chore: throw on nested toPass calls

This commit is contained in:
Max Schmitt 2024-09-20 11:49:44 +02:00
parent ace8cb2427
commit 9117562377
2 changed files with 22 additions and 1 deletions

View file

@ -26,6 +26,7 @@ import { currentTestInfo } from '../common/globals';
import { TestInfoImpl } from '../worker/testInfo'; import { TestInfoImpl } from '../worker/testInfo';
import type { ExpectMatcherState } from '../../types/test'; import type { ExpectMatcherState } from '../../types/test';
import { takeFirst } from '../common/config'; import { takeFirst } from '../common/config';
import { AsyncLocalStorage } from 'async_hooks';
interface LocatorEx extends Locator { interface LocatorEx extends Locator {
_expect(expression: string, options: Omit<FrameExpectOptions, 'expectedValue'> & { expectedValue?: any }): Promise<{ matches: boolean, received?: any, log?: string[], timedOut?: boolean }>; _expect(expression: string, options: Omit<FrameExpectOptions, 'expectedValue'> & { expectedValue?: any }): Promise<{ matches: boolean, received?: any, log?: string[], timedOut?: boolean }>;
@ -397,6 +398,7 @@ export async function toBeOK(
return { message, pass }; return { message, pass };
} }
const toPassContextStorage = new AsyncLocalStorage();
export async function toPass( export async function toPass(
this: ExpectMatcherState, this: ExpectMatcherState,
callback: () => any, callback: () => any,
@ -405,6 +407,8 @@ export async function toPass(
timeout?: number, timeout?: number,
} = {}, } = {},
) { ) {
if (toPassContextStorage.getStore() !== undefined)
throw new Error(`Error: Nested toPass calls detected. toPass should not be used inside another toPass.`);
const testInfo = currentTestInfo(); const testInfo = currentTestInfo();
const timeout = takeFirst(options.timeout, testInfo?._projectInternal.expect?.toPass?.timeout, 0); const timeout = takeFirst(options.timeout, testInfo?._projectInternal.expect?.toPass?.timeout, 0);
const intervals = takeFirst(options.intervals, testInfo?._projectInternal.expect?.toPass?.intervals, [100, 250, 500, 1000]); const intervals = takeFirst(options.intervals, testInfo?._projectInternal.expect?.toPass?.intervals, [100, 250, 500, 1000]);
@ -414,7 +418,7 @@ export async function toPass(
if (testInfo && currentTestInfo() !== testInfo) if (testInfo && currentTestInfo() !== testInfo)
return { continuePolling: false, result: undefined }; return { continuePolling: false, result: undefined };
try { try {
await callback(); await toPassContextStorage.run('inside', () => callback());
return { continuePolling: !!this.isNot, result: undefined }; return { continuePolling: !!this.isNot, result: undefined };
} catch (e) { } catch (e) {
return { continuePolling: !this.isNot, result: e }; return { continuePolling: !this.isNot, result: e };

View file

@ -298,3 +298,20 @@ test('should give priority to intervals parameter over intervals in config file'
expect(result.output).toContain('Expected: -1'); expect(result.output).toContain('Expected: -1');
expect(result.output).toContain('Received: 3'); expect(result.output).toContain('Received: 3');
}); });
test('should throw if you have nested toPass', async ({ runInlineTest }) => {
const result = await runInlineTest({
'a.spec.ts': `
import { test, expect } from '@playwright/test';
test('nested toPass', async () => {
await test.expect(async () => {
await test.expect(() => {
expect(1).toBe(2);
}).toPass({ timeout: 50 });
}).toPass({ timeout: 100 });
});
`
});
expect(result.exitCode).toBe(1);
expect(result.output).toContain('Error: Nested toPass calls detected. toPass should not be used inside another toPass.');
});