store screenshots in zip file
This commit is contained in:
parent
651f5a3ea4
commit
f7420c651c
|
|
@ -151,6 +151,14 @@ export class Snapshotter {
|
||||||
snapshot.resourceOverrides.push({ url, ref: content });
|
snapshot.resourceOverrides.push({ url, ref: content });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const [sha1, contents] of Object.entries(data.canvasRenderResults)) {
|
||||||
|
this._delegate.onSnapshotterBlob({
|
||||||
|
sha1, buffer: Buffer.from(contents, 'base64')
|
||||||
|
});
|
||||||
|
snapshot.resourceOverrides.push({ url: 'TODO: this is required but unused', sha1 });
|
||||||
|
}
|
||||||
|
|
||||||
this._delegate.onFrameSnapshot(snapshot);
|
this._delegate.onFrameSnapshot(snapshot);
|
||||||
});
|
});
|
||||||
await Promise.all(snapshots);
|
await Promise.all(snapshots);
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ export type SnapshotData = {
|
||||||
url: string,
|
url: string,
|
||||||
timestamp: number,
|
timestamp: number,
|
||||||
collectionTime: number,
|
collectionTime: number,
|
||||||
|
canvasRenderResults: Record<string, string>,
|
||||||
};
|
};
|
||||||
|
|
||||||
export function frameSnapshotStreamer(snapshotStreamer: string, removeNoScript: boolean) {
|
export function frameSnapshotStreamer(snapshotStreamer: string, removeNoScript: boolean) {
|
||||||
|
|
@ -86,6 +87,7 @@ export function frameSnapshotStreamer(snapshotStreamer: string, removeNoScript:
|
||||||
private _readingStyleSheet = false; // To avoid invalidating due to our own reads.
|
private _readingStyleSheet = false; // To avoid invalidating due to our own reads.
|
||||||
private _fakeBase: HTMLBaseElement;
|
private _fakeBase: HTMLBaseElement;
|
||||||
private _observer: MutationObserver;
|
private _observer: MutationObserver;
|
||||||
|
private _capturedCanvases = new Set<string>();
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
const invalidateCSSGroupingRule = (rule: CSSGroupingRule) => {
|
const invalidateCSSGroupingRule = (rule: CSSGroupingRule) => {
|
||||||
|
|
@ -319,6 +321,7 @@ export function frameSnapshotStreamer(snapshotStreamer: string, removeNoScript:
|
||||||
this._handleMutations(this._observer.takeRecords());
|
this._handleMutations(this._observer.takeRecords());
|
||||||
|
|
||||||
const definedCustomElements = new Set<string>();
|
const definedCustomElements = new Set<string>();
|
||||||
|
const canvasRenderResults: Record<string, string> = {};
|
||||||
|
|
||||||
const visitNode = (node: Node | ShadowRoot): { equals: boolean, n: NodeSnapshot } | undefined => {
|
const visitNode = (node: Node | ShadowRoot): { equals: boolean, n: NodeSnapshot } | undefined => {
|
||||||
const nodeType = node.nodeType;
|
const nodeType = node.nodeType;
|
||||||
|
|
@ -406,7 +409,19 @@ export function frameSnapshotStreamer(snapshotStreamer: string, removeNoScript:
|
||||||
|
|
||||||
if (nodeName === 'CANVAS') {
|
if (nodeName === 'CANVAS') {
|
||||||
const canvas = node as HTMLCanvasElement;
|
const canvas = node as HTMLCanvasElement;
|
||||||
attrs['__playwright_canvas_'] = canvas.toDataURL('image/webp', 1);
|
const requestedMIME = 'image/webp';
|
||||||
|
const dataURL = canvas.toDataURL(requestedMIME);
|
||||||
|
const actualMIME = dataURL.substring('data:'.length, dataURL.indexOf(';'));
|
||||||
|
const contentsB64 = dataURL.substring(dataURL.indexOf(',') + 1);
|
||||||
|
const sha = '' + contentsB64.length; // TODO
|
||||||
|
|
||||||
|
attrs['__playwright_canvas_sha_'] = sha;
|
||||||
|
attrs['__playwright_canvas_mime_'] = actualMIME;
|
||||||
|
|
||||||
|
if (!this._capturedCanvases.has(sha)) {
|
||||||
|
this._capturedCanvases.add(sha);
|
||||||
|
canvasRenderResults[sha] = contentsB64;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nodeType === Node.DOCUMENT_FRAGMENT_NODE)
|
if (nodeType === Node.DOCUMENT_FRAGMENT_NODE)
|
||||||
|
|
@ -579,6 +594,7 @@ export function frameSnapshotStreamer(snapshotStreamer: string, removeNoScript:
|
||||||
url: location.href,
|
url: location.href,
|
||||||
timestamp,
|
timestamp,
|
||||||
collectionTime: 0,
|
collectionTime: 0,
|
||||||
|
canvasRenderResults,
|
||||||
};
|
};
|
||||||
|
|
||||||
for (const sheet of this._staleStyleSheets) {
|
for (const sheet of this._staleStyleSheets) {
|
||||||
|
|
|
||||||
|
|
@ -285,7 +285,13 @@ function snapshotScript(...targetIds: (string | undefined)[]) {
|
||||||
const context = canvas.getContext('2d');
|
const context = canvas.getContext('2d');
|
||||||
context?.drawImage(img, 0, 0);
|
context?.drawImage(img, 0, 0);
|
||||||
};
|
};
|
||||||
img.src = canvas.getAttribute('__playwright_canvas_')!;
|
const url = new URL(window.location.href);
|
||||||
|
const index = url.pathname.lastIndexOf('/snapshot/');
|
||||||
|
if (index !== -1)
|
||||||
|
url.pathname = url.pathname.substring(0, index + 1);
|
||||||
|
url.pathname += `sha1/${canvas.getAttribute('__playwright_canvas_sha_')}`;
|
||||||
|
url.searchParams.set('ct', canvas.getAttribute('__playwright_canvas_mime_')!);
|
||||||
|
img.src = url.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -133,7 +133,7 @@ async function doFetch(event: FetchEvent): Promise<Response> {
|
||||||
// Sha1 for sources is based on the file path, can't load it of a random model.
|
// Sha1 for sources is based on the file path, can't load it of a random model.
|
||||||
const sha1 = relativePath.slice('/sha1/'.length);
|
const sha1 = relativePath.slice('/sha1/'.length);
|
||||||
for (const trace of loadedTraces.values()) {
|
for (const trace of loadedTraces.values()) {
|
||||||
const blob = await trace.traceModel.resourceForSha1(sha1);
|
const blob = await trace.traceModel.resourceForSha1(sha1, url.searchParams.get('ct'));
|
||||||
if (blob)
|
if (blob)
|
||||||
return new Response(blob, { status: 200, headers: downloadHeaders(url.searchParams) });
|
return new Response(blob, { status: 200, headers: downloadHeaders(url.searchParams) });
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -112,11 +112,11 @@ export class TraceModel {
|
||||||
return this._backend.hasEntry(filename);
|
return this._backend.hasEntry(filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
async resourceForSha1(sha1: string): Promise<Blob | undefined> {
|
async resourceForSha1(sha1: string, contentTypeOverride?: string | null): Promise<Blob | undefined> {
|
||||||
const blob = await this._backend.readBlob('resources/' + sha1);
|
const blob = await this._backend.readBlob('resources/' + sha1);
|
||||||
if (!blob)
|
if (!blob)
|
||||||
return;
|
return;
|
||||||
return new Blob([blob], { type: this._resourceToContentType.get(sha1) || 'application/octet-stream' });
|
return new Blob([blob], { type: contentTypeOverride || this._resourceToContentType.get(sha1) || 'application/octet-stream' });
|
||||||
}
|
}
|
||||||
|
|
||||||
storage(): SnapshotStorage {
|
storage(): SnapshotStorage {
|
||||||
|
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 8.7 KiB |
Loading…
Reference in a new issue