fix(trace viewer): prefer latest resource with the same url (#23763)

When rendering snapshot, disregard earlier resources with the same url,
because it's most likely that the latest one was used for rendering.

An example would be reloading the page before the stylesheet has
finished loading. In this case, the stylesheet will be requested twice,
and the second copy that was not aborted should be used for the
snapshot.

Fixes #23709.
This commit is contained in:
Dmitry Gozman 2023-06-17 06:58:16 -07:00 committed by GitHub
parent f6d86c20f3
commit 132a5a4bf5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 42 additions and 3 deletions

View File

@ -123,8 +123,9 @@ export class SnapshotRenderer {
if (resource._frameref !== snapshot.frameId)
continue;
if (resource.request.url === url) {
// Pick the last resource with matching url - most likely it was used
// at the time of snapshot, not the earlier aborted resource with the same url.
result = resource;
break;
}
}
@ -133,8 +134,11 @@ export class SnapshotRenderer {
for (const resource of this._resources) {
if (typeof resource._monotonicTime === 'number' && resource._monotonicTime >= snapshot.timestamp)
break;
if (resource.request.url === url)
return resource;
if (resource.request.url === url) {
// Pick the last resource with matching url - most likely it was used
// at the time of snapshot, not the earlier aborted resource with the same url.
result = resource;
}
}
}

View File

@ -850,3 +850,38 @@ test('should open trace-1.31', async ({ showTraceViewer }) => {
const snapshot = await traceViewer.snapshotFrame('locator.click');
await expect(snapshot.locator('[__playwright_target__]')).toHaveText(['Submit']);
});
test('should prefer later resource request', async ({ page, server, runAndTrace }) => {
const html = `
<body>
<script>
const link = document.createElement('link');
link.rel = 'stylesheet';
link.href = 'style.css';
document.head.appendChild(link);
if (!window.location.href.includes('reloaded'))
window.location.href = window.location.href + '?reloaded';
</script>
</body>
`;
let reloadStartedCallback = () => {};
const reloadStartedPromise = new Promise<void>(f => reloadStartedCallback = f);
server.setRoute('/style.css', async (req, res) => {
// Make sure reload happens before style arrives.
await reloadStartedPromise;
res.end('body { background-color: rgb(123, 123, 123) }');
});
server.setRoute('/index.html', (req, res) => res.end(html));
server.setRoute('/index.html?reloaded', (req, res) => {
reloadStartedCallback();
res.end(html);
});
const traceViewer = await runAndTrace(async () => {
await page.goto(server.PREFIX + '/index.html');
});
const frame = await traceViewer.snapshotFrame('page.goto');
await expect(frame.locator('body')).toHaveCSS('background-color', 'rgb(123, 123, 123)');
});