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

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

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