diff --git a/src/client/connection.ts b/src/client/connection.ts
index 9de2b92116..e6d980f11a 100644
--- a/src/client/connection.ts
+++ b/src/client/connection.ts
@@ -110,7 +110,7 @@ export class Connection extends EventEmitter {
if (!callback)
throw new Error(`Cannot find command to respond: ${id}`);
this._callbacks.delete(id);
- if (error)
+ if (error && !result)
callback.reject(parseError(error));
else
callback.resolve(this._replaceGuidsWithChannels(result));
diff --git a/src/dispatchers/dispatcher.ts b/src/dispatchers/dispatcher.ts
index 159021c4ec..45ba25afea 100644
--- a/src/dispatchers/dispatcher.ts
+++ b/src/dispatchers/dispatcher.ts
@@ -281,11 +281,12 @@ export class DispatcherConnection {
await sdkObject?.instrumentation.onAfterCall(sdkObject, callMetadata);
}
- const log = validMetadata.collectLogs ? callMetadata.log : undefined;
- if (callMetadata.error)
- this.onmessage({ id, error: error, log });
- else
- this.onmessage({ id, result: callMetadata.result, log });
+ const response: any = { id };
+ if (callMetadata.result)
+ response.result = callMetadata.result;
+ if (error)
+ response.error = error;
+ this.onmessage(response);
}
private _replaceDispatchersWithGuids(payload: any): any {
diff --git a/src/dispatchers/frameDispatcher.ts b/src/dispatchers/frameDispatcher.ts
index 29ff6be139..f643174bbc 100644
--- a/src/dispatchers/frameDispatcher.ts
+++ b/src/dispatchers/frameDispatcher.ts
@@ -232,6 +232,8 @@ export class FrameDispatcher extends Dispatcher Validator): Scheme {
scheme.Metadata = tObject({
stack: tOptional(tArray(tType('StackFrame'))),
apiName: tOptional(tString),
- collectLogs: tOptional(tBoolean),
});
scheme.Point = tObject({
x: tNumber,
diff --git a/src/test/expect.ts b/src/test/expect.ts
index f0fb688d4f..f8bab74da6 100644
--- a/src/test/expect.ts
+++ b/src/test/expect.ts
@@ -107,7 +107,6 @@ function wrap(matcherName: string, matcher: any) {
reportStepError(e);
}
};
- result.displayName = 'expect.' + matcherName;
return result;
}
diff --git a/src/test/index.ts b/src/test/index.ts
index 6294a7ca01..ad7c81b8b0 100644
--- a/src/test/index.ts
+++ b/src/test/index.ts
@@ -212,6 +212,8 @@ export const test = _baseTest.extend({
}
(context as any)._csi = {
onApiCallBegin: (apiCall: string) => {
+ if (apiCall.startsWith('expect.'))
+ return { userObject: null };
const step = (testInfo as any)._addStep({
category: 'pw:api',
title: apiCall,
diff --git a/src/utils/stackTrace.ts b/src/utils/stackTrace.ts
index 21815165fc..7aaa5db11d 100644
--- a/src/utils/stackTrace.ts
+++ b/src/utils/stackTrace.ts
@@ -62,15 +62,14 @@ export function captureStackTrace(): ParsedStackTrace {
return null;
if (frame.file.startsWith('internal'))
return null;
- if (frame.file.includes(path.join('node_modules', 'expect')))
- return null;
const fileName = path.resolve(process.cwd(), frame.file);
if (isTesting && fileName.includes(path.join('playwright', 'tests', 'config', 'coverage.js')))
return null;
const inClient =
// Allow fixtures in the reported stacks.
(!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(TEST_LIB)
|| fileName.startsWith(TEST_SRC));
@@ -94,7 +93,15 @@ export function captureStackTrace(): ParsedStackTrace {
for (let i = 0; i < parsedFrames.length - 1; i++) {
if (parsedFrames[i].inClient && !parsedFrames[i + 1].inClient) {
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);
break;
}
diff --git a/tests/config/browserTest.ts b/tests/config/browserTest.ts
index b66250f114..c3a5666105 100644
--- a/tests/config/browserTest.ts
+++ b/tests/config/browserTest.ts
@@ -143,6 +143,8 @@ export const playwrightFixtures: Fixtures {
+ if (apiCall.startsWith('expect.'))
+ return { userObject: null };
const testInfoImpl = testInfo as any;
const step = testInfoImpl._addStep({
category: 'pw:api',
diff --git a/tests/playwright-test/reporter.spec.ts b/tests/playwright-test/reporter.spec.ts
index f0f8f530bf..507dad9a15 100644
--- a/tests/playwright-test/reporter.spec.ts
+++ b/tests/playwright-test/reporter.spec.ts
@@ -229,9 +229,7 @@ test('should report expect steps', async ({ runInlineTest }) => {
`%% end {\"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\":\"object.expect.toHaveTitle(:root)\",\"category\":\"pw:api\"}`,
- `%% 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\"}]}`,
+ `%% end {\"title\":\"expect.not.toHaveTitle\",\"category\":\"expect\"}`,
`%% begin {\"title\":\"After Hooks\",\"category\":\"hook\"}`,
`%% begin {\"title\":\"browserContext.close\",\"category\":\"pw:api\"}`,
`%% end {\"title\":\"browserContext.close\",\"category\":\"pw:api\"}`,