diff --git a/packages/isomorphic/timeoutRunner.ts b/packages/isomorphic/timeoutRunner.ts index d551ee203323b..b001c6bc0399f 100644 --- a/packages/isomorphic/timeoutRunner.ts +++ b/packages/isomorphic/timeoutRunner.ts @@ -24,7 +24,8 @@ import { monotonicTime } from './time'; export async function raceAgainstDeadline(cb: () => Promise, deadline: number): Promise<{ result: T, timedOut: false } | { timedOut: true }> { let timer: NodeJS.Timeout | undefined; - return Promise.race([ + // Note: not including "await" here truncates the async stack inside cb(), so always include it. + return await Promise.race([ cb().then(result => { return { result, timedOut: false }; }), diff --git a/tests/playwright-test/test-step.spec.ts b/tests/playwright-test/test-step.spec.ts index b23541dec3a37..0a994c6d8576f 100644 --- a/tests/playwright-test/test-step.spec.ts +++ b/tests/playwright-test/test-step.spec.ts @@ -388,6 +388,41 @@ test('should not pass return value from step', async ({ runInlineTest }) => { expect(result.output).toContain('v2 = 20'); }); +test('should contain steps chain in the stack', async ({ runInlineTest }) => { + const result = await runInlineTest({ + 'a.test.ts': ` + import { test, expect } from '@playwright/test'; + + async function innerFunction(page) { + await test.step('inner step', async () => { + await expect(page.locator('div')).toBeVisible({ timeout: 1 }); + }); + } + + async function outerFunction(page) { + await test.step('outer step', async () => { + await innerFunction(page); + }); + } + + // It is important to have "page" here to trigger some internal instrumentation. + test('test with chained steps', async ({ page }) => { + await test.step('top-level step', async () => { + await outerFunction(page); + }); + }); + ` + }, { reporter: '', workers: 1 }); + expect(result.exitCode).toBe(1); + expect(result.failed).toBe(1); + expect(result.output).toContain('at innerFunction'); + expect(result.output).toContain('at outerFunction'); + expect(result.output).toContain('a.test.ts:5'); + expect(result.output).toContain('a.test.ts:6'); + expect(result.output).toContain('a.test.ts:11'); + expect(result.output).toContain('a.test.ts:18'); +}); + test('step timeout option', async ({ runInlineTest }) => { const result = await runInlineTest({ 'a.test.ts': `