fix(tracing): do not capture iframes in head (#12126)

This commit is contained in:
Yury Semikhatsky 2022-02-16 09:09:15 -08:00 committed by GitHub
parent d4deefbad3
commit 08fd8d0762
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 29 additions and 0 deletions

View File

@ -269,6 +269,7 @@ export function frameSnapshotStreamer(snapshotStreamer: string) {
const snapshotNumber = ++this._lastSnapshotNumber; const snapshotNumber = ++this._lastSnapshotNumber;
let nodeCounter = 0; let nodeCounter = 0;
let shadowDomNesting = 0; let shadowDomNesting = 0;
let headNesting = 0;
// Ensure we are up to date. // Ensure we are up to date.
this._handleMutations(this._observer.takeRecords()); this._handleMutations(this._observer.takeRecords());
@ -293,6 +294,10 @@ export function frameSnapshotStreamer(snapshotStreamer: string) {
return; return;
if (nodeName === 'META' && (node as HTMLMetaElement).httpEquiv.toLowerCase() === 'content-security-policy') if (nodeName === 'META' && (node as HTMLMetaElement).httpEquiv.toLowerCase() === 'content-security-policy')
return; return;
// Skip iframes which are inside document's head as they are not visisble.
// See https://github.com/microsoft/playwright/issues/12005.
if ((nodeName === 'IFRAME' || nodeName === 'FRAME') && headNesting)
return;
const data = ensureCachedData(node); const data = ensureCachedData(node);
const values: any[] = []; const values: any[] = [];
@ -392,12 +397,15 @@ export function frameSnapshotStreamer(snapshotStreamer: string) {
result.push(value); result.push(value);
} else { } else {
if (nodeName === 'HEAD') { if (nodeName === 'HEAD') {
++headNesting;
// Insert fake <base> first, to ensure all <link> elements use the proper base uri. // Insert fake <base> first, to ensure all <link> elements use the proper base uri.
this._fakeBase.setAttribute('href', document.baseURI); this._fakeBase.setAttribute('href', document.baseURI);
visitChild(this._fakeBase); visitChild(this._fakeBase);
} }
for (let child = node.firstChild; child; child = child.nextSibling) for (let child = node.firstChild; child; child = child.nextSibling)
visitChild(child); visitChild(child);
if (nodeName === 'HEAD')
--headNesting;
expectValue(kEndOfList); expectValue(kEndOfList);
let documentOrShadowRoot = null; let documentOrShadowRoot = null;
if (node.ownerDocument!.documentElement === node) if (node.ownerDocument!.documentElement === node)

View File

@ -386,6 +386,27 @@ test('should not hang for clicks that open dialogs', async ({ context, page }) =
await context.tracing.stop(); await context.tracing.stop();
}); });
test('should ignore iframes in head', async ({ context, page, server }, testInfo) => {
await page.goto(server.PREFIX + '/input/button.html');
await page.evaluate(() => {
document.head.appendChild(document.createElement('iframe'));
// Add iframe in a shadow tree.
const div = document.createElement('div');
document.head.appendChild(div);
const shadow = div.attachShadow({ mode: 'open' });
shadow.appendChild(document.createElement('iframe'));
});
await context.tracing.start({ screenshots: true, snapshots: true });
await page.click('button');
await context.tracing.stopChunk({ path: testInfo.outputPath('trace.zip') });
const trace = await parseTrace(testInfo.outputPath('trace.zip'));
expect(trace.events.find(e => e.metadata?.apiName === 'page.click')).toBeTruthy();
expect(trace.events.find(e => e.type === 'frame-snapshot')).toBeTruthy();
expect(trace.events.find(e => e.type === 'frame-snapshot' && JSON.stringify(e.snapshot.html).includes('IFRAME'))).toBeFalsy();
});
test('should hide internal stack frames', async ({ context, page }, testInfo) => { test('should hide internal stack frames', async ({ context, page }, testInfo) => {
await context.tracing.start({ screenshots: true, snapshots: true }); await context.tracing.start({ screenshots: true, snapshots: true });
let evalPromise; let evalPromise;