Skip to content

Commit

Permalink
chore: allow highlighting aria template from extension (#33594)
Browse files Browse the repository at this point in the history
  • Loading branch information
pavelfeldman authored Nov 14, 2024
1 parent a8af7cc commit 4817483
Show file tree
Hide file tree
Showing 9 changed files with 50 additions and 19 deletions.
3 changes: 2 additions & 1 deletion packages/playwright-core/src/protocol/validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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({}));
Expand Down
12 changes: 8 additions & 4 deletions packages/playwright-core/src/server/ariaSnapshot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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))
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 parseYamlTemplate(fragment);
return parsed;
}
11 changes: 8 additions & 3 deletions packages/playwright-core/src/server/debugController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down Expand Up @@ -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() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
12 changes: 6 additions & 6 deletions packages/playwright-core/src/server/recorder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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>();
Expand Down Expand Up @@ -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') {
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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();
}

Expand Down
6 changes: 4 additions & 2 deletions packages/protocol/src/channels.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {};
Expand Down
3 changes: 2 additions & 1 deletion packages/protocol/src/protocol.yml
Original file line number Diff line number Diff line change
Expand Up @@ -791,7 +791,8 @@ DebugController:

highlight:
parameters:
selector: string
selector: string?
ariaTemplate: string?

hideHighlight:

Expand Down
2 changes: 1 addition & 1 deletion packages/recorder/src/recorder.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand Down
18 changes: 18 additions & 0 deletions tests/library/debug-controller.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down Expand Up @@ -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);
});

0 comments on commit 4817483

Please sign in to comment.