chore: custom error if HTML report gets uploaded in Trace Viewer (#17558)

Fixes https://github.com/microsoft/playwright/issues/17309
This commit is contained in:
Max Schmitt 2022-09-26 20:57:05 +02:00 committed by GitHub
parent d6dbfe547f
commit cf75f8ca20
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 39 additions and 19 deletions

View File

@ -35,15 +35,27 @@ const loadedTraces = new Map<string, { traceModel: TraceModel, snapshotServer: S
const clientIdToTraceUrls = new MultiMap<string, string>();
async function loadTrace(trace: string, clientId: string, progress: (done: number, total: number) => void): Promise<TraceModel> {
const entry = loadedTraces.get(trace);
clientIdToTraceUrls.set(clientId, trace);
async function loadTrace(traceUrl: string, traceFileName: string | null, clientId: string, progress: (done: number, total: number) => void): Promise<TraceModel> {
const entry = loadedTraces.get(traceUrl);
clientIdToTraceUrls.set(clientId, traceUrl);
if (entry)
return entry.traceModel;
const traceModel = new TraceModel();
await traceModel.load(trace, progress);
try {
await traceModel.load(traceUrl, progress);
} catch (error: any) {
// eslint-disable-next-line no-console
console.error(error);
if (error?.message?.includes('Cannot find .trace file') && await traceModel.hasEntry('index.html'))
throw new Error('Could not load trace. Did you upload a Playwright HTML report instead? Make sure to extract the archive first and then double-click the index.html file or put it on a web server.');
else if (traceFileName)
throw new Error(`Could not load trace from ${traceFileName}. Make sure to upload a valid Playwright trace.`);
else
throw new Error(`Could not load trace from ${traceUrl}. Make sure a valid Playwright Trace is accessible over this url.`);
}
const snapshotServer = new SnapshotServer(traceModel.storage());
loadedTraces.set(trace, { traceModel, snapshotServer });
loadedTraces.set(traceUrl, { traceModel, snapshotServer });
return traceModel;
}
@ -65,21 +77,15 @@ async function doFetch(event: FetchEvent): Promise<Response> {
if (relativePath === '/context') {
try {
const traceModel = await loadTrace(traceUrl, event.clientId, (done: number, total: number) => {
const traceModel = await loadTrace(traceUrl, url.searchParams.get('traceFileName'), event.clientId, (done: number, total: number) => {
client.postMessage({ method: 'progress', params: { done, total } });
});
return new Response(JSON.stringify(traceModel!.contextEntry), {
status: 200,
headers: { 'Content-Type': 'application/json' }
});
} catch (error: unknown) {
// eslint-disable-next-line no-console
console.error(error);
const traceFileName = url.searchParams.get('traceFileName')!;
return new Response(JSON.stringify({
error: traceFileName ? `Could not load trace from ${traceFileName}. Make sure to upload a valid Playwright trace.` :
`Could not load trace from ${traceUrl}. Make sure a valid Playwright Trace is accessible over this url.`,
}), {
} catch (error: any) {
return new Response(JSON.stringify({ error: error?.message }), {
status: 500,
headers: { 'Content-Type': 'application/json' }
});

View File

@ -31,6 +31,7 @@ export class TraceModel {
private _snapshotStorage: PersistentSnapshotStorage | undefined;
private _entries = new Map<string, zip.Entry>();
private _version: number | undefined;
private _zipReader: zip.ZipReader | undefined;
constructor() {
this.contextEntry = createEmptyContext();
@ -46,12 +47,12 @@ export class TraceModel {
async load(traceURL: string, progress: (done: number, total: number) => void) {
this.contextEntry.traceUrl = traceURL;
const zipReader = new zipjs.ZipReader( // @ts-ignore
this._zipReader = new zipjs.ZipReader( // @ts-ignore
new zipjs.HttpReader(this._formatUrl(traceURL), { mode: 'cors', preventHeadRequest: true }),
{ useWebWorkers: false }) as zip.ZipReader;
let traceEntry: zip.Entry | undefined;
let networkEntry: zip.Entry | undefined;
for (const entry of await zipReader.getEntries({ onprogress: progress })) {
for (const entry of await this._zipReader.getEntries({ onprogress: progress })) {
if (entry.filename.endsWith('.trace'))
traceEntry = entry;
if (entry.filename.endsWith('.network'))
@ -60,10 +61,13 @@ export class TraceModel {
this.contextEntry.hasSource = true;
this._entries.set(entry.filename, entry);
}
if (!traceEntry)
throw new Error('Cannot find .trace file');
this._snapshotStorage = new PersistentSnapshotStorage(this._entries);
const traceWriter = new zipjs.TextWriter() as zip.TextWriter;
await traceEntry!.getData!(traceWriter);
await traceEntry.getData!(traceWriter);
for (const line of (await traceWriter.getData()).split('\n'))
this.appendEvent(line);
@ -76,6 +80,16 @@ export class TraceModel {
this._build();
}
async hasEntry(filename: string): Promise<boolean> {
if (!this._zipReader)
return false;
for (const entry of await this._zipReader.getEntries()) {
if (entry.filename === filename)
return true;
}
return false;
}
async resourceForSha1(sha1: string): Promise<Blob | undefined> {
const entry = this._entries.get('resources/' + sha1);
if (!entry)

View File

@ -286,7 +286,7 @@ for (const webPackage of ['html-reporter', 'recorder', 'trace-viewer']) {
`packages/web/src/`,
],
command: 'npx',
args: ['vite', 'build'],
args: ['vite', 'build', ...(watchMode ? ['--sourcemap'] : [])],
cwd: path.join(__dirname, '..', '..', 'packages', webPackage),
});
}
@ -335,7 +335,7 @@ if (lintMode) {
command: 'npx',
args: ['tsc', ...(watchMode ? ['-w'] : []), '-p', quotePath(filePath(`packages/${webPackage}`))],
shell: true,
});
});
}
}