diff --git a/packages/playwright-core/src/utils/traceUtils.ts b/packages/playwright-core/src/utils/traceUtils.ts index b9a85b53db..006e1bcd92 100644 --- a/packages/playwright-core/src/utils/traceUtils.ts +++ b/packages/playwright-core/src/utils/traceUtils.ts @@ -122,11 +122,11 @@ export async function saveTraceFile(fileName: string, traceEvents: TraceEvent[], }); } -export function createBeforeActionTraceEventForExpect(callId: string, apiName: string, expected: any, stack: StackFrame[]): BeforeActionTraceEvent { +export function createBeforeActionTraceEventForExpect(callId: string, apiName: string, wallTime: number, expected: any, stack: StackFrame[]): BeforeActionTraceEvent { return { type: 'before', callId, - wallTime: Date.now(), + wallTime, startTime: monotonicTime(), class: 'Test', method: 'step', diff --git a/packages/playwright-test/src/matchers/expect.ts b/packages/playwright-test/src/matchers/expect.ts index 3719a1bab8..a9a4dd9664 100644 --- a/packages/playwright-test/src/matchers/expect.ts +++ b/packages/playwright-test/src/matchers/expect.ts @@ -224,7 +224,7 @@ class ExpectMetaInfoProxyHandler implements ProxyHandler { const generateTraceEvent = matcherName !== 'poll' && matcherName !== 'toPass'; const callId = ++lastCallId; if (generateTraceEvent) - testInfo._traceEvents.push(createBeforeActionTraceEventForExpect(`expect@${callId}`, defaultTitle, args[0], stackFrames)); + testInfo._traceEvents.push(createBeforeActionTraceEventForExpect(`expect@${callId}`, defaultTitle, wallTime, args[0], stackFrames)); const reportStepError = (jestError: Error) => { const message = jestError.message; diff --git a/tests/playwright-test/ui-mode-trace.spec.ts b/tests/playwright-test/ui-mode-trace.spec.ts index ed36d41378..e4f5a1766b 100644 --- a/tests/playwright-test/ui-mode-trace.spec.ts +++ b/tests/playwright-test/ui-mode-trace.spec.ts @@ -45,6 +45,54 @@ test('should merge trace events', async ({ runUITest, server }) => { ], { timeout: 15000 }); }); +test('should merge web assertion events', async ({ runUITest }, testInfo) => { + const { page } = await runUITest({ + 'a.test.ts': ` + import { test, expect } from '@playwright/test'; + test('trace test', async ({ page }) => { + await page.setContent(''); + await expect(page.locator('button')).toBeVisible(); + }); + `, + }); + + await page.getByText('trace test').dblclick(); + + const listItem = page.getByTestId('action-list').getByRole('listitem'); + await expect( + listItem, + 'action list' + ).toHaveText([ + /browserContext\.newPage[\d.]+m?s/, + /page\.setContent[\d.]+m?s/, + /expect\.toBeVisiblelocator\('button'\)[\d.]+m?s/, + ], { timeout: 15000 }); +}); + +test('should merge screenshot assertions', async ({ runUITest }, testInfo) => { + const { page } = await runUITest({ + 'a.test.ts': ` + import { test, expect } from '@playwright/test'; + test('trace test', async ({ page }) => { + await page.setContent(''); + await expect(page.locator('button')).toHaveScreenshot(); + }); + `, + }); + + await page.getByText('trace test').dblclick(); + + const listItem = page.getByTestId('action-list').getByRole('listitem'); + await expect( + listItem, + 'action list' + ).toHaveText([ + /browserContext\.newPage[\d.]+m?s/, + /page\.setContent[\d.]+m?s/, + /expect\.toHaveScreenshot[\d.]+m?s/, + ], { timeout: 15000 }); +}); + test('should locate sync assertions in source', async ({ runUITest, server }) => { const { page } = await runUITest({ 'a.test.ts': `