Back to Repositories

Testing Virtual Node Serialization Implementation in Preact

This test suite validates the serializeVNode functionality in Preact’s debug utilities, focusing on component serialization and prop handling. It ensures proper string representation of virtual nodes with various configurations and component types.

Test Coverage Overview

The test suite provides comprehensive coverage of serializeVNode functionality, including:
  • Component displayName handling for both function and class components
  • Serialization of basic vnodes with and without children
  • Complex prop serialization including functions and objects
  • Edge cases for component rendering and prop value conversion

Implementation Analysis

The testing approach employs Jest’s describe/it pattern with clear test case isolation. Each test focuses on a specific serialization aspect, using Preact’s createElement for component creation and expect assertions for validation. The implementation leverages Preact’s internal debugging utilities for component visualization.

Technical Details

Testing tools and setup include:
  • Jest as the testing framework
  • Preact’s createElement for component creation
  • Custom serializeVNode utility from debug module
  • Component class extension from Preact core
  • JSX transformation with createElement pragma

Best Practices Demonstrated

The test suite exemplifies strong testing practices including:
  • Isolated test cases with clear descriptions
  • Comprehensive coverage of component variations
  • Proper handling of complex props and edge cases
  • Consistent assertion patterns
  • Clear separation of concerns between different serialization scenarios

preactjs/preact

debug/test/browser/serializeVNode.test.js

            
import { createElement, Component } from 'preact';
import { serializeVNode } from '../../src/debug';

/** @jsx createElement */

describe('serializeVNode', () => {
	it("should prefer a function component's displayName", () => {
		function Foo() {
			return <div />;
		}
		Foo.displayName = 'Bar';

		expect(serializeVNode(<Foo />)).to.equal('<Bar />');
	});

	it("should prefer a class component's displayName", () => {
		class Bar extends Component {
			render() {
				return <div />;
			}
		}
		Bar.displayName = 'Foo';

		expect(serializeVNode(<Bar />)).to.equal('<Foo />');
	});

	it('should serialize vnodes without children', () => {
		expect(serializeVNode(<br />)).to.equal('<br />');
	});

	it('should serialize vnodes with children', () => {
		expect(serializeVNode(<div>Hello World</div>)).to.equal('<div>..</div>');
	});

	it('should serialize components', () => {
		function Foo() {
			return <div />;
		}
		expect(serializeVNode(<Foo />)).to.equal('<Foo />');
	});

	it('should serialize props', () => {
		expect(serializeVNode(<div class="foo" />)).to.equal('<div class="foo" />');

		// Ensure that we have a predictable function name. Our test runner
		// creates an all inclusive bundle per file and the identifier
		// "noop" may have already been used.
		// eslint-disable-next-line func-style
		let noop = function noopFn() {};
		expect(serializeVNode(<div onClick={noop} />)).to.equal(
			'<div onClick="function noopFn() {}" />'
		);

		function Foo(props) {
			return props.foo;
		}

		expect(serializeVNode(<Foo foo={[1, 2, 3]} />)).to.equal(
			'<Foo foo="1,2,3" />'
		);

		expect(serializeVNode(<div prop={Object.create(null)} />)).to.equal(
			'<div prop="[object Object]" />'
		);
	});
});