mirror of
https://github.com/microsoft/playwright.git
synced 2025-06-26 21:40:17 +00:00
fix(trace-viewer): multiple iframe and UX fixes (#10486)
This commit is contained in:
parent
5a8010cf4f
commit
206a877cea
@ -265,6 +265,12 @@ export function frameSnapshotStreamer(snapshotStreamer: string) {
|
||||
return;
|
||||
if (nodeName === 'SCRIPT')
|
||||
return;
|
||||
// Don't preload resources.
|
||||
if (nodeName === 'LINK' && nodeType === Node.ELEMENT_NODE) {
|
||||
const rel = (node as Element).getAttribute('rel')?.toLowerCase();
|
||||
if (rel === 'preload' || rel === 'prefetch')
|
||||
return;
|
||||
}
|
||||
if (this._removeNoScript && nodeName === 'NOSCRIPT')
|
||||
return;
|
||||
if (nodeName === 'META' && (node as HTMLMetaElement).httpEquiv.toLowerCase() === 'content-security-policy')
|
||||
|
||||
@ -59,8 +59,12 @@ export class SnapshotRenderer {
|
||||
// Element node.
|
||||
const builder: string[] = [];
|
||||
builder.push('<', n[0]);
|
||||
for (const [attr, value] of Object.entries(n[1] || {}))
|
||||
builder.push(' ', attr, '="', escapeAttribute(value as string), '"');
|
||||
// Never set relative URLs as <iframe src> - they start fetching frames immediately.
|
||||
const isFrame = n[0] === 'IFRAME' || n[0] === 'FRAME';
|
||||
for (const [attr, value] of Object.entries(n[1] || {})) {
|
||||
const attrToSet = isFrame && attr.toLowerCase() === 'src' ? '__playwright_src__' : attr;
|
||||
builder.push(' ', attrToSet, '="', escapeAttribute(value as string), '"');
|
||||
}
|
||||
builder.push('>');
|
||||
for (let i = 2; i < n.length; i++)
|
||||
builder.push(visit(n[i], snapshotIndex));
|
||||
@ -181,14 +185,19 @@ function snapshotScript() {
|
||||
scrollLefts.push(e);
|
||||
|
||||
for (const iframe of root.querySelectorAll('iframe')) {
|
||||
const src = iframe.getAttribute('src');
|
||||
const src = iframe.getAttribute('__playwright_src__');
|
||||
if (!src) {
|
||||
iframe.setAttribute('src', 'data:text/html,<body style="background: #ddd"></body>');
|
||||
} else {
|
||||
// Append query parameters to inherit ?name= or ?time= values from parent.
|
||||
const url = new URL('/trace' + src + window.location.search, window.location.href);
|
||||
const url = new URL(window.location.href);
|
||||
url.searchParams.delete('pointX');
|
||||
url.searchParams.delete('pointY');
|
||||
// We can be loading iframe from within iframe, reset base to be absolute.
|
||||
const index = url.pathname.lastIndexOf('/snapshot/');
|
||||
if (index !== -1)
|
||||
url.pathname = url.pathname.substring(0, index + 1);
|
||||
url.pathname += src.substring(1);
|
||||
iframe.setAttribute('src', url.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@ -88,7 +88,9 @@ export class SnapshotServer {
|
||||
headers.delete('Content-Length');
|
||||
headers.set('Content-Length', String(content.size));
|
||||
headers.set('Cache-Control', 'public, max-age=31536000');
|
||||
return new Response(content, {
|
||||
const { status } = resource.response;
|
||||
const isNullBodyStatus = status === 101 || status === 204 || status === 205 || status === 304;
|
||||
return new Response(isNullBodyStatus ? null : content, {
|
||||
headers,
|
||||
status: resource.response.status,
|
||||
statusText: resource.response.statusText,
|
||||
|
||||
@ -70,9 +70,11 @@
|
||||
padding: 4px;
|
||||
border-radius: 3px;
|
||||
height: 28px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
display: block;
|
||||
flex: none;
|
||||
}
|
||||
|
||||
.snapshot-container {
|
||||
|
||||
@ -14,7 +14,6 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Size } from '../geometry';
|
||||
import './snapshotTab.css';
|
||||
import './tabbedPane.css';
|
||||
import * as React from 'react';
|
||||
@ -23,8 +22,7 @@ import { ActionTraceEvent } from '../../../server/trace/common/traceEvents';
|
||||
|
||||
export const SnapshotTab: React.FunctionComponent<{
|
||||
action: ActionTraceEvent | undefined,
|
||||
defaultSnapshotInfo: { viewport: Size, url: string },
|
||||
}> = ({ action, defaultSnapshotInfo }) => {
|
||||
}> = ({ action }) => {
|
||||
const [measure, ref] = useMeasure<HTMLDivElement>();
|
||||
const [snapshotIndex, setSnapshotIndex] = React.useState(0);
|
||||
|
||||
@ -57,7 +55,7 @@ export const SnapshotTab: React.FunctionComponent<{
|
||||
}, [snapshotIndex, snapshots]);
|
||||
|
||||
const iframeRef = React.useRef<HTMLIFrameElement>(null);
|
||||
const [snapshotInfo, setSnapshotInfo] = React.useState(defaultSnapshotInfo);
|
||||
const [snapshotInfo, setSnapshotInfo] = React.useState({ viewport: kDefaultViewport, url: '' });
|
||||
React.useEffect(() => {
|
||||
(async () => {
|
||||
if (snapshotInfoUrl) {
|
||||
@ -66,8 +64,7 @@ export const SnapshotTab: React.FunctionComponent<{
|
||||
if (!info.error)
|
||||
setSnapshotInfo(info);
|
||||
} else {
|
||||
// Reset to default if snapshotInfoUrl was removed
|
||||
setSnapshotInfo(defaultSnapshotInfo);
|
||||
setSnapshotInfo({ viewport: kDefaultViewport, url: '' });
|
||||
}
|
||||
if (!iframeRef.current)
|
||||
return;
|
||||
@ -76,7 +73,7 @@ export const SnapshotTab: React.FunctionComponent<{
|
||||
} catch (e) {
|
||||
}
|
||||
})();
|
||||
}, [iframeRef, snapshotUrl, snapshotInfoUrl, pointX, pointY, defaultSnapshotInfo]);
|
||||
}, [iframeRef, snapshotUrl, snapshotInfoUrl, pointX, pointY]);
|
||||
|
||||
const snapshotSize = snapshotInfo.viewport;
|
||||
const scale = Math.min(measure.width / snapshotSize.width, measure.height / snapshotSize.height, 1);
|
||||
@ -124,3 +121,5 @@ function renderTitle(snapshotTitle: string): string {
|
||||
return 'Action';
|
||||
return snapshotTitle;
|
||||
}
|
||||
|
||||
const kDefaultViewport = { width: 1280, height: 720 };
|
||||
|
||||
@ -115,7 +115,6 @@ export const Workbench: React.FunctionComponent<{
|
||||
})();
|
||||
}, [traceURL, uploadedTraceName]);
|
||||
|
||||
const defaultSnapshotInfo = { viewport: contextEntry.options.viewport || { width: 1280, height: 720 }, url: '' };
|
||||
const boundaries = { minimum: contextEntry.startTime, maximum: contextEntry.endTime };
|
||||
|
||||
|
||||
@ -153,7 +152,7 @@ export const Workbench: React.FunctionComponent<{
|
||||
</div>
|
||||
<SplitView sidebarSize={300} orientation='horizontal' sidebarIsFirst={true}>
|
||||
<SplitView sidebarSize={300} orientation='horizontal'>
|
||||
<SnapshotTab action={selectedAction} defaultSnapshotInfo={defaultSnapshotInfo} />
|
||||
<SnapshotTab action={selectedAction} />
|
||||
<TabbedPane tabs={tabs} selectedTab={selectedPropertiesTab} setSelectedTab={setSelectedPropertiesTab}/>
|
||||
</SplitView>
|
||||
<TabbedPane tabs={
|
||||
|
||||
@ -142,7 +142,7 @@ it.describe('snapshots', () => {
|
||||
for (; ; ++counter) {
|
||||
snapshot = await snapshotter.captureSnapshot(toImpl(page), 'snapshot' + counter);
|
||||
const text = distillSnapshot(snapshot).replace(/frame@[^"]+["]/, '<id>"');
|
||||
if (text === '<IFRAME src=\"/snapshot/<id>\"></IFRAME>')
|
||||
if (text === '<IFRAME __playwright_src__=\"/snapshot/<id>\"></IFRAME>')
|
||||
break;
|
||||
await page.waitForTimeout(250);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user