fix(inspector): support custom test id attribute (#18996)
Fixes #18959.
This commit is contained in:
parent
4f72a895e9
commit
43a6bf4d45
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ export class BrowserDispatcher extends Dispatcher<Browser, channels.BrowserChann
|
|||
}
|
||||
|
||||
async newContextForReuse(params: channels.BrowserNewContextForReuseParams, metadata: CallMetadata): Promise<channels.BrowserNewContextForReuseResult> {
|
||||
return newContextForReuse(this._object, this, params, null, metadata);
|
||||
return await newContextForReuse(this._object, this, params, null, metadata);
|
||||
}
|
||||
|
||||
async close(): Promise<void> {
|
||||
|
|
@ -105,7 +105,7 @@ export class ConnectedBrowserDispatcher extends Dispatcher<Browser, channels.Bro
|
|||
}
|
||||
|
||||
async newContextForReuse(params: channels.BrowserNewContextForReuseParams, metadata: CallMetadata): Promise<channels.BrowserNewContextForReuseResult> {
|
||||
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<void> {
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
|
|
|
|||
|
|
@ -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(`<div data-custom-id='one'>One</div>`);
|
||||
|
||||
// 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(`<div data-custom-id='one'>One</div>`);
|
||||
// 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();
|
||||
});`
|
||||
});
|
||||
|
|
|
|||
|
|
@ -413,6 +413,35 @@ it.describe('pause', () => {
|
|||
'keyup',
|
||||
]);
|
||||
});
|
||||
|
||||
it('should highlight locators with custom testId', async ({ page, playwright, recorderPageGetter }) => {
|
||||
await page.setContent('<div id=target1>click me</div><div data-custom-id=foo id=target2>and me</div>');
|
||||
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<string[]> {
|
||||
|
|
|
|||
Loading…
Reference in a new issue