diff --git a/src/test/test.ts b/src/test/test.ts index f8dae60164..f46839e72c 100644 --- a/src/test/test.ts +++ b/src/test/test.ts @@ -78,6 +78,7 @@ export class Suite extends Base implements reporterTypes.Suite { fn: Function, location: Location, }[] = []; + _timeout: number | undefined; _addSpec(spec: Spec) { spec.parent = this; diff --git a/src/test/testType.ts b/src/test/testType.ts index bbd1745e92..d325a0c0f3 100644 --- a/src/test/testType.ts +++ b/src/test/testType.ts @@ -125,9 +125,15 @@ export class TestTypeImpl { } private _setTimeout(timeout: number) { + const suite = currentlyLoadingFileSuite(); + if (suite) { + suite._timeout = timeout; + return; + } + const testInfo = currentTestInfo(); if (!testInfo) - throw new Error(`test.setTimeout() can only be called inside test or fixture`); + throw new Error(`test.setTimeout() can only be called from a test file`); testInfo.setTimeout(timeout); } diff --git a/src/test/workerRunner.ts b/src/test/workerRunner.ts index 6a824b5da0..a0e025fbaf 100644 --- a/src/test/workerRunner.ts +++ b/src/test/workerRunner.ts @@ -243,6 +243,15 @@ export class WorkerRunner extends EventEmitter { deadlineRunner.setDeadline(deadline()); }, }; + + // Inherit test.setTimeout() from parent suites. + for (let suite = spec.parent; suite; suite = suite.parent) { + if (suite._timeout !== undefined) { + testInfo.setTimeout(suite._timeout); + break; + } + } + this._setCurrentTest({ testInfo, testId }); const deadline = () => { return testInfo.timeout ? startTime + testInfo.timeout : undefined; diff --git a/tests/playwright-test/timeout.spec.ts b/tests/playwright-test/timeout.spec.ts index 94ce32eb94..04565e7ce0 100644 --- a/tests/playwright-test/timeout.spec.ts +++ b/tests/playwright-test/timeout.spec.ts @@ -68,6 +68,35 @@ test('should respect test.setTimeout', async ({ runInlineTest }) => { expect(result.output).toContain('Timeout of 1000ms exceeded'); }); +test('should respect test.setTimeout outside of the test', async ({ runInlineTest }) => { + const result = await runInlineTest({ + 'a.spec.ts': ` + const { test } = pwt; + + test.setTimeout(500); + test('fails', async ({}) => { + await new Promise(f => setTimeout(f, 1000)); + }); + test('passes', async ({}) => { + await new Promise(f => setTimeout(f, 100)); + }); + + test.describe('suite', () => { + test.setTimeout(50); + test('fails', async ({}) => { + await new Promise(f => setTimeout(f, 100)); + }); + test('passes', async ({}) => { + }); + }); + ` + }); + expect(result.exitCode).toBe(1); + expect(result.failed).toBe(2); + expect(result.passed).toBe(2); + expect(result.output).toContain('Timeout of 500ms exceeded'); +}); + test('should timeout when calling test.setTimeout too late', async ({ runInlineTest }) => { const result = await runInlineTest({ 'a.spec.ts': `