chore: render expect in trace viewer (#9141)
This commit is contained in:
parent
1a2aa0e2e5
commit
241411ad42
|
|
@ -110,7 +110,7 @@ export class Connection extends EventEmitter {
|
||||||
if (!callback)
|
if (!callback)
|
||||||
throw new Error(`Cannot find command to respond: ${id}`);
|
throw new Error(`Cannot find command to respond: ${id}`);
|
||||||
this._callbacks.delete(id);
|
this._callbacks.delete(id);
|
||||||
if (error)
|
if (error && !result)
|
||||||
callback.reject(parseError(error));
|
callback.reject(parseError(error));
|
||||||
else
|
else
|
||||||
callback.resolve(this._replaceGuidsWithChannels(result));
|
callback.resolve(this._replaceGuidsWithChannels(result));
|
||||||
|
|
|
||||||
|
|
@ -281,11 +281,12 @@ export class DispatcherConnection {
|
||||||
await sdkObject?.instrumentation.onAfterCall(sdkObject, callMetadata);
|
await sdkObject?.instrumentation.onAfterCall(sdkObject, callMetadata);
|
||||||
}
|
}
|
||||||
|
|
||||||
const log = validMetadata.collectLogs ? callMetadata.log : undefined;
|
const response: any = { id };
|
||||||
if (callMetadata.error)
|
if (callMetadata.result)
|
||||||
this.onmessage({ id, error: error, log });
|
response.result = callMetadata.result;
|
||||||
else
|
if (error)
|
||||||
this.onmessage({ id, result: callMetadata.result, log });
|
response.error = error;
|
||||||
|
this.onmessage(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _replaceDispatchersWithGuids(payload: any): any {
|
private _replaceDispatchersWithGuids(payload: any): any {
|
||||||
|
|
|
||||||
|
|
@ -232,6 +232,8 @@ export class FrameDispatcher extends Dispatcher<Frame, channels.FrameInitializer
|
||||||
const result = await this._frame.expect(metadata, params.selector, { ...params, expectedValue });
|
const result = await this._frame.expect(metadata, params.selector, { ...params, expectedValue });
|
||||||
if (result.received !== undefined)
|
if (result.received !== undefined)
|
||||||
result.received = serializeResult(result.received);
|
result.received = serializeResult(result.received);
|
||||||
|
if (result.pass === !!params.isNot)
|
||||||
|
metadata.error = { error: { name: 'Expect', message: 'Expect failed' } };
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,6 @@ export type StackFrame = {
|
||||||
export type Metadata = {
|
export type Metadata = {
|
||||||
stack?: StackFrame[],
|
stack?: StackFrame[],
|
||||||
apiName?: string,
|
apiName?: string,
|
||||||
collectLogs?: boolean,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Point = {
|
export type Point = {
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,6 @@ Metadata:
|
||||||
type: array?
|
type: array?
|
||||||
items: StackFrame
|
items: StackFrame
|
||||||
apiName: string?
|
apiName: string?
|
||||||
collectLogs: boolean?
|
|
||||||
|
|
||||||
|
|
||||||
Point:
|
Point:
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,6 @@ export function createScheme(tChannel: (name: string) => Validator): Scheme {
|
||||||
scheme.Metadata = tObject({
|
scheme.Metadata = tObject({
|
||||||
stack: tOptional(tArray(tType('StackFrame'))),
|
stack: tOptional(tArray(tType('StackFrame'))),
|
||||||
apiName: tOptional(tString),
|
apiName: tOptional(tString),
|
||||||
collectLogs: tOptional(tBoolean),
|
|
||||||
});
|
});
|
||||||
scheme.Point = tObject({
|
scheme.Point = tObject({
|
||||||
x: tNumber,
|
x: tNumber,
|
||||||
|
|
|
||||||
|
|
@ -107,7 +107,6 @@ function wrap(matcherName: string, matcher: any) {
|
||||||
reportStepError(e);
|
reportStepError(e);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
result.displayName = 'expect.' + matcherName;
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -212,6 +212,8 @@ export const test = _baseTest.extend<TestFixtures, WorkerAndFileFixtures>({
|
||||||
}
|
}
|
||||||
(context as any)._csi = {
|
(context as any)._csi = {
|
||||||
onApiCallBegin: (apiCall: string) => {
|
onApiCallBegin: (apiCall: string) => {
|
||||||
|
if (apiCall.startsWith('expect.'))
|
||||||
|
return { userObject: null };
|
||||||
const step = (testInfo as any)._addStep({
|
const step = (testInfo as any)._addStep({
|
||||||
category: 'pw:api',
|
category: 'pw:api',
|
||||||
title: apiCall,
|
title: apiCall,
|
||||||
|
|
|
||||||
|
|
@ -62,15 +62,14 @@ export function captureStackTrace(): ParsedStackTrace {
|
||||||
return null;
|
return null;
|
||||||
if (frame.file.startsWith('internal'))
|
if (frame.file.startsWith('internal'))
|
||||||
return null;
|
return null;
|
||||||
if (frame.file.includes(path.join('node_modules', 'expect')))
|
|
||||||
return null;
|
|
||||||
const fileName = path.resolve(process.cwd(), frame.file);
|
const fileName = path.resolve(process.cwd(), frame.file);
|
||||||
if (isTesting && fileName.includes(path.join('playwright', 'tests', 'config', 'coverage.js')))
|
if (isTesting && fileName.includes(path.join('playwright', 'tests', 'config', 'coverage.js')))
|
||||||
return null;
|
return null;
|
||||||
const inClient =
|
const inClient =
|
||||||
// Allow fixtures in the reported stacks.
|
// Allow fixtures in the reported stacks.
|
||||||
(!fileName.includes('test/index') && !fileName.includes('test\\index')) && (
|
(!fileName.includes('test/index') && !fileName.includes('test\\index')) && (
|
||||||
fileName.startsWith(CLIENT_LIB)
|
frame.file.includes(path.join('node_modules', 'expect'))
|
||||||
|
|| fileName.startsWith(CLIENT_LIB)
|
||||||
|| fileName.startsWith(CLIENT_SRC)
|
|| fileName.startsWith(CLIENT_SRC)
|
||||||
|| fileName.startsWith(TEST_LIB)
|
|| fileName.startsWith(TEST_LIB)
|
||||||
|| fileName.startsWith(TEST_SRC));
|
|| fileName.startsWith(TEST_SRC));
|
||||||
|
|
@ -94,7 +93,15 @@ export function captureStackTrace(): ParsedStackTrace {
|
||||||
for (let i = 0; i < parsedFrames.length - 1; i++) {
|
for (let i = 0; i < parsedFrames.length - 1; i++) {
|
||||||
if (parsedFrames[i].inClient && !parsedFrames[i + 1].inClient) {
|
if (parsedFrames[i].inClient && !parsedFrames[i + 1].inClient) {
|
||||||
const frame = parsedFrames[i].frame;
|
const frame = parsedFrames[i].frame;
|
||||||
apiName = frame.function ? frame.function[0].toLowerCase() + frame.function.slice(1) : '';
|
const text = parsedFrames[i].frameText;
|
||||||
|
// expect matchers have the following stack structure:
|
||||||
|
// at __EXTERNAL_MATCHER_TRAP__ (.../index.js:342:30)
|
||||||
|
// at Object.throwingMatcher [as toBeChecked] (.../index.js:343:15)
|
||||||
|
const aliasIndex = text.indexOf('[as ');
|
||||||
|
if (aliasIndex !== -1)
|
||||||
|
apiName = 'expect.' + text.substring(aliasIndex + 4, text.indexOf(']'));
|
||||||
|
else
|
||||||
|
apiName = frame.function ? frame.function[0].toLowerCase() + frame.function.slice(1) : '';
|
||||||
parsedFrames = parsedFrames.slice(i + 1);
|
parsedFrames = parsedFrames.slice(i + 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -143,6 +143,8 @@ export const playwrightFixtures: Fixtures<PlaywrightTestOptions & PlaywrightTest
|
||||||
await context.tracing.start({ screenshots: true, snapshots: true });
|
await context.tracing.start({ screenshots: true, snapshots: true });
|
||||||
(context as any)._csi = {
|
(context as any)._csi = {
|
||||||
onApiCallBegin: (apiCall: string) => {
|
onApiCallBegin: (apiCall: string) => {
|
||||||
|
if (apiCall.startsWith('expect.'))
|
||||||
|
return { userObject: null };
|
||||||
const testInfoImpl = testInfo as any;
|
const testInfoImpl = testInfo as any;
|
||||||
const step = testInfoImpl._addStep({
|
const step = testInfoImpl._addStep({
|
||||||
category: 'pw:api',
|
category: 'pw:api',
|
||||||
|
|
|
||||||
|
|
@ -229,9 +229,7 @@ test('should report expect steps', async ({ runInlineTest }) => {
|
||||||
`%% end {\"title\":\"browserContext.newPage\",\"category\":\"pw:api\"}`,
|
`%% end {\"title\":\"browserContext.newPage\",\"category\":\"pw:api\"}`,
|
||||||
`%% end {\"title\":\"Before Hooks\",\"category\":\"hook\",\"steps\":[{\"title\":\"browserContext.newPage\",\"category\":\"pw:api\"}]}`,
|
`%% end {\"title\":\"Before Hooks\",\"category\":\"hook\",\"steps\":[{\"title\":\"browserContext.newPage\",\"category\":\"pw:api\"}]}`,
|
||||||
`%% begin {\"title\":\"expect.not.toHaveTitle\",\"category\":\"expect\"}`,
|
`%% begin {\"title\":\"expect.not.toHaveTitle\",\"category\":\"expect\"}`,
|
||||||
`%% begin {\"title\":\"object.expect.toHaveTitle(:root)\",\"category\":\"pw:api\"}`,
|
`%% end {\"title\":\"expect.not.toHaveTitle\",\"category\":\"expect\"}`,
|
||||||
`%% end {\"title\":\"object.expect.toHaveTitle(:root)\",\"category\":\"pw:api\"}`,
|
|
||||||
`%% end {\"title\":\"expect.not.toHaveTitle\",\"category\":\"expect\",\"steps\":[{\"title\":\"object.expect.toHaveTitle(:root)\",\"category\":\"pw:api\"}]}`,
|
|
||||||
`%% begin {\"title\":\"After Hooks\",\"category\":\"hook\"}`,
|
`%% begin {\"title\":\"After Hooks\",\"category\":\"hook\"}`,
|
||||||
`%% begin {\"title\":\"browserContext.close\",\"category\":\"pw:api\"}`,
|
`%% begin {\"title\":\"browserContext.close\",\"category\":\"pw:api\"}`,
|
||||||
`%% end {\"title\":\"browserContext.close\",\"category\":\"pw:api\"}`,
|
`%% end {\"title\":\"browserContext.close\",\"category\":\"pw:api\"}`,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue