Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/firefox/snapshot/injected/elementCollector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export function isVisible(el: Element): boolean {
} catch {
return false;
}
current = current.parentElement;
current = current.parentElement ?? (current.getRootNode() as ShadowRoot).host ?? null;
}

return true;
Expand Down
5 changes: 3 additions & 2 deletions src/firefox/snapshot/injected/treeWalker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,13 +115,14 @@ export function walkTree(
}
} else {
// Walk regular children
for (let i = 0; i < el.children.length; i++) {
const children = el.shadowRoot ? [...el.shadowRoot.children, ...el.children] : el.children;
for (let i = 0; i < children.length; i++) {
if (nodeCount >= MAX_NODES) {
truncated = true;
break;
}

const child = el.children[i];
const child = children[i];
if (!child) {
continue;
}
Expand Down
42 changes: 42 additions & 0 deletions tests/integration/firefox/snapshot.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -233,4 +233,46 @@ describe('Snapshot Integration Tests', () => {

expect(hasInvisibleButton).toBe(false);
}, 10000);

describe('shadow DOM', () => {
const SHADOW_PAGE =
'data:text/html,<x-box id=open></x-box><x-box id=hidden style="display:none"></x-box>' +
'<output id=out></output><script>customElements.define("x-box", class extends HTMLElement {' +
' connectedCallback() { const root = this.attachShadow({ mode: "open" });' +
' root.innerHTML = "<input id=deep><button id=deepBtn>Deep</button>";' +
' root.getElementById("deepBtn").onclick = () =>' +
' { out.textContent = this.id + ":" + root.getElementById("deep").value; }; } });</script>';

function shadowNode(snapshot: { json: { root: SnapshotNode } }, id: string) {
return findNodeInSnapshot(snapshot.json.root, (node) => node.id === id);
}

it('should include the elements of an open shadow root', async () => {
await firefox.navigate(SHADOW_PAGE);

const snapshot = await firefox.takeSnapshot();

expect(shadowNode(snapshot, 'deepBtn')?.name).toBe('Deep');
}, 10000);

it('should let shadow DOM elements be filled and clicked by UID', async () => {
await firefox.navigate(SHADOW_PAGE);
const snapshot = await firefox.takeSnapshot();

await firefox.fillByUid(shadowNode(snapshot, 'deep')!.uid, 'abc');
await firefox.clickByUid(shadowNode(snapshot, 'deepBtn')!.uid);

expect(await firefox.evaluate('document.getElementById("out").textContent')).toBe('open:abc');
}, 10000);

it('should leave out the shadow root of a hidden host', async () => {
await firefox.navigate(SHADOW_PAGE);

const snapshot = await firefox.takeSnapshot({ includeAll: true });

expect(findNodesInSnapshot(snapshot.json.root, (node) => node.id === 'deepBtn')).toHaveLength(
1
);
}, 10000);
});
});