Skip to content

Fix Node.contains ancestor traversal - #688

Open
olavoasantos wants to merge 1 commit into
mainfrom
fix-node-contains
Open

olavoasantos wants to merge 1 commit into
mainfrom
fix-node-contains

Conversation

@olavoasantos

@olavoasantos olavoasantos commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Problem

Node.contains() is supposed to walk from the candidate node toward the root until it finds the receiver. The previous loop repeatedly read the original candidate’s parent instead of advancing from the current node, so it stopped making progress after the first hop.

As a result, checks such as parent.contains(grandchild) and checks against a node in another attached subtree never returned.

Impact

Critical. This is a synchronous infinite loop. Because the polyfill is intended for non-browser environments such as Web Workers, one affected contains() call can block that worker’s event loop indefinitely instead of returning a boolean.

Reproduction

const parent = document.createElement('div');
const child = document.createElement('span');
const grandchild = document.createElement('em');

parent.appendChild(child);
child.appendChild(grandchild);

parent.contains(grandchild);

Before this change, the final call never returned. It now returns true. The equivalent check against a node in another subtree now terminates and returns false.

Change

Advance through currentNode.parentNode on each iteration and return false after reaching the root. This preserves the expected results for the receiver itself and direct children while allowing deeper and unrelated-node checks to terminate.

Tests

Regression coverage verifies the receiver itself, a direct child, a deep descendant, a node in another subtree, a detached node, and null. The deep-descendant and other-subtree cases exercise the paths that previously hung.

Stack

  • Stack: Independent quick wins (#702), layer 1 of 4
  • Base: main
  • This is the bottom of its stack.

Coverage includes both the explicit detached-node case and a node attached to another subtree.

Validation

Fresh GitHub CI on restacked head 3c57e5b passes:

  • lint;
  • type-check and build;
  • unit tests with coverage;
  • bundle-size checks;
  • Playwright end-to-end tests;
  • the classified Web Platform Test suite.

@olavoasantos
olavoasantos changed the base branch from parse-closing-tags-and-svg to main September 3, 2026 15:30

@henrytao-me henrytao-me left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants