Back to Repositories

Testing ComponentWillMount Lifecycle Methods in Preact

This test suite validates the componentWillMount lifecycle method in Preact components, focusing on state updates and callback handling during component initialization. It ensures proper state management and callback execution during the mounting phase of Preact components.

Test Coverage Overview

The test suite provides comprehensive coverage of componentWillMount behavior in Preact components.

  • Validates state updates within componentWillMount
  • Tests setState callback execution order
  • Verifies multiple setState calls within componentWillMount
  • Ensures proper state synchronization during component initialization

Implementation Analysis

The testing approach utilizes Jest’s describe/it pattern with setup and teardown hooks for consistent test environments.

Tests implement class-based components extending Preact’s Component class, with specific focus on constructor and componentWillMount lifecycle methods. The implementation leverages Preact’s test-utils for rerender functionality and custom scratch element setup.

Technical Details

  • Testing Framework: Jest
  • Component Library: Preact
  • Test Utilities: preact/test-utils
  • Helper Functions: setupScratch, teardown
  • Assertion Library: Sinon for spy functions
  • DOM Environment: Virtual scratch element

Best Practices Demonstrated

The test suite exemplifies strong testing practices through isolated component testing and proper cleanup.

  • Consistent beforeEach/afterEach hooks
  • Isolated state verification
  • Proper async callback testing
  • Clean test environment management
  • Clear test case organization

preactjs/preact

test/browser/lifecycles/componentWillMount.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;

	/** @type {() => void} */
	let rerender;

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

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

	describe('#componentWillMount', () => {
		it('should update state when called setState in componentWillMount', () => {
			let componentState;

			class Foo extends Component {
				constructor(props) {
					super(props);
					this.state = {
						value: 0
					};
				}
				componentWillMount() {
					this.setState({ value: 1 });
				}
				render() {
					componentState = this.state;
					return <div />;
				}
			}

			render(<Foo />, scratch);

			expect(componentState).to.deep.equal({ value: 1 });
		});

		it('should invoke setState callbacks when setState is called in componentWillMount', () => {
			let componentState;
			let callback = sinon.spy();

			class Foo extends Component {
				constructor(props) {
					super(props);
					this.state = {
						value: 0
					};
				}
				componentWillMount() {
					this.setState({ value: 1 }, callback);
					this.setState({ value: 2 }, () => {
						callback();
						this.setState({ value: 3 }, callback);
					});
				}
				render() {
					componentState = this.state;
					return <div />;
				}
			}

			render(<Foo />, scratch);

			expect(componentState).to.deep.equal({ value: 2 });
			expect(callback).to.have.been.calledTwice;

			rerender();

			expect(componentState).to.deep.equal({ value: 3 });
			expect(callback).to.have.been.calledThrice;
		});
	});
});