mirror of
https://github.com/microsoft/playwright.git
synced 2025-06-26 21:40:17 +00:00
chore: allow running multiple snapshotters for tests (#6147)
This commit is contained in:
parent
db09275d89
commit
e6f5ce9044
@ -20,7 +20,7 @@ import * as network from '../network';
|
||||
import { helper, RegisteredListener } from '../helper';
|
||||
import { debugLogger } from '../../utils/debugLogger';
|
||||
import { Frame } from '../frames';
|
||||
import { SnapshotData, frameSnapshotStreamer, kSnapshotBinding, kSnapshotStreamer } from './snapshotterInjected';
|
||||
import { SnapshotData, frameSnapshotStreamer } from './snapshotterInjected';
|
||||
import { calculateSha1, createGuid, monotonicTime } from '../../utils/utils';
|
||||
import { FrameSnapshot, ResourceSnapshot } from './snapshotTypes';
|
||||
import { ElementHandle } from '../dom';
|
||||
@ -41,6 +41,8 @@ export class Snapshotter {
|
||||
private _delegate: SnapshotterDelegate;
|
||||
private _eventListeners: RegisteredListener[] = [];
|
||||
private _interval = 0;
|
||||
private _snapshotStreamer: string;
|
||||
private _snapshotBinding: string;
|
||||
|
||||
constructor(context: BrowserContext, delegate: SnapshotterDelegate) {
|
||||
this._context = context;
|
||||
@ -50,10 +52,13 @@ export class Snapshotter {
|
||||
this._eventListeners = [
|
||||
helper.addEventListener(this._context, BrowserContext.Events.Page, this._onPage.bind(this)),
|
||||
];
|
||||
const guid = createGuid();
|
||||
this._snapshotStreamer = '__playwright_snapshot_streamer_' + guid;
|
||||
this._snapshotBinding = '__playwright_snapshot_binding_' + guid;
|
||||
}
|
||||
|
||||
async initialize() {
|
||||
await this._context.exposeBinding(kSnapshotBinding, false, (source, data: SnapshotData) => {
|
||||
await this._context.exposeBinding(this._snapshotBinding, false, (source, data: SnapshotData) => {
|
||||
const snapshot: FrameSnapshot = {
|
||||
snapshotName: data.snapshotName,
|
||||
pageId: source.page.uniqueId,
|
||||
@ -79,7 +84,7 @@ export class Snapshotter {
|
||||
}
|
||||
this._delegate.onFrameSnapshot(snapshot);
|
||||
});
|
||||
const initScript = '(' + frameSnapshotStreamer.toString() + ')()';
|
||||
const initScript = `(${frameSnapshotStreamer})("${this._snapshotStreamer}", "${this._snapshotBinding}")`;
|
||||
await this._context._doAddInitScript(initScript);
|
||||
const frames = [];
|
||||
for (const page of this._context.pages())
|
||||
@ -95,7 +100,7 @@ export class Snapshotter {
|
||||
|
||||
captureSnapshot(page: Page, snapshotName: string, element?: ElementHandle) {
|
||||
// This needs to be sync, as in not awaiting for anything before we issue the command.
|
||||
const expression = `window[${JSON.stringify(kSnapshotStreamer)}].captureSnapshot(${JSON.stringify(snapshotName)})`;
|
||||
const expression = `window["${this._snapshotStreamer}"].captureSnapshot(${JSON.stringify(snapshotName)})`;
|
||||
element?.callFunctionNoReply((element: Element, snapshotName: string) => {
|
||||
element.setAttribute('__playwright_target__', snapshotName);
|
||||
}, snapshotName);
|
||||
@ -111,15 +116,14 @@ export class Snapshotter {
|
||||
const frames = [];
|
||||
for (const page of this._context.pages())
|
||||
frames.push(...page.frames());
|
||||
await Promise.all(frames.map(frame => setIntervalInFrame(frame, interval)));
|
||||
await Promise.all(frames.map(frame => this._setIntervalInFrame(frame, interval)));
|
||||
}
|
||||
|
||||
private _onPage(page: Page) {
|
||||
const processNewFrame = (frame: Frame) => {
|
||||
annotateFrameHierarchy(frame);
|
||||
setIntervalInFrame(frame, this._interval);
|
||||
// FIXME: make addInitScript work for pages w/ setContent.
|
||||
const initScript = '(' + frameSnapshotStreamer.toString() + ')()';
|
||||
this._annotateFrameHierarchy(frame);
|
||||
this._setIntervalInFrame(frame, this._interval);
|
||||
const initScript = `(${frameSnapshotStreamer})("${this._snapshotStreamer}", "${this._snapshotBinding}")`;
|
||||
frame._existingMainContext()?.rawEvaluate(initScript).catch(debugExceptionHandler);
|
||||
};
|
||||
for (const frame of page.frames())
|
||||
@ -128,7 +132,7 @@ export class Snapshotter {
|
||||
|
||||
// Push streamer interval on navigation.
|
||||
this._eventListeners.push(helper.addEventListener(page, Page.Events.InternalFrameNavigatedToNewDocument, frame => {
|
||||
setIntervalInFrame(frame, this._interval);
|
||||
this._setIntervalInFrame(frame, this._interval);
|
||||
}));
|
||||
|
||||
// Capture resources.
|
||||
@ -182,27 +186,27 @@ export class Snapshotter {
|
||||
if (body)
|
||||
this._delegate.onBlob({ sha1: responseSha1, buffer: body });
|
||||
}
|
||||
}
|
||||
|
||||
async function setIntervalInFrame(frame: Frame, interval: number) {
|
||||
const context = frame._existingMainContext();
|
||||
await context?.evaluate(({ kSnapshotStreamer, interval }) => {
|
||||
(window as any)[kSnapshotStreamer].setSnapshotInterval(interval);
|
||||
}, { kSnapshotStreamer, interval }).catch(debugExceptionHandler);
|
||||
}
|
||||
private async _setIntervalInFrame(frame: Frame, interval: number) {
|
||||
const context = frame._existingMainContext();
|
||||
await context?.evaluate(({ snapshotStreamer, interval }) => {
|
||||
(window as any)[snapshotStreamer].setSnapshotInterval(interval);
|
||||
}, { snapshotStreamer: this._snapshotStreamer, interval }).catch(debugExceptionHandler);
|
||||
}
|
||||
|
||||
async function annotateFrameHierarchy(frame: Frame) {
|
||||
try {
|
||||
const frameElement = await frame.frameElement();
|
||||
const parent = frame.parentFrame();
|
||||
if (!parent)
|
||||
return;
|
||||
const context = await parent._mainContext();
|
||||
await context?.evaluate(({ kSnapshotStreamer, frameElement, frameId }) => {
|
||||
(window as any)[kSnapshotStreamer].markIframe(frameElement, frameId);
|
||||
}, { kSnapshotStreamer, frameElement, frameId: frame.uniqueId });
|
||||
frameElement.dispose();
|
||||
} catch (e) {
|
||||
private async _annotateFrameHierarchy(frame: Frame) {
|
||||
try {
|
||||
const frameElement = await frame.frameElement();
|
||||
const parent = frame.parentFrame();
|
||||
if (!parent)
|
||||
return;
|
||||
const context = await parent._mainContext();
|
||||
await context?.evaluate(({ snapshotStreamer, frameElement, frameId }) => {
|
||||
(window as any)[snapshotStreamer].markIframe(frameElement, frameId);
|
||||
}, { snapshotStreamer: this._snapshotStreamer, frameElement, frameId: frame.uniqueId });
|
||||
frameElement.dispose();
|
||||
} catch (e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -31,15 +31,9 @@ export type SnapshotData = {
|
||||
collectionTime: number,
|
||||
};
|
||||
|
||||
export const kSnapshotStreamer = '__playwright_snapshot_streamer_';
|
||||
export const kSnapshotBinding = '__playwright_snapshot_binding_';
|
||||
|
||||
export function frameSnapshotStreamer() {
|
||||
export function frameSnapshotStreamer(snapshotStreamer: string, snapshotBinding: string) {
|
||||
// Communication with Playwright.
|
||||
const kSnapshotStreamer = '__playwright_snapshot_streamer_';
|
||||
const kSnapshotBinding = '__playwright_snapshot_binding_';
|
||||
|
||||
if ((window as any)[kSnapshotStreamer])
|
||||
if ((window as any)[snapshotStreamer])
|
||||
return;
|
||||
|
||||
// Attributes present in the snapshot.
|
||||
@ -186,7 +180,7 @@ export function frameSnapshotStreamer() {
|
||||
try {
|
||||
const snapshot = this._captureSnapshot(snapshotName);
|
||||
if (snapshot)
|
||||
(window as any)[kSnapshotBinding](snapshot);
|
||||
(window as any)[snapshotBinding](snapshot);
|
||||
} catch (e) {
|
||||
}
|
||||
if (this._interval)
|
||||
@ -458,5 +452,5 @@ export function frameSnapshotStreamer() {
|
||||
}
|
||||
}
|
||||
|
||||
(window as any)[kSnapshotStreamer] = new Streamer();
|
||||
(window as any)[snapshotStreamer] = new Streamer();
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user