Back to Repositories

Testing DOM Sibling Detection Implementation in Preact

This test suite thoroughly examines the getDomSibling functionality in Preact, focusing on DOM node relationship traversal and sibling detection. The tests verify how the function handles different component structures, Fragment usage, and edge cases in the virtual DOM hierarchy.

Test Coverage Overview

The test suite provides comprehensive coverage of getDomSibling functionality across various DOM scenarios:

  • Direct sibling detection for both element and text nodes
  • Nested Fragment handling
  • Placeholder and null value handling
  • Complex component hierarchies
  • Edge cases with empty trees and last siblings

Implementation Analysis

The testing approach utilizes Jest’s describe/it pattern with systematic validation of DOM node relationships. Tests employ a combination of component rendering, Fragment nesting, and virtual DOM traversal to verify sibling detection accuracy.

Key patterns include setup/teardown hooks, virtual DOM inspection, and node equality assertions.

Technical Details

Testing infrastructure includes:

  • Jest test framework
  • Custom scratch element setup/teardown helpers
  • Virtual DOM traversal utilities
  • JSX transformation with createElement
  • Component rendering validation

Best Practices Demonstrated

The test suite exemplifies high-quality testing practices:

  • Isolated test cases with clear descriptions
  • Comprehensive edge case coverage
  • Consistent setup/teardown patterns
  • Structured test organization
  • Clear assertion patterns

preactjs/preact

test/browser/getDomSibling.test.js

            
import { createElement, render, Fragment } from '../../src/';
import { getDomSibling } from '../../src/component';
import { setupScratch, teardown } from '../_util/helpers';

/** @jsx createElement */

describe('getDomSibling', () => {
	/** @type {HTMLDivElement} */
	let scratch;

	const getRoot = dom => dom._children;

	beforeEach(() => {
		scratch = setupScratch();
	});

	afterEach(() => {
		teardown(scratch);
	});

	it('should find direct sibling', () => {
		render(
			<div>
				<div>A</div>
				<div>B</div>
			</div>,
			scratch
		);
		let vnode = getRoot(scratch)._children[0]._children[0];
		expect(getDomSibling(vnode)).to.equalNode(scratch.firstChild.childNodes[1]);
	});

	it('should find direct text node sibling', () => {
		render(
			<div>
				<div>A</div>B
			</div>,
			scratch
		);
		let vnode = getRoot(scratch)._children[0]._children[0];
		expect(getDomSibling(vnode)).to.equalNode(scratch.firstChild.childNodes[1]);
	});

	it('should find nested text node sibling', () => {
		render(
			<div>
				<Fragment>
					<div>A</div>
				</Fragment>
				<Fragment>B</Fragment>
			</div>,
			scratch
		);
		let vnode = getRoot(scratch)._children[0]._children[0];
		expect(getDomSibling(vnode)).to.equalNode(scratch.firstChild.childNodes[1]);
	});

	it('should find text node sibling with placeholder', () => {
		render(<div>A{null}B</div>, scratch);
		let vnode = getRoot(scratch)._children[0]._children[0];
		expect(getDomSibling(vnode)).to.equalNode(scratch.firstChild.childNodes[1]);
	});

	it('should find sibling with placeholder', () => {
		render(
			<div key="parent">
				<div key="A">A</div>
				{null}
				<div key="B">B</div>
			</div>,
			scratch
		);
		let vnode = getRoot(scratch)._children[0]._children[0];
		expect(getDomSibling(vnode)).to.equalNode(scratch.firstChild.childNodes[1]);
	});

	it('should find sibling with nested placeholder', () => {
		render(
			<div key="0">
				<Fragment key="0.0">
					<div key="A">A</div>
				</Fragment>
				<Fragment key="0.1">{null}</Fragment>
				<Fragment key="0.2">
					<div key="B">B</div>
				</Fragment>
			</div>,
			scratch
		);
		let vnode = getRoot(scratch)._children[0]._children[0]._children[0];
		expect(getDomSibling(vnode)).to.equalNode(scratch.firstChild.childNodes[1]);
	});

	it('should find sibling in parent', () => {
		render(
			<div>
				<Fragment>
					<div>A</div>
				</Fragment>
				<div>B</div>
			</div>,
			scratch
		);
		let vnode = getRoot(scratch)._children[0]._children[0]._children[0];
		expect(getDomSibling(vnode)).to.equalNode(scratch.firstChild.childNodes[1]);
	});

	it('should find unrelated sibling from a DOM VNode', () => {
		render(
			<div key="0">
				<Fragment key="0.0">
					<Fragment key="0.0.0">
						<Fragment key="0.0.0.0">
							<div key="A">A</div>
						</Fragment>
					</Fragment>
				</Fragment>
				<Fragment key="0.1">
					<Fragment key="0.1.0" />
					<Fragment key="0.1.1" />
					<Fragment key="0.1.2" />
				</Fragment>
				<Fragment key="0.2">
					<Fragment key="0.2.0" />
					<Fragment key="0.2.1" />
					<Fragment key="0.2.2">
						<div key="B">B</div>
					</Fragment>
				</Fragment>
			</div>,
			scratch
		);

		let divAVNode =
			getRoot(scratch)._children[0]._children[0]._children[0]._children[0]
				._children[0];
		expect(divAVNode.type).to.equal('div');
		expect(getDomSibling(divAVNode)).to.equalNode(
			scratch.firstChild.childNodes[1]
		);
	});

	it('should find unrelated sibling from a Fragment VNode', () => {
		render(
			<div key="0">
				<Fragment key="0.0">
					<Fragment key="0.0.0">
						<Fragment key="0.0.0.0">
							<div key="A">A</div>
						</Fragment>
					</Fragment>
				</Fragment>
				<Fragment key="0.1">
					<Fragment key="0.1.0">
						<div key="B">B</div>
					</Fragment>
				</Fragment>
			</div>,
			scratch
		);

		let fragment =
			getRoot(scratch)._children[0]._children[0]._children[0]._children[0];
		expect(fragment.type).to.equal(Fragment);
		expect(getDomSibling(fragment)).to.equalNode(
			scratch.firstChild.childNodes[1]
		);
	});

	it('should find unrelated sibling from a Component VNode', () => {
		const Foo = props => props.children;
		render(
			<div key="0">
				<Fragment key="0.0">
					<Fragment key="0.0.0">
						<Foo key="0.0.0.0">
							<div key="A">A</div>
						</Foo>
					</Fragment>
				</Fragment>
				<Fragment key="0.1">
					<Fragment key="0.1.0">
						<div key="B">B</div>
					</Fragment>
				</Fragment>
			</div>,
			scratch
		);

		let foo =
			getRoot(scratch)._children[0]._children[0]._children[0]._children[0];
		expect(foo.type).to.equal(Foo);
		expect(getDomSibling(foo)).to.equalNode(scratch.firstChild.childNodes[1]);
	});

	it('should find sibling through components', () => {
		const Foo = props => props.children;
		render(
			<div key="0">
				<Foo key="0.0">
					<div key="A">A</div>
				</Foo>
				<Foo key="0.1" />
				<Foo key="0.2">
					<Foo key="0.2.0">
						<div key="B">B</div>
					</Foo>
				</Foo>
			</div>,
			scratch
		);

		let divAVNode = getRoot(scratch)._children[0]._children[0]._children[0];
		expect(divAVNode.type).to.equal('div');
		expect(getDomSibling(divAVNode)).to.equalNode(
			scratch.firstChild.childNodes[1]
		);
	});

	it('should find sibling rendered in Components that wrap JSX children', () => {
		const Foo = props => <p key="p">{props.children}</p>;
		render(
			<div key="0">
				<div key="A">A</div>
				<Foo key="Foo">
					<span key="span">a span</span>
				</Foo>
			</div>,
			scratch
		);

		let divAVNode = getRoot(scratch)._children[0]._children[0];
		expect(divAVNode.type).to.equal('div');

		let sibling = getDomSibling(divAVNode);
		expect(sibling).to.equalNode(scratch.firstChild.childNodes[1]);
	});

	it('should find sibling rendered in Components without JSX children', () => {
		const Foo = props => <p key="p">A paragraph</p>;
		render(
			<div key="0">
				<div key="A">A</div>
				<Foo key="Foo" />
			</div>,
			scratch
		);

		let divAVNode = getRoot(scratch)._children[0]._children[0];
		expect(divAVNode.type).to.equal('div');

		let sibling = getDomSibling(divAVNode);
		expect(sibling).to.equalNode(scratch.firstChild.childNodes[1]);
	});

	it('should climb through Components without JSX children', () => {
		const divAVNode = <div key="A">A</div>;
		const Foo = () => divAVNode;

		render(
			<div key="0">
				<Foo key="Foo" />
				<div key="B">B</div>
			</div>,
			scratch
		);

		let sibling = getDomSibling(divAVNode);
		expect(sibling).to.equalNode(scratch.firstChild.childNodes[1]);
	});

	it('should return null if last sibling', () => {
		render(
			<div key="0">
				<Fragment key="0.0">
					<div key="A">A</div>
				</Fragment>
				<Fragment key="0.1">
					<div key="B">B</div>
				</Fragment>
				<Fragment key="0.2">
					<div key="C">C</div>
				</Fragment>
			</div>,
			scratch
		);

		const divCVNode = getRoot(scratch)._children[0]._children[2]._children[0];
		expect(getDomSibling(divCVNode)).to.equal(null);
	});

	it('should return null if no sibling', () => {
		render(
			<div key="0">
				<Fragment key="0.0">
					<Fragment key="0.0.0">
						<Fragment key="0.0.0.0">
							<div key="A">A</div>
						</Fragment>
					</Fragment>
				</Fragment>
				<Fragment key="0.1">
					<Fragment key="0.1.0">{null}</Fragment>
				</Fragment>
			</div>,
			scratch
		);

		let divAVNode =
			getRoot(scratch)._children[0]._children[0]._children[0]._children[0]
				._children[0];
		expect(getDomSibling(divAVNode)).to.equal(null);
	});

	it('should return null if no sibling with lots of empty trees', () => {
		render(
			<div key="0">
				<Fragment key="0.0">
					<Fragment key="0.0.0">
						<Fragment key="0.0.0.0">
							<div key="A">A</div>
						</Fragment>
					</Fragment>
				</Fragment>
				<Fragment key="0.1">
					<Fragment key="0.1.0" />
					<Fragment key="0.1.1" />
					<Fragment key="0.1.2" />
				</Fragment>
				<Fragment key="0.2">
					<Fragment key="0.2.0" />
					<Fragment key="0.2.1" />
					<Fragment key="0.2.2">{null}</Fragment>
				</Fragment>
			</div>,
			scratch
		);

		let divAVNode =
			getRoot(scratch)._children[0]._children[0]._children[0]._children[0]
				._children[0];
		expect(getDomSibling(divAVNode)).to.equal(null);
	});

	it('should return null if current parent has no siblings (even if parent has siblings at same level)', () => {
		let divAVNode = <div key="A">A</div>;

		render(
			<div key="0">
				<div key="0.0">
					<div key="0.0.0" />
					{divAVNode}
					<Fragment key="0.1.2" />
				</div>
				<div key="0.1">
					<Fragment key="0.1.0" />
					<div key="B">B</div>
				</div>
			</div>,
			scratch
		);

		expect(getDomSibling(divAVNode)).to.equal(null);
	});
});