diff --git a/packages/playwright-core/src/protocol/debug.ts b/packages/playwright-core/src/protocol/debug.ts index f29ae6be8241a..c58c3e4aafd7c 100644 --- a/packages/playwright-core/src/protocol/debug.ts +++ b/packages/playwright-core/src/protocol/debug.ts @@ -89,13 +89,16 @@ export const commandsWithTracingSnapshots = new Set([ 'Page.mouseClick', 'Page.mouseWheel', 'Page.touchscreenTap', + 'Page.accessibilitySnapshot', 'Frame.evalOnSelector', 'Frame.evalOnSelectorAll', 'Frame.addScriptTag', 'Frame.addStyleTag', + 'Frame.ariaSnapshot', 'Frame.blur', 'Frame.check', 'Frame.click', + 'Frame.content', 'Frame.dragAndDrop', 'Frame.dblclick', 'Frame.dispatchEvent', @@ -116,6 +119,9 @@ export const commandsWithTracingSnapshots = new Set([ 'Frame.isVisible', 'Frame.isEditable', 'Frame.press', + 'Frame.querySelector', + 'Frame.querySelectorAll', + 'Frame.queryCount', 'Frame.selectOption', 'Frame.setContent', 'Frame.setInputFiles', @@ -133,8 +139,10 @@ export const commandsWithTracingSnapshots = new Set([ 'ElementHandle.evaluateExpressionHandle', 'ElementHandle.evalOnSelector', 'ElementHandle.evalOnSelectorAll', + 'ElementHandle.boundingBox', 'ElementHandle.check', 'ElementHandle.click', + 'ElementHandle.contentFrame', 'ElementHandle.dblclick', 'ElementHandle.dispatchEvent', 'ElementHandle.fill', @@ -150,6 +158,8 @@ export const commandsWithTracingSnapshots = new Set([ 'ElementHandle.isHidden', 'ElementHandle.isVisible', 'ElementHandle.press', + 'ElementHandle.querySelector', + 'ElementHandle.querySelectorAll', 'ElementHandle.screenshot', 'ElementHandle.scrollIntoViewIfNeeded', 'ElementHandle.selectOption', diff --git a/packages/playwright-core/src/server/debugger.ts b/packages/playwright-core/src/server/debugger.ts index 420b438ccb33e..53a96ba8f250e 100644 --- a/packages/playwright-core/src/server/debugger.ts +++ b/packages/playwright-core/src/server/debugger.ts @@ -134,7 +134,7 @@ function shouldPauseBeforeStep(metadata: CallMetadata): boolean { // Always stop on 'close' if (metadata.method === 'close') return true; - if (metadata.method === 'waitForSelector' || metadata.method === 'waitForEventInfo') + if (metadata.method === 'waitForSelector' || metadata.method === 'waitForEventInfo' || metadata.method === 'querySelector' || metadata.method === 'querySelectorAll') return false; // Never stop on those, primarily for the test harness. const step = metadata.type + '.' + metadata.method; // Stop before everything that generates snapshot. But don't stop before those marked as pausesBeforeInputActions diff --git a/packages/protocol/src/protocol.yml b/packages/protocol/src/protocol.yml index 9997989f77cef..e8b9746b41cfe 100644 --- a/packages/protocol/src/protocol.yml +++ b/packages/protocol/src/protocol.yml @@ -1675,6 +1675,8 @@ Page: root: ElementHandle? returns: rootAXNode: AXNode? + flags: + snapshot: true pdf: parameters: @@ -1885,6 +1887,8 @@ Frame: timeout: number? returns: snapshot: string + flags: + snapshot: true blur: parameters: @@ -1943,6 +1947,8 @@ Frame: content: returns: value: string + flags: + snapshot: true dragAndDrop: parameters: @@ -2202,6 +2208,8 @@ Frame: strict: boolean? returns: element: ElementHandle? + flags: + snapshot: true querySelectorAll: parameters: @@ -2210,12 +2218,16 @@ Frame: elements: type: array items: ElementHandle + flags: + snapshot: true queryCount: parameters: selector: string returns: value: number + flags: + snapshot: true selectOption: parameters: @@ -2540,6 +2552,8 @@ ElementHandle: boundingBox: returns: value: Rect? + flags: + snapshot: true check: parameters: @@ -2585,6 +2599,8 @@ ElementHandle: contentFrame: returns: frame: Frame? + flags: + snapshot: true dblclick: parameters: @@ -2739,6 +2755,8 @@ ElementHandle: strict: boolean? returns: element: ElementHandle? + flags: + snapshot: true querySelectorAll: parameters: @@ -2747,6 +2765,8 @@ ElementHandle: elements: type: array items: ElementHandle + flags: + snapshot: true screenshot: parameters: diff --git a/tests/library/inspector/pause.spec.ts b/tests/library/inspector/pause.spec.ts index 745ae27d1d936..c06222493e2ad 100644 --- a/tests/library/inspector/pause.spec.ts +++ b/tests/library/inspector/pause.spec.ts @@ -188,12 +188,20 @@ it.describe('pause', () => { const iframe = page.frames()[1]; const button = await iframe.waitForSelector('button'); - const box1 = await button.boundingBox(); + const box1Promise = button.boundingBox(); + const actionPoint = await page.waitForSelector('x-pw-action-point'); - const box2 = await actionPoint.boundingBox(); + const box2Promise = actionPoint.boundingBox(); + await recorderPage.click('[title="Step over (F10)"]'); + + const box1 = await box1Promise; + const box2 = await box2Promise; const iframeActionPoint = await iframe.$('x-pw-action-point'); - expect(await iframeActionPoint?.boundingBox()).toBeFalsy(); + const iframeActionPointPromise = iframeActionPoint?.boundingBox(); + await recorderPage.click('[title="Resume (F8)"]'); + + expect(await iframeActionPointPromise).toBeFalsy(); const x1 = box1!.x + box1!.width / 2; const y1 = box1!.y + box1!.height / 2; @@ -203,7 +211,6 @@ it.describe('pause', () => { expect(Math.abs(x1 - x2) < 2).toBeTruthy(); expect(Math.abs(y1 - y2) < 2).toBeTruthy(); - await recorderPage.click('[title="Resume (F8)"]'); await scriptPromise; }); diff --git a/tests/playwright-test/playwright.trace.spec.ts b/tests/playwright-test/playwright.trace.spec.ts index 9f06e8f3b41e7..045ad6d419531 100644 --- a/tests/playwright-test/playwright.trace.spec.ts +++ b/tests/playwright-test/playwright.trace.spec.ts @@ -1271,3 +1271,49 @@ test('should record trace after fixture teardown timeout', { // Check console events to make sure that library trace is recorded. expect(trace.events).toContainEqual(expect.objectContaining({ type: 'console', text: 'from the page' })); }); + +test('should record trace snapshot for more obscure commands', async ({ runInlineTest }) => { + const result = await runInlineTest({ + 'a.spec.ts': ` + import { test, expect } from '@playwright/test'; + test('test 1', async ({ browser }) => { + const page = await browser.newPage(); + await page.setContent('
Content
'); + expect(await page.locator('div').count()).toBe(1); + await page.locator('div').boundingBox(); + }); + `, + }, { trace: 'on' }); + + expect(result.exitCode).toBe(0); + expect(result.passed).toBe(1); + + const tracePath = test.info().outputPath('test-results', 'a-test-1', 'trace.zip'); + const trace = await parseTrace(tracePath); + expect(trace.actionTree).toEqual([ + 'Before Hooks', + ' fixture: browser', + ' browserType.launch', + 'browser.newPage', + 'page.setContent', + 'locator.count', + 'expect.toBe', + 'locator.boundingBox', + 'After Hooks', + ]); + + const snapshots = trace.traceModel.storage(); + const snapshotFrameOrPageId = snapshots.snapshotsForTest()[0]; + + const countAction = trace.actions.find(a => a.apiName === 'locator.count'); + expect(countAction.beforeSnapshot).toBeTruthy(); + expect(countAction.afterSnapshot).toBeTruthy(); + expect(snapshots.snapshotByName(snapshotFrameOrPageId, countAction.beforeSnapshot)).toBeTruthy(); + expect(snapshots.snapshotByName(snapshotFrameOrPageId, countAction.afterSnapshot)).toBeTruthy(); + + const boundingBoxAction = trace.actions.find(a => a.apiName === 'locator.boundingBox'); + expect(boundingBoxAction.beforeSnapshot).toBeTruthy(); + expect(boundingBoxAction.afterSnapshot).toBeTruthy(); + expect(snapshots.snapshotByName(snapshotFrameOrPageId, boundingBoxAction.beforeSnapshot)).toBeTruthy(); + expect(snapshots.snapshotByName(snapshotFrameOrPageId, boundingBoxAction.afterSnapshot)).toBeTruthy(); +});