Testing cloneElement Implementation in Preact Compatibility Layer
This test suite validates the cloneElement functionality in Preact’s compatibility layer, ensuring proper element cloning and children handling in React-compatible scenarios.
Test Coverage Overview
Implementation Analysis
Technical Details
Best Practices Demonstrated
preactjs/preact
compat/test/browser/cloneElement.test.js
import { createElement as preactH } from 'preact';
import React, { createElement, render, cloneElement } from 'preact/compat';
import { setupScratch, teardown } from '../../../test/_util/helpers';
describe('compat cloneElement', () => {
/** @type {HTMLDivElement} */
let scratch;
beforeEach(() => {
scratch = setupScratch();
});
afterEach(() => {
teardown(scratch);
});
it('should clone elements', () => {
let element = (
<foo a="b" c="d">
a<span>b</span>
</foo>
);
const clone = cloneElement(element);
delete clone._original;
delete element._original;
expect(clone).to.eql(element);
});
it('should support props.children', () => {
let element = <foo children={<span>b</span>} />;
let clone = cloneElement(element);
delete clone._original;
delete element._original;
expect(clone).to.eql(element);
expect(cloneElement(clone).props.children).to.eql(element.props.children);
});
it('children take precedence over props.children', () => {
let element = (
<foo children={<span>c</span>}>
<div>b</div>
</foo>
);
let clone = cloneElement(element);
delete clone._original;
delete element._original;
expect(clone).to.eql(element);
expect(clone.props.children.type).to.eql('div');
});
it('should support children in prop argument', () => {
let element = <foo />;
let children = [<span>b</span>];
let clone = cloneElement(element, { children });
expect(clone.props.children).to.eql(children);
});
it('single child argument takes precedence over props.children', () => {
let element = <foo />;
let childrenA = [<span>b</span>];
let childrenB = [<div>c</div>];
let clone = cloneElement(element, { children: childrenA }, ...childrenB);
expect(clone.props.children).to.eql(childrenB[0]);
});
it('multiple children arguments take precedence over props.children', () => {
let element = <foo />;
let childrenA = [<span>b</span>];
let childrenB = [<div>c</div>, 'd'];
let clone = cloneElement(element, { children: childrenA }, ...childrenB);
expect(clone.props.children).to.eql(childrenB);
});
it('children argument takes precedence over props.children even if falsey', () => {
let element = <foo />;
let childrenA = [<span>b</span>];
let clone = cloneElement(element, { children: childrenA }, undefined);
expect(clone.children).to.eql(undefined);
});
it('should skip cloning on invalid element', () => {
let element = { foo: 42 };
// @ts-expect-error
let clone = cloneElement(element);
expect(clone).to.eql(element);
});
it('should work with jsx constructor from core', () => {
function Foo(props) {
return <div>{props.value}</div>;
}
let clone = cloneElement(preactH(Foo, {}), { value: 'foo' });
render(clone, scratch);
expect(scratch.textContent).to.equal('foo');
});
});