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
Implementation Analysis
Technical Details
Best Practices Demonstrated
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);
});
});