fix(tracing): workaround chromium scrollTop slowness (#14114)

References #14037.

We used to query and save all non-zero `scrollTop`/`scrollLeft` to restore the page perfectly. However, this became very slow with Chromium v100 regression (see issue).

This change only queries and stores `scrollTop`/`scrollLeft` for elements that are ancestors of the action target. The resulting snapshot does not perfectly recreate the original screen, but should be good enough to inspect the action.
This commit is contained in:
Dmitry Gozman 2022-05-12 18:55:29 +01:00 committed by GitHub
parent 0e2855348c
commit f6712ec43a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -44,6 +44,7 @@ export function frameSnapshotStreamer(snapshotStreamer: string) {
const kScrollTopAttribute = '__playwright_scroll_top_';
const kScrollLeftAttribute = '__playwright_scroll_left_';
const kStyleSheetAttribute = '__playwright_style_sheet_';
const kTargetAttribute = '__playwright_target__';
// Symbols for our own info on Nodes/StyleSheets.
const kSnapshotFrameId = Symbol('__playwright_snapshot_frameid_');
@ -273,6 +274,28 @@ export function frameSnapshotStreamer(snapshotStreamer: string) {
// Ensure we are up to date.
this._handleMutations(this._observer.takeRecords());
// Restore scroll positions for all ancestors of action target elements
// that will show the highlight/red dot in the trace viewer.
// Workaround for chromium regression:
// https://bugs.chromium.org/p/chromium/issues/detail?id=1324419
// https://github.com/microsoft/playwright/issues/14037
// TODO: remove after chromium is fixed?
const elementsToRestoreScrollPosition = new Set<Node>();
const findElementsToRestoreScrollPositionRecursively = (element: Element) => {
let shouldAdd = element.hasAttribute(kTargetAttribute);
for (let child = element.firstElementChild; child; child = child.nextElementSibling)
shouldAdd = shouldAdd || findElementsToRestoreScrollPositionRecursively(child);
if (element.shadowRoot) {
for (let child = element.shadowRoot.firstElementChild; child; child = child.nextElementSibling)
shouldAdd = shouldAdd || findElementsToRestoreScrollPositionRecursively(child);
}
if (shouldAdd)
elementsToRestoreScrollPosition.add(element);
return shouldAdd;
};
if (document.documentElement)
findElementsToRestoreScrollPositionRecursively(document.documentElement);
const visitNode = (node: Node | ShadowRoot): { equals: boolean, n: NodeSnapshot } | undefined => {
const nodeType = node.nodeType;
const nodeName = nodeType === Node.DOCUMENT_FRAGMENT_NODE ? 'template' : node.nodeName;
@ -380,12 +403,12 @@ export function frameSnapshotStreamer(snapshotStreamer: string) {
expectValue(value);
attrs[kSelectedAttribute] = value;
}
if (element.scrollTop) {
if (elementsToRestoreScrollPosition.has(element) && element.scrollTop) {
expectValue(kScrollTopAttribute);
expectValue(element.scrollTop);
attrs[kScrollTopAttribute] = '' + element.scrollTop;
}
if (element.scrollLeft) {
if (elementsToRestoreScrollPosition.has(element) && element.scrollLeft) {
expectValue(kScrollLeftAttribute);
expectValue(element.scrollLeft);
attrs[kScrollLeftAttribute] = '' + element.scrollLeft;