mirror of
https://github.com/microsoft/playwright.git
synced 2024-12-14 13:45:36 +03:00
feat(trace-viewer): render snapshot urls (#9993)
This commit is contained in:
parent
009478b8d5
commit
cd47bf26e8
@ -39,9 +39,12 @@ export class SnapshotServer {
|
||||
return new Response(renderedSnapshot.html, { status: 200, headers: { 'Content-Type': 'text/html' } });
|
||||
}
|
||||
|
||||
serveSnapshotSize(pathname: string, searchParams: URLSearchParams): Response {
|
||||
const snapshot = this._snapshot(pathname.substring('/snapshotSize'.length), searchParams);
|
||||
return this._respondWithJson(snapshot ? snapshot.viewport() : {});
|
||||
serveSnapshotInfo(pathname: string, searchParams: URLSearchParams): Response {
|
||||
const snapshot = this._snapshot(pathname.substring('/snapshotInfo'.length), searchParams);
|
||||
return this._respondWithJson(snapshot ? {
|
||||
viewport: snapshot.viewport(),
|
||||
url: snapshot.snapshot().frameUrl
|
||||
} : {});
|
||||
}
|
||||
|
||||
private _snapshot(pathname: string, params: URLSearchParams) {
|
||||
|
@ -74,10 +74,10 @@ async function doFetch(event: FetchEvent): Promise<Response> {
|
||||
});
|
||||
}
|
||||
|
||||
if (relativePath.startsWith('/snapshotSize/')) {
|
||||
if (relativePath.startsWith('/snapshotInfo/')) {
|
||||
if (!snapshotServer)
|
||||
return new Response(null, { status: 404 });
|
||||
return snapshotServer.serveSnapshotSize(relativePath, url.searchParams);
|
||||
return snapshotServer.serveSnapshotInfo(relativePath, url.searchParams);
|
||||
}
|
||||
|
||||
if (relativePath.startsWith('/snapshot/')) {
|
||||
|
@ -64,6 +64,17 @@
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.snapshot-url {
|
||||
background-color: var(--background);
|
||||
margin: 10px;
|
||||
padding: 4px;
|
||||
border-radius: 3px;
|
||||
height: 28px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.snapshot-container {
|
||||
display: block;
|
||||
background: white;
|
||||
|
@ -23,8 +23,8 @@ import { ActionTraceEvent } from '../../../server/trace/common/traceEvents';
|
||||
|
||||
export const SnapshotTab: React.FunctionComponent<{
|
||||
action: ActionTraceEvent | undefined,
|
||||
defaultSnapshotSize: Size,
|
||||
}> = ({ action, defaultSnapshotSize }) => {
|
||||
defaultSnapshotInfo: { viewport: Size, url: string },
|
||||
}> = ({ action, defaultSnapshotInfo }) => {
|
||||
const [measure, ref] = useMeasure<HTMLDivElement>();
|
||||
const [snapshotIndex, setSnapshotIndex] = React.useState(0);
|
||||
|
||||
@ -35,7 +35,7 @@ export const SnapshotTab: React.FunctionComponent<{
|
||||
const snapshots = [actionSnapshot ? { ...actionSnapshot, title: 'action' } : undefined, snapshotMap.get('before'), snapshotMap.get('after')].filter(Boolean) as { title: string, snapshotName: string }[];
|
||||
|
||||
let snapshotUrl = 'data:text/html,<body style="background: #ddd"></body>';
|
||||
let snapshotSizeUrl: string | undefined;
|
||||
let snapshotInfoUrl: string | undefined;
|
||||
let pointX: number | undefined;
|
||||
let pointY: number | undefined;
|
||||
if (action) {
|
||||
@ -43,7 +43,7 @@ export const SnapshotTab: React.FunctionComponent<{
|
||||
if (snapshot && snapshot.snapshotName) {
|
||||
const traceUrl = new URL(window.location.href).searchParams.get('trace');
|
||||
snapshotUrl = new URL(`snapshot/${action.metadata.pageId}?trace=${traceUrl}&name=${snapshot.snapshotName}`, window.location.href).toString();
|
||||
snapshotSizeUrl = new URL(`snapshotSize/${action.metadata.pageId}?trace=${traceUrl}&name=${snapshot.snapshotName}`, window.location.href).toString();
|
||||
snapshotInfoUrl = new URL(`snapshotInfo/${action.metadata.pageId}?trace=${traceUrl}&name=${snapshot.snapshotName}`, window.location.href).toString();
|
||||
if (snapshot.snapshotName.includes('action')) {
|
||||
pointX = action.metadata.point?.x;
|
||||
pointY = action.metadata.point?.y;
|
||||
@ -57,12 +57,13 @@ export const SnapshotTab: React.FunctionComponent<{
|
||||
}, [snapshotIndex, snapshots]);
|
||||
|
||||
const iframeRef = React.useRef<HTMLIFrameElement>(null);
|
||||
const [snapshotSize, setSnapshotSize] = React.useState(defaultSnapshotSize);
|
||||
const [snapshotInfo, setSnapshotInfo] = React.useState(defaultSnapshotInfo);
|
||||
React.useEffect(() => {
|
||||
(async () => {
|
||||
if (snapshotSizeUrl) {
|
||||
const response = await fetch(snapshotSizeUrl);
|
||||
setSnapshotSize(await response.json());
|
||||
if (snapshotInfoUrl) {
|
||||
const response = await fetch(snapshotInfoUrl);
|
||||
const info = await response.json();
|
||||
setSnapshotInfo(info);
|
||||
}
|
||||
if (!iframeRef.current)
|
||||
return;
|
||||
@ -71,8 +72,9 @@ export const SnapshotTab: React.FunctionComponent<{
|
||||
} catch (e) {
|
||||
}
|
||||
})();
|
||||
}, [iframeRef, snapshotUrl, snapshotSizeUrl, pointX, pointY]);
|
||||
}, [iframeRef, snapshotUrl, snapshotInfoUrl, pointX, pointY]);
|
||||
|
||||
const snapshotSize = snapshotInfo.viewport;
|
||||
const scale = Math.min(measure.width / snapshotSize.width, measure.height / snapshotSize.height, 1);
|
||||
const scaledSize = {
|
||||
width: snapshotSize.width * scale,
|
||||
@ -96,6 +98,7 @@ export const SnapshotTab: React.FunctionComponent<{
|
||||
</div>;
|
||||
})}
|
||||
</div>
|
||||
<div className='snapshot-url' title={snapshotInfo.url}>{snapshotInfo.url}</div>
|
||||
<div ref={ref} className='snapshot-wrapper'>
|
||||
<div className='snapshot-container' style={{
|
||||
width: snapshotSize.width + 'px',
|
||||
|
@ -83,7 +83,7 @@ export const Workbench: React.FunctionComponent<{
|
||||
})();
|
||||
}, [traceURL]);
|
||||
|
||||
const defaultSnapshotSize = contextEntry.options.viewport || { width: 1280, height: 720 };
|
||||
const defaultSnapshotInfo = { viewport: contextEntry.options.viewport || { width: 1280, height: 720 }, url: '' };
|
||||
const boundaries = { minimum: contextEntry.startTime, maximum: contextEntry.endTime };
|
||||
|
||||
|
||||
@ -121,7 +121,7 @@ export const Workbench: React.FunctionComponent<{
|
||||
</div>
|
||||
<SplitView sidebarSize={300} orientation='horizontal' sidebarIsFirst={true}>
|
||||
<SplitView sidebarSize={300} orientation='horizontal'>
|
||||
<SnapshotTab action={selectedAction} defaultSnapshotSize={defaultSnapshotSize} />
|
||||
<SnapshotTab action={selectedAction} defaultSnapshotInfo={defaultSnapshotInfo} />
|
||||
<TabbedPane tabs={tabs} selectedTab={selectedTab} setSelectedTab={setSelectedTab}/>
|
||||
</SplitView>
|
||||
<ActionList
|
||||
|
@ -278,7 +278,16 @@ test('should have network requests', async ({ showTraceViewer }) => {
|
||||
]);
|
||||
});
|
||||
|
||||
test('should capture iframe', async ({ page, server, browserName, runAndTrace }) => {
|
||||
test('should show snapshot URL', async ({ page, runAndTrace, server }) => {
|
||||
const traceViewer = await runAndTrace(async () => {
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
await page.evaluate('2+2');
|
||||
});
|
||||
await traceViewer.snapshotFrame('page.evaluate');
|
||||
await expect(traceViewer.page.locator('.snapshot-url')).toHaveText(server.EMPTY_PAGE);
|
||||
});
|
||||
|
||||
test('should capture iframe', async ({ page, server, runAndTrace }) => {
|
||||
await page.route('**/empty.html', route => {
|
||||
route.fulfill({
|
||||
body: '<iframe src="iframe.html"></iframe>',
|
||||
|
Loading…
Reference in New Issue
Block a user