fix(debug controller): highlight selectors in iframe (#33273)
This commit is contained in:
parent
96a29b69eb
commit
b148ce1ad1
|
|
@ -30,6 +30,8 @@ import type { IRecorderAppFactory, IRecorderApp, IRecorder } from './recorder/re
|
||||||
import { metadataToCallLog } from './recorder/recorderUtils';
|
import { metadataToCallLog } from './recorder/recorderUtils';
|
||||||
import type * as actions from '@recorder/actions';
|
import type * as actions from '@recorder/actions';
|
||||||
import { buildFullSelector } from '../utils/isomorphic/recorderUtils';
|
import { buildFullSelector } from '../utils/isomorphic/recorderUtils';
|
||||||
|
import { stringifySelector } from '../utils/isomorphic/selectorParser';
|
||||||
|
import type { Frame } from './frames';
|
||||||
|
|
||||||
const recorderSymbol = Symbol('recorderSymbol');
|
const recorderSymbol = Symbol('recorderSymbol');
|
||||||
|
|
||||||
|
|
@ -146,12 +148,12 @@ export class Recorder implements InstrumentationListener, IRecorder {
|
||||||
this._pushAllSources();
|
this._pushAllSources();
|
||||||
});
|
});
|
||||||
|
|
||||||
await this._context.exposeBinding('__pw_recorderState', false, source => {
|
await this._context.exposeBinding('__pw_recorderState', false, async source => {
|
||||||
let actionSelector = '';
|
let actionSelector = '';
|
||||||
let actionPoint: Point | undefined;
|
let actionPoint: Point | undefined;
|
||||||
const hasActiveScreenshotCommand = [...this._currentCallsMetadata.keys()].some(isScreenshotCommand);
|
const hasActiveScreenshotCommand = [...this._currentCallsMetadata.keys()].some(isScreenshotCommand);
|
||||||
if (!hasActiveScreenshotCommand) {
|
if (!hasActiveScreenshotCommand) {
|
||||||
actionSelector = this._highlightedSelector;
|
actionSelector = await this._scopeHighlightedSelectorToFrame(source.frame);
|
||||||
for (const [metadata, sdkObject] of this._currentCallsMetadata) {
|
for (const [metadata, sdkObject] of this._currentCallsMetadata) {
|
||||||
if (source.page === sdkObject.attribution.page) {
|
if (source.page === sdkObject.attribution.page) {
|
||||||
actionPoint = metadata.point || actionPoint;
|
actionPoint = metadata.point || actionPoint;
|
||||||
|
|
@ -243,13 +245,38 @@ export class Recorder implements InstrumentationListener, IRecorder {
|
||||||
this._refreshOverlay();
|
this._refreshOverlay();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async _scopeHighlightedSelectorToFrame(frame: Frame): Promise<string> {
|
||||||
|
try {
|
||||||
|
const mainFrame = frame._page.mainFrame();
|
||||||
|
const resolved = await mainFrame.selectors.resolveFrameForSelector(this._highlightedSelector);
|
||||||
|
// selector couldn't be found, don't highlight anything
|
||||||
|
if (!resolved)
|
||||||
|
return '';
|
||||||
|
|
||||||
|
// selector points to no specific frame, highlight in all frames
|
||||||
|
if (resolved?.frame === mainFrame)
|
||||||
|
return stringifySelector(resolved.info.parsed);
|
||||||
|
|
||||||
|
// selector points to this frame, highlight it
|
||||||
|
if (resolved?.frame === frame)
|
||||||
|
return stringifySelector(resolved.info.parsed);
|
||||||
|
|
||||||
|
// selector points to a different frame, highlight nothing
|
||||||
|
return '';
|
||||||
|
} catch {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
setOutput(codegenId: string, outputFile: string | undefined) {
|
setOutput(codegenId: string, outputFile: string | undefined) {
|
||||||
this._contextRecorder.setOutput(codegenId, outputFile);
|
this._contextRecorder.setOutput(codegenId, outputFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _refreshOverlay() {
|
private _refreshOverlay() {
|
||||||
for (const page of this._context.pages())
|
for (const page of this._context.pages()) {
|
||||||
page.mainFrame().evaluateExpression('window.__pw_refreshOverlay()').catch(() => {});
|
for (const frame of page.frames())
|
||||||
|
frame.evaluateExpression('window.__pw_refreshOverlay()').catch(() => {});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async onBeforeCall(sdkObject: SdkObject, metadata: CallMetadata) {
|
async onBeforeCall(sdkObject: SdkObject, metadata: CallMetadata) {
|
||||||
|
|
|
||||||
|
|
@ -253,3 +253,29 @@ test('should reset routes before reuse', async ({ server, connectedBrowserFactor
|
||||||
await expect(page2).toHaveTitle('console.log test');
|
await expect(page2).toHaveTitle('console.log test');
|
||||||
await browser2.close();
|
await browser2.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should highlight inside iframe', async ({ backend, connectedBrowser }, testInfo) => {
|
||||||
|
testInfo.annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/33146' });
|
||||||
|
|
||||||
|
const context = await connectedBrowser._newContextForReuse();
|
||||||
|
const page = await context.newPage();
|
||||||
|
await backend.navigate({ url: `data:text/html,<div>bar</div><iframe srcdoc="<div>bar</div>"/>` });
|
||||||
|
|
||||||
|
|
||||||
|
await page.frameLocator('iframe').getByText('bar').highlight();
|
||||||
|
|
||||||
|
const highlight = page.frameLocator('iframe').locator('x-pw-highlight');
|
||||||
|
await expect(highlight).not.toHaveCount(0);
|
||||||
|
await backend.hideHighlight();
|
||||||
|
await expect(highlight).toHaveCount(0);
|
||||||
|
|
||||||
|
await backend.highlight({ selector: `frameLocator('iframe').getByText('bar')` });
|
||||||
|
await expect(highlight).not.toHaveCount(0);
|
||||||
|
|
||||||
|
await backend.highlight({ selector: `frameLocator('iframe').frameLocator('iframe').getByText('bar')` });
|
||||||
|
await expect(highlight).toHaveCount(0);
|
||||||
|
|
||||||
|
await backend.highlight({ selector: `getByText('bar')` });
|
||||||
|
await expect(highlight).toHaveCount(1);
|
||||||
|
await expect(page.locator('x-pw-highlight')).toHaveCount(1);
|
||||||
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue