feat(trace): preserve noscript when javascript is disabled (#28971)
Closes #27504, closes #27532.
This commit is contained in:
parent
7670fd21e2
commit
48317af1cc
|
|
@ -86,7 +86,7 @@ export class Snapshotter {
|
||||||
eventsHelper.addEventListener(this._context, BrowserContext.Events.Page, this._onPage.bind(this)),
|
eventsHelper.addEventListener(this._context, BrowserContext.Events.Page, this._onPage.bind(this)),
|
||||||
];
|
];
|
||||||
|
|
||||||
const initScript = `(${frameSnapshotStreamer})("${this._snapshotStreamer}")`;
|
const initScript = `(${frameSnapshotStreamer})("${this._snapshotStreamer}", ${!!this._context._options.javaScriptEnabled})`;
|
||||||
await this._context.addInitScript(initScript);
|
await this._context.addInitScript(initScript);
|
||||||
await this._runInAllFrames(initScript);
|
await this._runInAllFrames(initScript);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ export type SnapshotData = {
|
||||||
collectionTime: number,
|
collectionTime: number,
|
||||||
};
|
};
|
||||||
|
|
||||||
export function frameSnapshotStreamer(snapshotStreamer: string) {
|
export function frameSnapshotStreamer(snapshotStreamer: string, removeNoScript: boolean) {
|
||||||
// Communication with Playwright.
|
// Communication with Playwright.
|
||||||
if ((window as any)[snapshotStreamer])
|
if ((window as any)[snapshotStreamer])
|
||||||
return;
|
return;
|
||||||
|
|
@ -81,7 +81,6 @@ export function frameSnapshotStreamer(snapshotStreamer: string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
class Streamer {
|
class Streamer {
|
||||||
private _removeNoScript = true;
|
|
||||||
private _lastSnapshotNumber = 0;
|
private _lastSnapshotNumber = 0;
|
||||||
private _staleStyleSheets = new Set<CSSStyleSheet>();
|
private _staleStyleSheets = new Set<CSSStyleSheet>();
|
||||||
private _readingStyleSheet = false; // To avoid invalidating due to our own reads.
|
private _readingStyleSheet = false; // To avoid invalidating due to our own reads.
|
||||||
|
|
@ -337,7 +336,7 @@ export function frameSnapshotStreamer(snapshotStreamer: string) {
|
||||||
if (rel === 'preload' || rel === 'prefetch')
|
if (rel === 'preload' || rel === 'prefetch')
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this._removeNoScript && nodeName === 'NOSCRIPT')
|
if (removeNoScript && nodeName === 'NOSCRIPT')
|
||||||
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;
|
||||||
|
|
|
||||||
|
|
@ -65,15 +65,18 @@ export class SnapshotRenderer {
|
||||||
}
|
}
|
||||||
} else if (typeof n[0] === 'string') {
|
} else if (typeof n[0] === 'string') {
|
||||||
// Element node.
|
// Element node.
|
||||||
const builder: string[] = [];
|
// Note that <noscript> will not be rendered by default in the trace viewer, because
|
||||||
builder.push('<', n[0]);
|
// JS is enabled. So rename it to <x-noscript>.
|
||||||
|
const nodeName = n[0] === 'NOSCRIPT' ? 'X-NOSCRIPT' : n[0];
|
||||||
const attrs = Object.entries(n[1] || {});
|
const attrs = Object.entries(n[1] || {});
|
||||||
|
const builder: string[] = [];
|
||||||
|
builder.push('<', nodeName);
|
||||||
const kCurrentSrcAttribute = '__playwright_current_src__';
|
const kCurrentSrcAttribute = '__playwright_current_src__';
|
||||||
const isFrame = n[0] === 'IFRAME' || n[0] === 'FRAME';
|
const isFrame = nodeName === 'IFRAME' || nodeName === 'FRAME';
|
||||||
const isAnchor = n[0] === 'A';
|
const isAnchor = nodeName === 'A';
|
||||||
const isImg = n[0] === 'IMG';
|
const isImg = nodeName === 'IMG';
|
||||||
const isImgWithCurrentSrc = isImg && attrs.some(a => a[0] === kCurrentSrcAttribute);
|
const isImgWithCurrentSrc = isImg && attrs.some(a => a[0] === kCurrentSrcAttribute);
|
||||||
const isSourceInsidePictureWithCurrentSrc = n[0] === 'SOURCE' && parentTag === 'PICTURE' && parentAttrs?.some(a => a[0] === kCurrentSrcAttribute);
|
const isSourceInsidePictureWithCurrentSrc = nodeName === 'SOURCE' && parentTag === 'PICTURE' && parentAttrs?.some(a => a[0] === kCurrentSrcAttribute);
|
||||||
for (const [attr, value] of attrs) {
|
for (const [attr, value] of attrs) {
|
||||||
let attrName = attr;
|
let attrName = attr;
|
||||||
if (isFrame && attr.toLowerCase() === 'src') {
|
if (isFrame && attr.toLowerCase() === 'src') {
|
||||||
|
|
@ -99,9 +102,9 @@ export class SnapshotRenderer {
|
||||||
}
|
}
|
||||||
builder.push('>');
|
builder.push('>');
|
||||||
for (let i = 2; i < n.length; i++)
|
for (let i = 2; i < n.length; i++)
|
||||||
builder.push(visit(n[i], snapshotIndex, n[0], attrs));
|
builder.push(visit(n[i], snapshotIndex, nodeName, attrs));
|
||||||
if (!autoClosing.has(n[0]))
|
if (!autoClosing.has(nodeName))
|
||||||
builder.push('</', n[0], '>');
|
builder.push('</', nodeName, '>');
|
||||||
(n as any)._string = builder.join('');
|
(n as any)._string = builder.join('');
|
||||||
} else {
|
} else {
|
||||||
// Why are we here? Let's not throw, just in case.
|
// Why are we here? Let's not throw, just in case.
|
||||||
|
|
|
||||||
|
|
@ -1121,3 +1121,21 @@ test('should highlight locator in iframe while typing', async ({ page, runAndTra
|
||||||
expect(Math.abs(elementBox.y - highlightBox.y)).toBeLessThan(5);
|
expect(Math.abs(elementBox.y - highlightBox.y)).toBeLessThan(5);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should preserve noscript when javascript is disabled', async ({ browser, server, showTraceViewer }) => {
|
||||||
|
const traceFile = test.info().outputPath('trace.zip');
|
||||||
|
const page = await browser.newPage({ javaScriptEnabled: false });
|
||||||
|
await page.context().tracing.start({ snapshots: true, screenshots: true, sources: true });
|
||||||
|
await page.goto(server.EMPTY_PAGE);
|
||||||
|
await page.setContent(`
|
||||||
|
<body>
|
||||||
|
<noscript>javascript is disabled!</noscript>
|
||||||
|
</body>
|
||||||
|
`);
|
||||||
|
await page.context().tracing.stop({ path: traceFile });
|
||||||
|
await page.close();
|
||||||
|
|
||||||
|
const traceViewer = await showTraceViewer([traceFile]);
|
||||||
|
const frame = await traceViewer.snapshotFrame('page.setContent');
|
||||||
|
await expect(frame.getByText('javascript is disabled!')).toBeVisible();
|
||||||
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue