From 43a6bf4d45990de14ec9e6b11241cd6ca71b97e0 Mon Sep 17 00:00:00 2001 From: Dmitry Gozman Date: Tue, 29 Nov 2022 11:43:47 -0800 Subject: [PATCH] fix(inspector): support custom test id attribute (#18996) Fixes #18959. --- .../src/server/debugController.ts | 10 ++++--- .../server/dispatchers/browserDispatcher.ts | 4 +-- .../playwright-core/src/server/recorder.ts | 16 ++-------- tests/library/debug-controller.spec.ts | 17 +++++++---- tests/library/inspector/pause.spec.ts | 29 +++++++++++++++++++ 5 files changed, 50 insertions(+), 26 deletions(-) diff --git a/packages/playwright-core/src/server/debugController.ts b/packages/playwright-core/src/server/debugController.ts index af80750724..1d29c1a4e6 100644 --- a/packages/playwright-core/src/server/debugController.ts +++ b/packages/playwright-core/src/server/debugController.ts @@ -114,14 +114,16 @@ export class DebugController extends SdkObject { const { context } = await browser.newContextForReuse({}, internalMetadata); await context.newPage(internalMetadata); } + // Update test id attribute. + if (params.testIdAttributeName) { + for (const page of this._playwright.allPages()) + page.context().selectors().setTestIdAttributeName(params.testIdAttributeName); + } // Toggle the mode. for (const recorder of await this._allRecorders()) { recorder.hideHighlightedSelecor(); - if (params.mode === 'recording') { + if (params.mode === 'recording') recorder.setOutput(this._codegenId, params.file); - if (params.testIdAttributeName) - recorder.setTestIdAttributeName(params.testIdAttributeName); - } recorder.setMode(params.mode); } this.setAutoCloseEnabled(true); diff --git a/packages/playwright-core/src/server/dispatchers/browserDispatcher.ts b/packages/playwright-core/src/server/dispatchers/browserDispatcher.ts index a6bdbf9f9c..43fdab9e48 100644 --- a/packages/playwright-core/src/server/dispatchers/browserDispatcher.ts +++ b/packages/playwright-core/src/server/dispatchers/browserDispatcher.ts @@ -48,7 +48,7 @@ export class BrowserDispatcher extends Dispatcher { - return newContextForReuse(this._object, this, params, null, metadata); + return await newContextForReuse(this._object, this, params, null, metadata); } async close(): Promise { @@ -105,7 +105,7 @@ export class ConnectedBrowserDispatcher extends Dispatcher { - return newContextForReuse(this._object, this as any as BrowserDispatcher, params, this.selectors, metadata); + return await newContextForReuse(this._object, this as any as BrowserDispatcher, params, this.selectors, metadata); } async close(): Promise { diff --git a/packages/playwright-core/src/server/recorder.ts b/packages/playwright-core/src/server/recorder.ts index 449161a27e..136df7a946 100644 --- a/packages/playwright-core/src/server/recorder.ts +++ b/packages/playwright-core/src/server/recorder.ts @@ -172,7 +172,7 @@ export class Recorder implements InstrumentationListener { actionPoint, actionSelector, language: this._currentLanguage, - testIdAttributeName: this._contextRecorder.testIdAttributeName(), + testIdAttributeName: this._context.selectors().testIdAttributeName(), }; return uiState; }); @@ -224,7 +224,7 @@ export class Recorder implements InstrumentationListener { } setHighlightedSelector(language: Language, selector: string) { - this._highlightedSelector = locatorOrSelectorAsSelector(language, selector, this._contextRecorder.testIdAttributeName()); + this._highlightedSelector = locatorOrSelectorAsSelector(language, selector, this._context.selectors().testIdAttributeName()); this._refreshOverlay(); } @@ -233,10 +233,6 @@ export class Recorder implements InstrumentationListener { this._refreshOverlay(); } - setTestIdAttributeName(testIdAttributeName: string) { - this._contextRecorder.setTestIdAttributeName(testIdAttributeName); - } - setOutput(codegenId: string, outputFile: string | undefined) { this._contextRecorder.setOutput(codegenId, outputFile); } @@ -397,14 +393,6 @@ class ContextRecorder extends EventEmitter { this._generator = generator; } - testIdAttributeName() { - return this._testIdAttributeName; - } - - setTestIdAttributeName(testIdAttributeName: string) { - this._testIdAttributeName = testIdAttributeName; - } - setOutput(codegenId: string, outputFile?: string) { const languages = new Set([ new JavaLanguageGenerator(), diff --git a/tests/library/debug-controller.spec.ts b/tests/library/debug-controller.spec.ts index c905d3d918..8ef3622b36 100644 --- a/tests/library/debug-controller.spec.ts +++ b/tests/library/debug-controller.spec.ts @@ -185,30 +185,35 @@ test('test', async ({ page }) => { }); test('should record custom data-testid', async ({ backend, connectedBrowser }) => { + // This test emulates "record at cursor" functionality + // with custom test id attribute in the config. + const events = []; backend.on('sourceChanged', event => events.push(event)); + // 1. "Show browser" (or "run test"). + const context = await connectedBrowser._newContextForReuse(); + const page = await context.newPage(); + await page.setContent(`
One
`); + + // 2. "Record at cursor". await backend.setMode({ mode: 'recording', testIdAttributeName: 'data-custom-id' }); - const context = await connectedBrowser._newContextForReuse(); - const [page] = context.pages(); - - await page.setContent(`
One
`); + // 3. Record a click action. await page.locator('div').click(); + // 4. Expect "getByTestId" locator. await expect.poll(() => events[events.length - 1]).toEqual({ header: `import { test, expect } from '@playwright/test'; test('test', async ({ page }) => {`, footer: `});`, actions: [ - ` await page.goto('about:blank');`, ` await page.getByTestId('one').click();`, ], text: `import { test, expect } from '@playwright/test'; test('test', async ({ page }) => { - await page.goto('about:blank'); await page.getByTestId('one').click(); });` }); diff --git a/tests/library/inspector/pause.spec.ts b/tests/library/inspector/pause.spec.ts index 1580d326e6..b287c1acdf 100644 --- a/tests/library/inspector/pause.spec.ts +++ b/tests/library/inspector/pause.spec.ts @@ -413,6 +413,35 @@ it.describe('pause', () => { 'keyup', ]); }); + + it('should highlight locators with custom testId', async ({ page, playwright, recorderPageGetter }) => { + await page.setContent('
click me
and me
'); + const scriptPromise = (async () => { + await page.pause(); + await page.getByText('click me').click(); + playwright.selectors.setTestIdAttribute('data-custom-id'); + await page.getByTestId('foo').click(); + })(); + const recorderPage = await recorderPageGetter(); + + await recorderPage.click('[title="Step over (F10)"]'); + const div1Box1 = roundBox(await page.locator('x-pw-highlight').boundingBox()); + const div1Box2 = roundBox(await page.locator('#target1').boundingBox()); + expect(div1Box1).toEqual(div1Box2); + + await recorderPage.click('[title="Step over (F10)"]'); + let div2Box1: Box; + await expect.poll(async () => { + div2Box1 = await page.locator('x-pw-highlight').boundingBox(); + return div2Box1; + }).toBeTruthy(); + div2Box1 = roundBox(div2Box1); + const div2Box2 = roundBox(await page.locator('#target2').boundingBox()); + expect(div2Box1).toEqual(div2Box2); + + await recorderPage.click('[title="Resume (F8)"]'); + await scriptPromise; + }); }); async function sanitizeLog(recorderPage: Page): Promise {