fix(expect): respect custom message in expect.poll

This commit is contained in:
Dmitry Gozman 2024-09-13 10:33:54 +01:00
parent cd4dabef8b
commit 561435841e
3 changed files with 40 additions and 9 deletions

View file

@ -290,7 +290,7 @@ class ExpectMetaInfoProxyHandler implements ProxyHandler<any> {
if (this._info.isPoll) { if (this._info.isPoll) {
if ((customAsyncMatchers as any)[matcherName] || matcherName === 'resolves' || matcherName === 'rejects') if ((customAsyncMatchers as any)[matcherName] || matcherName === 'resolves' || matcherName === 'rejects')
throw new Error(`\`expect.poll()\` does not support "${matcherName}" matcher.`); throw new Error(`\`expect.poll()\` does not support "${matcherName}" matcher.`);
matcher = (...args: any[]) => pollMatcher(resolvedMatcherName, !!this._info.isNot, this._info.pollIntervals, this._info.pollTimeout ?? currentExpectTimeout(), this._info.generator!, ...args); matcher = (...args: any[]) => pollMatcher(resolvedMatcherName, this._info, this._prefix, ...args);
} }
return (...args: any[]) => { return (...args: any[]) => {
const testInfo = currentTestInfo(); const testInfo = currentTestInfo();
@ -350,25 +350,34 @@ class ExpectMetaInfoProxyHandler implements ProxyHandler<any> {
} }
} }
async function pollMatcher(qualifiedMatcherName: any, isNot: boolean, pollIntervals: number[] | undefined, timeout: number, generator: () => any, ...args: any[]) { async function pollMatcher(qualifiedMatcherName: string, info: ExpectMetaInfo, prefix: string[], ...args: any[]) {
const testInfo = currentTestInfo(); const testInfo = currentTestInfo();
const timeout = info.pollTimeout ?? currentExpectTimeout();
const { deadline, timeoutMessage } = testInfo ? testInfo._deadlineForMatcher(timeout) : TestInfoImpl._defaultDeadlineForMatcher(timeout); const { deadline, timeoutMessage } = testInfo ? testInfo._deadlineForMatcher(timeout) : TestInfoImpl._defaultDeadlineForMatcher(timeout);
const result = await pollAgainstDeadline<Error|undefined>(async () => { const result = await pollAgainstDeadline<Error|undefined>(async () => {
if (testInfo && currentTestInfo() !== testInfo) if (testInfo && currentTestInfo() !== testInfo)
return { continuePolling: false, result: undefined }; return { continuePolling: false, result: undefined };
const value = await generator(); const innerInfo: ExpectMetaInfo = {
let expectInstance = expectLibrary(value) as any; ...info,
if (isNot) isSoft: false, // soft is outside of poll, not inside
expectInstance = expectInstance.not; isPoll: false,
pollTimeout: undefined,
pollIntervals: undefined,
generator: undefined,
};
const value = await info.generator!();
try { try {
expectInstance[qualifiedMatcherName].call(expectInstance, ...args); let matchers = createMatchers(value, innerInfo, prefix);
if (info.isNot)
matchers = matchers.not;
matchers[qualifiedMatcherName](...args);
return { continuePolling: false, result: undefined }; return { continuePolling: false, result: undefined };
} catch (error) { } catch (error) {
return { continuePolling: true, result: error }; return { continuePolling: true, result: error };
} }
}, deadline, pollIntervals ?? [100, 250, 500, 1000]); }, deadline, info.pollIntervals ?? [100, 250, 500, 1000]);
if (result.timedOut) { if (result.timedOut) {
const message = result.result ? [ const message = result.result ? [

View file

@ -262,4 +262,20 @@ test('should propagate string exception from async arrow function', { annotation
}); });
expect(result.output).toContain('some error'); expect(result.output).toContain('some error');
}); });
test('should show custom message', {
annotation: { type: 'issue', description: 'https://github.com/microsoft/playwright/issues/32582' }
}, async ({ runInlineTest }) => {
const result = await runInlineTest({
'a.spec.ts': `
import { test, expect } from '@playwright/test';
test('should fail', async () => {
await expect.poll(() => 1, { message: 'custom message', timeout: 500 }).toBe(2);
});
`,
});
expect(result.output).toContain('Error: custom message');
expect(result.output).toContain('Expected: 2');
expect(result.output).toContain('Received: 1');
});

View file

@ -987,9 +987,12 @@ expect |expect.poll.toHaveLength @ a.test.ts:14
pw:api | page.goto(about:blank) @ a.test.ts:7 pw:api | page.goto(about:blank) @ a.test.ts:7
test.step | inner step attempt: 0 @ a.test.ts:8 test.step | inner step attempt: 0 @ a.test.ts:8
expect | expect.toBe @ a.test.ts:10 expect | expect.toBe @ a.test.ts:10
expect | expect.toHaveLength @ a.test.ts:6
expect | error: Error: expect(received).toHaveLength(expected)
pw:api | page.goto(about:blank) @ a.test.ts:7 pw:api | page.goto(about:blank) @ a.test.ts:7
test.step | inner step attempt: 1 @ a.test.ts:8 test.step | inner step attempt: 1 @ a.test.ts:8
expect | expect.toBe @ a.test.ts:10 expect | expect.toBe @ a.test.ts:10
expect | expect.toHaveLength @ a.test.ts:6
hook |After Hooks hook |After Hooks
fixture | fixture: page fixture | fixture: page
fixture | fixture: context fixture | fixture: context
@ -1036,9 +1039,12 @@ expect |expect.poll.toBe @ a.test.ts:13
expect | expect.toHaveText @ a.test.ts:7 expect | expect.toHaveText @ a.test.ts:7
test.step | iteration 1 @ a.test.ts:9 test.step | iteration 1 @ a.test.ts:9
expect | expect.toBeVisible @ a.test.ts:10 expect | expect.toBeVisible @ a.test.ts:10
expect | expect.toBe @ a.test.ts:6
expect | error: Error: expect(received).toBe(expected) // Object.is equality
expect | expect.toHaveText @ a.test.ts:7 expect | expect.toHaveText @ a.test.ts:7
test.step | iteration 2 @ a.test.ts:9 test.step | iteration 2 @ a.test.ts:9
expect | expect.toBeVisible @ a.test.ts:10 expect | expect.toBeVisible @ a.test.ts:10
expect | expect.toBe @ a.test.ts:6
hook |After Hooks hook |After Hooks
fixture | fixture: page fixture | fixture: page
fixture | fixture: context fixture | fixture: context