Back to Repositories

Testing Hook Name Integration Workflow in Preact Devtools

This test suite validates the addHookName functionality in Preact’s devtools, focusing on how custom hook names are handled and integrated with the options API. The tests ensure proper behavior both with and without options hooks present.

Test Coverage Overview

The test suite provides comprehensive coverage of the addHookName utility in Preact’s devtools implementation.

  • Tests basic hook name addition functionality
  • Verifies behavior when options hook is absent
  • Validates interaction with useState hook
  • Checks proper integration with Preact’s options API

Implementation Analysis

The testing approach employs Jest’s describe/it pattern combined with Preact-specific test utilities.

Key implementation aspects include:
  • Usage of setupScratch and teardown helpers
  • Integration of sinon spy for monitoring hook calls
  • Component rendering validation
  • Hook state management verification

Technical Details

  • Testing Framework: Jest
  • Component Framework: Preact
  • Utilities: sinon for spies
  • Helper Functions: setupScratch, teardown
  • Key Imports: createElement, render, options from Preact
  • Hook Testing: useState from preact/hooks

Best Practices Demonstrated

The test suite exemplifies several testing best practices in React/Preact development.

  • Proper test isolation through beforeEach/afterEach
  • Clean setup and teardown procedures
  • Explicit error case handling
  • Clear test case separation
  • Effective use of spy patterns for validation

preactjs/preact

devtools/test/browser/addHookName.test.js

            
import { createElement, render, options } from 'preact';
import { setupScratch, teardown } from '../../../test/_util/helpers';
import { useState } from 'preact/hooks';
import { addHookName } from 'preact/devtools';

/** @jsx createElement */

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

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

	afterEach(() => {
		teardown(scratch);
		delete options._addHookName;
	});

	it('should do nothing when no options hook is present', () => {
		function useFoo() {
			return addHookName(useState(0), 'foo');
		}

		function App() {
			let [v] = useFoo();
			return <div>{v}</div>;
		}

		expect(() => render(<App />, scratch)).to.not.throw();
	});

	it('should call options hook with value', () => {
		let spy = (options._addHookName = sinon.spy());

		function useFoo() {
			return addHookName(useState(0), 'foo');
		}

		function App() {
			let [v] = useFoo();
			return <div>{v}</div>;
		}

		render(<App />, scratch);

		expect(spy).to.be.calledOnce;
		expect(spy).to.be.calledWith('foo');
	});
});