chore: allow highlighting aria template from extension (#33594)

This commit is contained in:
Pavel Feldman 2024-11-13 21:33:38 -08:00 коммит произвёл GitHub
Родитель a8af7cc435
Коммит 4817483ff2
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
9 изменённых файлов: 51 добавлений и 20 удалений

Просмотреть файл

@ -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);
});