Back to Repositories

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

The test suite comprehensively covers element cloning operations in Preact’s compatibility layer.

  • Basic element cloning validation
  • Props.children handling scenarios
  • Children precedence rules
  • Multiple children arguments
  • Edge cases with invalid elements
  • Integration with Preact core JSX constructor

Implementation Analysis

The testing approach systematically verifies cloneElement behavior through isolated unit tests.

Tests utilize Jest’s describe/it pattern and custom helper functions for DOM setup. Implementation focuses on comparing cloned elements with originals, validating props inheritance, and ensuring proper children hierarchy resolution.

Technical Details

  • Testing Framework: Jest
  • Helper Utilities: setupScratch, teardown
  • DOM Environment: Virtual scratch div element
  • Component Types: Functional components and JSX elements
  • Assertion Style: Expect chainable assertions

Best Practices Demonstrated

The test suite exemplifies high-quality testing practices with clear test isolation and thorough edge case coverage.

  • Proper test setup and teardown
  • Consistent assertion patterns
  • Comprehensive props and children validation
  • Edge case handling
  • Integration testing with core functionality

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');
	});
});