chore: allow highlighting aria template from extension (#33594)
This commit is contained in:
Родитель
a8af7cc435
Коммит
4817483ff2
|
@ -422,7 +422,8 @@ scheme.DebugControllerSetRecorderModeParams = tObject({
|
|||
});
|
||||
scheme.DebugControllerSetRecorderModeResult = tOptional(tObject({}));
|
||||
scheme.DebugControllerHighlightParams = tObject({
|
||||
selector: tString,
|
||||
selector: tOptional(tString),
|
||||
ariaTemplate: tOptional(tString),
|
||||
});
|
||||
scheme.DebugControllerHighlightResult = tOptional(tObject({}));
|
||||
scheme.DebugControllerHideHighlightParams = tOptional(tObject({}));
|
||||
|
|
|
@ -15,12 +15,16 @@
|
|||
*/
|
||||
|
||||
import { parseYamlTemplate } from '../utils/isomorphic/ariaSnapshot';
|
||||
import type { AriaTemplateNode } from '@isomorphic/ariaSnapshot';
|
||||
import type { AriaTemplateNode, ParsedYaml } from '@isomorphic/ariaSnapshot';
|
||||
import { yaml } from '../utilsBundle';
|
||||
|
||||
export function parseAriaSnapshot(text: string): AriaTemplateNode {
|
||||
const fragment = yaml.parse(text);
|
||||
if (!Array.isArray(fragment))
|
||||
throw new Error('Expected object key starting with "- ":\n\n' + text + '\n');
|
||||
return parseYamlTemplate(fragment);
|
||||
return parseYamlTemplate(parseYamlForAriaSnapshot(text));
|
||||
}
|
||||
|
||||
export function parseYamlForAriaSnapshot(text: string): ParsedYaml {
|
||||
const parsed = yaml.parse(text);
|
||||
if (!Array.isArray(parsed))
|
||||
throw new Error('Expected object key starting with "- ":\n\n' + text + '\n');
|
||||
return parsed;
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ import type { Playwright } from './playwright';
|
|||
import { Recorder } from './recorder';
|
||||
import { EmptyRecorderApp } from './recorder/recorderApp';
|
||||
import { asLocator, type Language } from '../utils';
|
||||
import { parseYamlForAriaSnapshot } from './ariaSnapshot';
|
||||
|
||||
const internalMetadata = serverSideCallMetadata();
|
||||
|
||||
|
@ -142,9 +143,13 @@ export class DebugController extends SdkObject {
|
|||
this._autoCloseTimer = setTimeout(heartBeat, 30000);
|
||||
}
|
||||
|
||||
async highlight(selector: string) {
|
||||
for (const recorder of await this._allRecorders())
|
||||
recorder.setHighlightedSelector(this._sdkLanguage, selector);
|
||||
async highlight(params: { selector?: string, ariaTemplate?: string }) {
|
||||
for (const recorder of await this._allRecorders()) {
|
||||
if (params.ariaTemplate)
|
||||
recorder.setHighlightedAriaTemplate(parseYamlForAriaSnapshot(params.ariaTemplate));
|
||||
else if (params.selector)
|
||||
recorder.setHighlightedSelector(this._sdkLanguage, params.selector);
|
||||
}
|
||||
}
|
||||
|
||||
async hideHighlight() {
|
||||
|
|
|
@ -68,7 +68,7 @@ export class DebugControllerDispatcher extends Dispatcher<DebugController, chann
|
|||
}
|
||||
|
||||
async highlight(params: channels.DebugControllerHighlightParams) {
|
||||
await this._object.highlight(params.selector);
|
||||
await this._object.highlight(params);
|
||||
}
|
||||
|
||||
async hideHighlight() {
|
||||
|
|
|
@ -40,7 +40,7 @@ export class Recorder implements InstrumentationListener, IRecorder {
|
|||
readonly handleSIGINT: boolean | undefined;
|
||||
private _context: BrowserContext;
|
||||
private _mode: Mode;
|
||||
private _highlightedElement: { selector?: string, ariaSnapshot?: ParsedYaml } = {};
|
||||
private _highlightedElement: { selector?: string, ariaTemplate?: ParsedYaml } = {};
|
||||
private _overlayState: OverlayState = { offsetX: 0 };
|
||||
private _recorderApp: IRecorderApp | null = null;
|
||||
private _currentCallsMetadata = new Map<CallMetadata, SdkObject>();
|
||||
|
@ -107,8 +107,8 @@ export class Recorder implements InstrumentationListener, IRecorder {
|
|||
if (data.event === 'highlightRequested') {
|
||||
if (data.params.selector)
|
||||
this.setHighlightedSelector(this._currentLanguage, data.params.selector);
|
||||
if (data.params.ariaSnapshot)
|
||||
this.setHighlightedAriaSnapshot(data.params.ariaSnapshot);
|
||||
if (data.params.ariaTemplate)
|
||||
this.setHighlightedAriaTemplate(data.params.ariaTemplate);
|
||||
return;
|
||||
}
|
||||
if (data.event === 'step') {
|
||||
|
@ -169,7 +169,7 @@ export class Recorder implements InstrumentationListener, IRecorder {
|
|||
mode: this._mode,
|
||||
actionPoint,
|
||||
actionSelector,
|
||||
ariaTemplate: this._highlightedElement.ariaSnapshot,
|
||||
ariaTemplate: this._highlightedElement.ariaTemplate,
|
||||
language: this._currentLanguage,
|
||||
testIdAttributeName: this._contextRecorder.testIdAttributeName(),
|
||||
overlay: this._overlayState,
|
||||
|
@ -245,8 +245,8 @@ export class Recorder implements InstrumentationListener, IRecorder {
|
|||
this._refreshOverlay();
|
||||
}
|
||||
|
||||
setHighlightedAriaSnapshot(ariaSnapshot: ParsedYaml) {
|
||||
this._highlightedElement = { ariaSnapshot };
|
||||
setHighlightedAriaTemplate(ariaTemplate: ParsedYaml) {
|
||||
this._highlightedElement = { ariaTemplate };
|
||||
this._refreshOverlay();
|
||||
}
|
||||
|
||||
|
|
|
@ -741,10 +741,12 @@ export type DebugControllerSetRecorderModeOptions = {
|
|||
};
|
||||
export type DebugControllerSetRecorderModeResult = void;
|
||||
export type DebugControllerHighlightParams = {
|
||||
selector: string,
|
||||
selector?: string,
|
||||
ariaTemplate?: string,
|
||||
};
|
||||
export type DebugControllerHighlightOptions = {
|
||||
|
||||
selector?: string,
|
||||
ariaTemplate?: string,
|
||||
};
|
||||
export type DebugControllerHighlightResult = void;
|
||||
export type DebugControllerHideHighlightParams = {};
|
||||
|
|
|
@ -791,7 +791,8 @@ DebugController:
|
|||
|
||||
highlight:
|
||||
parameters:
|
||||
selector: string
|
||||
selector: string?
|
||||
ariaTemplate: string?
|
||||
|
||||
hideHighlight:
|
||||
|
||||
|
|
|
@ -120,7 +120,7 @@ export const Recorder: React.FC<RecorderProps> = ({
|
|||
setAriaSnapshotErrors(errors);
|
||||
setAriaSnapshot(ariaSnapshot);
|
||||
if (!errors.length)
|
||||
window.dispatch({ event: 'highlightRequested', params: { ariaSnapshot: fragment } });
|
||||
window.dispatch({ event: 'highlightRequested', params: { ariaTemplate: fragment } });
|
||||
}, [mode]);
|
||||
const isRecording = mode === 'recording' || mode === 'recording-inspecting';
|
||||
const locatorPlaceholder = isRecording ? '// Unavailable while recording' : (locator ? undefined : '// Pick element or type locator');
|
||||
|
|
|
@ -20,6 +20,7 @@ import { createGuid } from '../../packages/playwright-core/lib/utils/crypto';
|
|||
import { Backend } from '../config/debugControllerBackend';
|
||||
import type { Browser, BrowserContext } from '@playwright/test';
|
||||
import type * as channels from '@protocol/channels';
|
||||
import { roundBox } from '../page/pageTest';
|
||||
|
||||
type BrowserWithReuse = Browser & { _newContextForReuse: () => Promise<BrowserContext> };
|
||||
type Fixtures = {
|
||||
|
@ -279,3 +280,20 @@ test('should highlight inside iframe', async ({ backend, connectedBrowser }, tes
|
|||
await expect(highlight).toHaveCount(1);
|
||||
await expect(page.locator('x-pw-highlight')).toHaveCount(1);
|
||||
});
|
||||
|
||||
test('should highlight aria template', async ({ backend, connectedBrowser }, testInfo) => {
|
||||
const context = await connectedBrowser._newContextForReuse();
|
||||
const page = await context.newPage();
|
||||
await backend.navigate({ url: `data:text/html,<button>Submit</button>` });
|
||||
|
||||
const button = page.getByRole('button');
|
||||
const highlight = page.locator('x-pw-highlight');
|
||||
|
||||
await backend.highlight({ ariaTemplate: `- button "Submit2"` });
|
||||
await expect(highlight).toHaveCount(0);
|
||||
|
||||
await backend.highlight({ ariaTemplate: `- button "Submit"` });
|
||||
const box1 = roundBox(await button.boundingBox());
|
||||
const box2 = roundBox(await highlight.boundingBox());
|
||||
expect(box1).toEqual(box2);
|
||||
});
|
||||
|
|
Загрузка…
Ссылка в новой задаче