Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 12 additions & 7 deletions packages/trace-viewer/src/sw/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ function loadTrace(clientId: string, url: URL, isContextRequest: boolean, progre
return loadedTrace;
const promise = innerLoadTrace(traceUrl, progress);
loadedTraces.set(traceUrl, promise);
promise.catch(() => loadedTraces.delete(traceUrl));
return promise;
}

Expand All @@ -118,7 +119,14 @@ async function innerLoadTrace(traceUrl: string, progress: Progress): Promise<Loa
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.');
if (error instanceof TraceVersionError)
throw new Error(`Could not load trace from ${traceUrl}. ${error.message}`);
throw new Error(`Could not load trace from ${traceUrl}. Make sure a valid Playwright Trace is accessible over this url.`);

let message = `Could not load trace from ${traceUrl}. Make sure a valid Playwright Trace is accessible over this url.`;

const lnaPermission = await navigator.permissions.query({ name: 'local-network-access' as PermissionName }).catch(() => { });
if (lnaPermission && lnaPermission.state !== 'granted')
message += `\n\nIf your trace is in a local or private network, please grant permission for Local Network Access.`; // workbenchLoader.tsx opens the prompt when it sees this message.

throw new Error(message);
}
const snapshotServer = new SnapshotServer(traceModel.storage(), sha1 => traceModel.resourceForSha1(sha1));
return { traceModel, snapshotServer };
Expand All @@ -131,12 +139,6 @@ async function doFetch(event: FetchEvent): Promise<Response> {
if (request.url.startsWith('chrome-extension://'))
return fetch(request);

if (request.headers.get('x-pw-serviceworker') === 'forward') {
const request = new Request(event.request);
request.headers.delete('x-pw-serviceworker');
return fetch(request);
}

const url = new URL(request.url);
let relativePath: string | undefined;
if (request.url.startsWith(self.registration.scope))
Expand Down Expand Up @@ -281,5 +283,8 @@ function isLiveTrace(traceUrl: string): boolean {
}

self.addEventListener('fetch', function(event: FetchEvent) {
if (event.request.headers.get('x-pw-serviceworker') === 'skip')
return false;

event.respondWith(doFetch(event));
});
1 change: 1 addition & 0 deletions packages/trace-viewer/src/ui/workbenchLoader.css
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ body .drop-target {
font-weight: bold;
text-align: center;
margin: 30px;
white-space: pre-line;
}

.drop-target input {
Expand Down
33 changes: 23 additions & 10 deletions packages/trace-viewer/src/ui/workbenchLoader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -139,19 +139,32 @@ export const WorkbenchLoader: React.FunctionComponent<{
navigator.serviceWorker.addEventListener('message', swListener);
setProgress({ done: 0, total: 1 });

const params = new URLSearchParams();
params.set('trace', traceURL);
const response = await fetch(`contexts?${params.toString()}`);
if (!response.ok) {
async function tryFetch(traceURL: string): Promise<string | undefined> {
const params = new URLSearchParams();
params.set('trace', traceURL);
const response = await fetch(`contexts?${params.toString()}`);
if (!response.ok) {
const { error } = await response.json();
setProcessingErrorMessage(error);
return error;
}
const contextEntries = await response.json();
const model = new MultiTraceModel(traceURL, contextEntries);
setProgress({ done: 0, total: 0 });
setProcessingErrorMessage(null);
setModel(model);
}

let error = await tryFetch(traceURL);
if (error?.includes('please grant permission for Local Network Access')) {
// fetching the asset opens the permission prompt. but only from window, not from SW (https://issues.chromium.org/issues/460180743)
await fetch(traceURL, { headers: { 'x-pw-serviceworker': 'skip' } });
error = await tryFetch(traceURL);
}
if (error) {
if (!isServer)
setTraceURL(undefined);
setProcessingErrorMessage((await response.json()).error);
return;
}
const contextEntries = await response.json();
const model = new MultiTraceModel(traceURL, contextEntries);
setProgress({ done: 0, total: 0 });
setModel(model);
} finally {
navigator.serviceWorker.removeEventListener('message', swListener);
}
Expand Down
Loading