Back to Repositories

Testing componentDidMount Lifecycle Method Implementation in PreactJS

This test suite validates the componentDidMount lifecycle method in Preact components, focusing on ref handling and state management. It ensures proper execution timing and state update behavior in component mounting scenarios.

Test Coverage Overview

The test suite provides comprehensive coverage of componentDidMount functionality in Preact components.

Key areas tested include:
  • Ref initialization timing and accuracy
  • Multiple setState callback handling
  • Component mounting sequence verification
  • State update batching behavior

Implementation Analysis

The testing approach utilizes Jest and Sinon for spy functionality, implementing isolated component testing scenarios. The suite employs Preact’s test-utils for rerender capabilities and custom scratch element setup for DOM manipulation.

Testing patterns include:
  • Component class implementations with lifecycle methods
  • Ref callback verification
  • State update sequence validation

Technical Details

Testing infrastructure includes:
  • Preact test-utils for rerender functionality
  • Custom scratch element setup/teardown helpers
  • Sinon spy implementation for callback tracking
  • Jest test runner configuration
  • DOM element reference management

Best Practices Demonstrated

The test suite exemplifies high-quality testing practices through isolated component testing and comprehensive lifecycle verification.

Notable practices include:
  • Clean setup/teardown between tests
  • Explicit state management testing
  • Ref handling verification
  • Asynchronous state update validation

preactjs/preact

test/browser/lifecycles/componentDidMount.test.js

            
import { createElement, render, Component } from 'preact';
import { setupRerender } from 'preact/test-utils';
import { setupScratch, teardown } from '../../_util/helpers';

/** @jsx createElement */

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

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

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

	describe('#componentDidMount', () => {
		it('is invoked after refs are set', () => {
			const spy = sinon.spy();

			class App extends Component {
				componentDidMount() {
					expect(spy).to.have.been.calledOnceWith(scratch.firstChild);
				}

				render() {
					return <div ref={spy} />;
				}
			}

			render(<App />, scratch);
			expect(spy).to.have.been.calledOnceWith(scratch.firstChild);
		});

		it('supports multiple setState callbacks', () => {
			const spy = sinon.spy();

			class App extends Component {
				constructor(props) {
					super(props);
					this.state = { count: 0 };
				}

				componentDidMount() {
					// eslint-disable-next-line
					this.setState({ count: 1 }, spy);
					// eslint-disable-next-line
					this.setState({ count: 2 }, spy);
				}

				render() {
					return <div />;
				}
			}

			render(<App />, scratch);

			rerender();
			expect(spy).to.have.been.calledTwice;
		});
	});
});