Skip to content

Commit

Permalink
cherry-pick(release-1.12): account for last child node removal (#7335)
Browse files Browse the repository at this point in the history
PR #7332 SHA 02538fb

Co-authored-by: Pavel Feldman <pavel.feldman@gmail.com>
  • Loading branch information
aslushnikov and pavelfeldman authored Jun 26, 2021
1 parent c25e00b commit 81d4b43
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 8 deletions.
18 changes: 10 additions & 8 deletions src/server/snapshot/snapshotterInjected.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export function frameSnapshotStreamer(snapshotStreamer: string) {
// Symbols for our own info on Nodes/StyleSheets.
const kSnapshotFrameId = Symbol('__playwright_snapshot_frameid_');
const kCachedData = Symbol('__playwright_snapshot_cache_');
const kEndOfList = Symbol('__playwright_end_of_list_');
type CachedData = {
cached?: any[], // Cached values to determine whether the snapshot will be the same.
ref?: [number, number], // Previous snapshotNumber and nodeIndex.
Expand Down Expand Up @@ -355,6 +356,7 @@ export function frameSnapshotStreamer(snapshotStreamer: string) {
}
for (let child = node.firstChild; child; child = child.nextSibling)
visitChild(child);
expectValue(kEndOfList);
let documentOrShadowRoot = null;
if (node.ownerDocument!.documentElement === node)
documentOrShadowRoot = node.ownerDocument;
Expand All @@ -363,20 +365,19 @@ export function frameSnapshotStreamer(snapshotStreamer: string) {
if (documentOrShadowRoot) {
for (const sheet of (documentOrShadowRoot as any).adoptedStyleSheets || [])
visitChildStyleSheet(sheet);
expectValue(kEndOfList);
}
}

// Process iframe src attribute before bailing out since it depends on a symbol, not the DOM.
if (nodeName === 'IFRAME' || nodeName === 'FRAME') {
const element = node as Element;
for (let i = 0; i < element.attributes.length; i++) {
const frameId = (element as any)[kSnapshotFrameId];
const name = 'src';
const value = frameId ? `/snapshot/${frameId}` : '';
expectValue(name);
expectValue(value);
attrs[name] = value;
}
const frameId = (element as any)[kSnapshotFrameId];
const name = 'src';
const value = frameId ? `/snapshot/${frameId}` : '';
expectValue(name);
expectValue(value);
attrs[name] = value;
}

// We can skip attributes comparison because nothing else has changed,
Expand Down Expand Up @@ -409,6 +410,7 @@ export function frameSnapshotStreamer(snapshotStreamer: string) {
expectValue(value);
attrs[name] = value;
}
expectValue(kEndOfList);
}

if (result.length === 2 && !Object.keys(attrs).length)
Expand Down
20 changes: 20 additions & 0 deletions tests/snapshotter.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,26 @@ it.describe('snapshots', () => {
expect(distillSnapshot(snapshot2)).toBe('<style>button { color: blue; }</style><BUTTON>Hello</BUTTON>');
});

it('should respect node removal', async ({ page, toImpl, snapshotter }) => {
page.on('console', console.log);
await page.setContent('<div><button id="button1"></button><button id="button2"></button></div>');
const snapshot1 = await snapshotter.captureSnapshot(toImpl(page), 'snapshot1');
expect(distillSnapshot(snapshot1)).toBe('<DIV><BUTTON id=\"button1\"></BUTTON><BUTTON id=\"button2\"></BUTTON></DIV>');
await page.evaluate(() => document.getElementById('button2').remove());
const snapshot2 = await snapshotter.captureSnapshot(toImpl(page), 'snapshot2');
expect(distillSnapshot(snapshot2)).toBe('<DIV><BUTTON id=\"button1\"></BUTTON></DIV>');
});

it('should respect attr removal', async ({ page, toImpl, snapshotter }) => {
page.on('console', console.log);
await page.setContent('<div id="div" attr1="1" attr2="2"></div>');
const snapshot1 = await snapshotter.captureSnapshot(toImpl(page), 'snapshot1');
expect(distillSnapshot(snapshot1)).toBe('<DIV id=\"div\" attr1=\"1\" attr2=\"2\"></DIV>');
await page.evaluate(() => document.getElementById('div').removeAttribute('attr2'));
const snapshot2 = await snapshotter.captureSnapshot(toImpl(page), 'snapshot2');
expect(distillSnapshot(snapshot2)).toBe('<DIV id=\"div\" attr1=\"1\"></DIV>');
});

it('should have a custom doctype', async ({page, server, toImpl, snapshotter}) => {
await page.goto(server.EMPTY_PAGE);
await page.setContent('<!DOCTYPE foo><body>hi</body>');
Expand Down

0 comments on commit 81d4b43

Please sign in to comment.