diff --git a/packages/playwright-core/src/utils/httpServer.ts b/packages/playwright-core/src/utils/httpServer.ts
index ab87f905f2..95715dc6e4 100644
--- a/packages/playwright-core/src/utils/httpServer.ts
+++ b/packages/playwright-core/src/utils/httpServer.ts
@@ -113,6 +113,18 @@ export class HttpServer {
}
private _onRequest(request: http.IncomingMessage, response: http.ServerResponse) {
+ response.setHeader('Access-Control-Allow-Origin', '*');
+ response.setHeader('Access-Control-Request-Method', '*');
+ response.setHeader('Access-Control-Allow-Methods', 'OPTIONS, GET');
+ if (request.headers.origin)
+ response.setHeader('Access-Control-Allow-Headers', request.headers.origin);
+
+ if (request.method === 'OPTIONS') {
+ response.writeHead(200);
+ response.end();
+ return;
+ }
+
request.on('error', () => response.end());
try {
if (!request.url) {
diff --git a/packages/playwright-core/src/web/traceViewer/snapshotRenderer.ts b/packages/playwright-core/src/web/traceViewer/snapshotRenderer.ts
index e0b93d1a49..aea85cfc81 100644
--- a/packages/playwright-core/src/web/traceViewer/snapshotRenderer.ts
+++ b/packages/playwright-core/src/web/traceViewer/snapshotRenderer.ts
@@ -220,6 +220,23 @@ function snapshotScript() {
element.scrollLeft = +element.getAttribute(scrollLeftAttribute)!;
element.removeAttribute(scrollLeftAttribute);
}
+
+ const search = new URL(window.location.href).searchParams;
+ const pointX = search.get('pointX');
+ const pointY = search.get('pointY');
+ if (pointX) {
+ const pointElement = document.createElement('x-pw-pointer');
+ pointElement.style.position = 'fixed';
+ pointElement.style.backgroundColor = 'red';
+ pointElement.style.width = '20px';
+ pointElement.style.height = '20px';
+ pointElement.style.borderRadius = '10px';
+ pointElement.style.margin = '-10px 0 0 -10px';
+ pointElement.style.zIndex = '2147483647';
+ pointElement.style.left = pointX + 'px';
+ pointElement.style.top = pointY + 'px';
+ document.documentElement.appendChild(pointElement);
+ }
};
window.addEventListener('load', onLoad);
}
diff --git a/packages/playwright-core/src/web/traceViewer/snapshotServer.ts b/packages/playwright-core/src/web/traceViewer/snapshotServer.ts
index bb2eb0fdde..b106635124 100644
--- a/packages/playwright-core/src/web/traceViewer/snapshotServer.ts
+++ b/packages/playwright-core/src/web/traceViewer/snapshotServer.ts
@@ -30,36 +30,6 @@ export class SnapshotServer {
this._snapshotStorage = snapshotStorage;
}
- static serveSnapshotRoot(): Response {
- return new Response(`
-
-
-
-
- `, {
- status: 200,
- headers: {
- 'Cache-Control': 'public, max-age=31536000',
- 'Content-Type': 'text/html'
- }
- });
- }
-
serveSnapshot(pathname: string, searchParams: URLSearchParams, snapshotUrl: string): Response {
const snapshot = this._snapshot(pathname.substring('/snapshot'.length), searchParams);
if (!snapshot)
@@ -132,33 +102,6 @@ declare global {
}
}
-function rootScript() {
- const pointElement = document.createElement('div');
- pointElement.style.position = 'fixed';
- pointElement.style.backgroundColor = 'red';
- pointElement.style.width = '20px';
- pointElement.style.height = '20px';
- pointElement.style.borderRadius = '10px';
- pointElement.style.margin = '-10px 0 0 -10px';
- pointElement.style.zIndex = '2147483647';
-
- const iframe = document.createElement('iframe');
- document.body.appendChild(iframe);
- (window as any).showSnapshot = async (url: string, options: { point?: Point } = {}) => {
- iframe.src = url;
- if (options.point) {
- pointElement.style.left = options.point.x + 'px';
- pointElement.style.top = options.point.y + 'px';
- document.documentElement.appendChild(pointElement);
- } else {
- pointElement.remove();
- }
- };
- window.addEventListener('message', event => {
- window.showSnapshot(window.location.href + event.data.snapshotUrl);
- }, false);
-}
-
function removeHash(url: string) {
try {
const u = new URL(url);
diff --git a/packages/playwright-core/src/web/traceViewer/sw.ts b/packages/playwright-core/src/web/traceViewer/sw.ts
index 3811c3bb0e..93212fadba 100644
--- a/packages/playwright-core/src/web/traceViewer/sw.ts
+++ b/packages/playwright-core/src/web/traceViewer/sw.ts
@@ -31,7 +31,7 @@ let snapshotServer: SnapshotServer | undefined;
async function loadTrace(trace: string): Promise {
const traceModel = new TraceModel();
- const url = trace.startsWith('http') ? trace : `/file?path=${trace}`;
+ const url = trace.startsWith('http') || trace.startsWith('blob') ? trace : `/file?path=${trace}`;
await traceModel.load(url);
return traceModel;
}
@@ -53,8 +53,6 @@ async function doFetch(event: FetchEvent): Promise {
headers: { 'Content-Type': 'application/json' }
});
}
- if (pathname === '/snapshot/')
- return SnapshotServer.serveSnapshotRoot();
if (pathname.startsWith('/snapshotSize/'))
return snapshotServer!.serveSnapshotSize(pathname, searchParams);
if (pathname.startsWith('/snapshot/'))
diff --git a/packages/playwright-core/src/web/traceViewer/traceModel.ts b/packages/playwright-core/src/web/traceViewer/traceModel.ts
index 608d67edeb..0c731e0d9e 100644
--- a/packages/playwright-core/src/web/traceViewer/traceModel.ts
+++ b/packages/playwright-core/src/web/traceViewer/traceModel.ts
@@ -43,7 +43,7 @@ export class TraceModel {
}
async load(traceURL: string) {
- const response = await fetch(traceURL);
+ const response = await fetch(traceURL, { mode: 'cors' });
const blob = await response.blob();
const zipReader = new zipjs.ZipReader(new zipjs.BlobReader(blob), { useWebWorkers: false }) as zip.ZipReader;
let traceEntry: zip.Entry | undefined;
diff --git a/packages/playwright-core/src/web/traceViewer/ui/actionList.css b/packages/playwright-core/src/web/traceViewer/ui/actionList.css
index c530eafb27..181454f657 100644
--- a/packages/playwright-core/src/web/traceViewer/ui/actionList.css
+++ b/packages/playwright-core/src/web/traceViewer/ui/actionList.css
@@ -124,13 +124,8 @@
}
.no-actions-entry {
- height: 400px;
- display: grid;
- place-items: center;
- text-align: center;
-}
-
-.no-actions-entry-text {
- font-weight: bold;
- font-size: 1.3rem;
+ flex: auto;
+ display: flex;
+ align-items: center;
+ justify-content: center;
}
diff --git a/packages/playwright-core/src/web/traceViewer/ui/actionList.tsx b/packages/playwright-core/src/web/traceViewer/ui/actionList.tsx
index b62f333261..1a99507de2 100644
--- a/packages/playwright-core/src/web/traceViewer/ui/actionList.tsx
+++ b/packages/playwright-core/src/web/traceViewer/ui/actionList.tsx
@@ -72,16 +72,7 @@ export const ActionList: React.FC = ({
}}
ref={actionListRef}
>
- {actions.length === 0 &&
-
-
- No actions recorded
-
-
- Make sure that the right context was used when recording the trace.
-
-
-
}
+ {actions.length === 0 && No actions recorded
}
{actions.map(action => {
const { metadata } = action;
const selectedSuffix = action === selectedAction ? ' selected' : '';
diff --git a/packages/playwright-core/src/web/traceViewer/ui/snapshotTab.tsx b/packages/playwright-core/src/web/traceViewer/ui/snapshotTab.tsx
index ac33873f3e..1a1e831e81 100644
--- a/packages/playwright-core/src/web/traceViewer/ui/snapshotTab.tsx
+++ b/packages/playwright-core/src/web/traceViewer/ui/snapshotTab.tsx
@@ -66,8 +66,7 @@ export const SnapshotTab: React.FunctionComponent<{
if (!iframeRef.current)
return;
try {
- const point = pointX === undefined ? undefined : { x: pointX, y: pointY };
- (iframeRef.current.contentWindow as any).showSnapshot(snapshotUrl, { point });
+ iframeRef.current.src = snapshotUrl + (pointX === undefined ? '' : `&pointX=${pointX}&pointY=${pointY}`);
} catch (e) {
}
})();
@@ -102,7 +101,7 @@ export const SnapshotTab: React.FunctionComponent<{
height: snapshotSize.height + 'px',
transform: `translate(${-snapshotSize.width * (1 - scale) / 2 + (measure.width - scaledSize.width) / 2}px, ${-snapshotSize.height * (1 - scale) / 2 + (measure.height - scaledSize.height) / 2}px) scale(${scale})`,
}}>
-
+
;
diff --git a/packages/playwright-core/src/web/traceViewer/ui/workbench.tsx b/packages/playwright-core/src/web/traceViewer/ui/workbench.tsx
index a6d759d126..7e06cc6ab0 100644
--- a/packages/playwright-core/src/web/traceViewer/ui/workbench.tsx
+++ b/packages/playwright-core/src/web/traceViewer/ui/workbench.tsx
@@ -31,19 +31,19 @@ import * as modelUtil from './modelUtil';
export const Workbench: React.FunctionComponent<{
}> = () => {
+ const [traceURL, setTraceURL] = React.useState(new URL(window.location.href).searchParams.get('trace')!);
const [contextEntry, setContextEntry] = React.useState(emptyContext);
const [selectedAction, setSelectedAction] = React.useState();
const [highlightedAction, setHighlightedAction] = React.useState();
const [selectedTab, setSelectedTab] = React.useState('logs');
- const trace = new URL(window.location.href).searchParams.get('trace');
React.useEffect(() => {
(async () => {
- const contextEntry = (await fetch(`/context?trace=${trace}`).then(response => response.json())) as ContextEntry;
+ const contextEntry = (await fetch(`/context?trace=${traceURL}`).then(response => response.json())) as ContextEntry;
modelUtil.indexModel(contextEntry);
setContextEntry(contextEntry);
})();
- }, [trace]);
+ }, [traceURL]);
const actions = React.useMemo(() => {
const actions: ActionTraceEvent[] = [];
@@ -61,7 +61,13 @@ export const Workbench: React.FunctionComponent<{
const consoleCount = errors + warnings;
const networkCount = selectedAction ? modelUtil.resourcesForAction(selectedAction).length : 0;
- return
+ return
{ event.preventDefault(); }}
+ onDrop={event => {
+ event.preventDefault();
+ const url = URL.createObjectURL(event.dataTransfer.files[0]);
+ setTraceURL(url.toString());
+ }}>
ðŸŽ
Playwright
diff --git a/tests/trace-viewer/trace-viewer.spec.ts b/tests/trace-viewer/trace-viewer.spec.ts
index 95b81d49d9..32d5e0a28c 100644
--- a/tests/trace-viewer/trace-viewer.spec.ts
+++ b/tests/trace-viewer/trace-viewer.spec.ts
@@ -84,9 +84,9 @@ class TraceViewerPage {
async snapshotFrame(actionName: string, ordinal: number = 0, hasSubframe: boolean = false): Promise
{
await this.selectAction(actionName, ordinal);
- while (this.page.frames().length < (hasSubframe ? 4 : 3))
+ while (this.page.frames().length < (hasSubframe ? 3 : 2))
await this.page.waitForEvent('frameattached');
- return this.page.mainFrame().childFrames()[0].childFrames()[0];
+ return this.page.mainFrame().childFrames()[0];
}
}