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 коммит произвёл GitHub
Родитель f6d86c20f3
Коммит 132a5a4bf5
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
2 изменённых файлов: 42 добавлений и 3 удалений

Просмотреть файл

@ -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;
}
}
}

Просмотреть файл

@ -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)');
});