Important: This documentation covers Yarn 1 (Classic).
For Yarn 2+ docs and migration guide, see yarnpkg.com.

Package detail

enzyme-adapter-preact-pure

preactjs25.2kMIT4.1.0TypeScript support: included

Enzyme adapter for Preact

readme

enzyme-adapter-preact-pure

This is an adapter to support using the Enzyme UI component testing library with Preact. For documentation, please see the testing guide on the PreactJS website.

Supported Preact versions

Version 3.x of the adapter supports Preact v10+. Earlier versions support both Preact v8 and v10.

Usage

Add the library to your development dependencies:

# If using npm
npm install --save-dev enzyme-adapter-preact-pure

# If using yarn
yarn add --dev enzyme-adapter-preact-pure

Then in the setup code for your tests, configure Enzyme to use the adapter provided by this package:

import { configure } from 'enzyme';
import Adapter from 'enzyme-adapter-preact-pure';

configure({ adapter: new Adapter() });

Once the adapter is configured, you can write Enzyme tests for your Preact UI components following the Enzyme docs. The full DOM rendering, shallow rendering and string rendering modes are supported.

Example projects

For runnable example projects, see the examples/ directory. To run the examples locally, clone this repository, then run:

cd examples/<project name>
npm install
npm test

Differences compared to Enzyme + React

The general intent is that tests written using Enzyme + React can be easily made to work with Enzyme + Preact or vice-versa. However there are some differences in behavior between this adapter and Enzyme's React adapters to be aware of:

Shallow rendering

  • When using Enzyme's shallow rendering mode, this adapter always invokes the component's lifecycle methods (componentDidUpdate etc.). The disableLifecycleMethods option is not respected.

  • React's shallow rendering does not create actual DOM nodes. The shallow rendering implemented by this adapter does. It works by simply by rendering the component as normal, except making any child components output only the children passed to them. In other words, during shallow rendering, all child components behave as if they were defined like this:

    function ShallowRenderedChild({ children }) {
      return children;
    }

    This means that any side effects that rendered DOM elements have, such as <img> elements loading images, will still execute.

If you are converting a React Enzyme test suite to use Preact, try out our CompatShallowRenderer. This renderer is an alternate shallow renderer to the default that uses a custom diffing algorithm that mirrors the Preact diff algorithm but only shallowly renders elements, similarly to what react-shallow-render does for React components. This renderer has a couple of behaviors that more closely resembles the React adapters, including:

  • No DOM nodes are created, so a DOM environment is not required
  • disableLifecycleMethods option is respected
  • Virtual element props are preserved intact so filter methods on the Enzyme wrapper behave more similarly to the React wrappers

To enable the CompatShallowRenderer, pass it into the shallowRenderer Adapter option when configuring Enzyme:

import { configure } from 'enzyme';
import Adapter from 'enzyme-adapter-preact-pure';
import { CompatShallowRenderer } from 'enzyme-adapter-preact-pure/compat';

// Setup Enzyme
configure({
  adapter: new Adapter({
    ShallowRenderer: CompatShallowRenderer,
  }),
});

Simulating events

The simulate API does not dispatch actual DOM events in the React adapters, it just calls the corresponding handler. The Preact adapter does dispatch an actual event using element.dispatchEvent(...). Because this behavior, the Preact adapters can only simulate events on real DOM nodes, not Components.

If you'd like to simulate events on Components, enable the simulateEventsOnComponents option in the Adapter options. This option changes the previous behavior of how events were dispatched (by directly invoking event handlers instead of dispatching an event) and so is disabled by default. Enabling this option is useful if you are migrating an Enzyme test suite from React to Preact.

import { configure } from 'enzyme';
import Adapter from 'enzyme-adapter-preact-pure';

// Setup Enzyme
configure({
  adapter: new Adapter({
    simulateEventsOnComponents: true,
  }),
});

String rendering

By default, the Preact string renderer renders your component into the DOM and then returns the innerHTML of the DOM container. This behavior means string rendering requires a DOM environment.

If you'd like to run tests that use the string renderer in a test environment that does not have a DOM, pass preact-render-to-string into the renderToString Adapter option. Enabling this option is useful if you are migrating an Enzyme test suite from React to Preact.

import { configure } from 'enzyme';
import Adapter from 'enzyme-adapter-preact-pure';
import renderToString from 'preact-render-to-string';

// Setup Enzyme
configure({
  adapter: new Adapter({
    renderToString,
  }),
});

State updates

setState synchronously re-renders the component in React, except in event handlers. Preact on the other hand by default batches together calls to setState within the same tick of the event loop and schedules a render to happen in a future microtask. React's behavior may change in a future release.

To make writing tests easier, the Preact adapter will apply any pending state updates and re-render when:

  • The component is initially rendered by mount or shallow
  • An Enzyme API call is made that is expected to trigger a change in the rendered output, such as wrapper.setProps, wrapper.simulate or wrapper.setState
  • wrapper.update is called explicitly by a test

The consequences of this when writing tests are that any state updates triggered outside of an Enzyme method call will not be reflected in the rendered DOM until wrapper.update is called. Note this function also needs to be called when using React, as it synchronizes Enzyme's snapshot of the output with the actual DOM tree.

Example:

const wrapper = shallow(<ParentComponent />);

// Trigger a state update outsize of Enzyme.
wrapper.find(ChildComponent).props().onClick();

// Update the Enzyme wrapper's snapshot.
wrapper.update();

// Test that parent component updated as expected.

When using the Hooks API you also need to wrap any code which triggers effects in an act call in order to flush effects and trigger a re-render. The initial render and calls to APIs such as setProps or simulate are automatically wrapped in act for you.

In Preact the act function is available in the "preact/test-utils" package.

import { act } from 'preact/test-utils';

// Any effects scheduled by the initial render will run before `mount` returns.
const wrapper = mount(<Widget showInputField={false} />);

// Perform an action outside of Enzyme which triggers effects in the parent
// `Widget`. Since Enzyme doesn't know about this, we have to wrap the calls
// with `act` to make effects execute before we call `wrapper.update`.
act(() => {
  wrapper.find(ChildWidget).props().onButtonClicked();
});

// Update the Enzyme wrapper's snapshot
wrapper.update();

Property names

In order to support Enzyme's class selectors, class props on Preact components are mapped to className.

import { mount } from 'enzyme';

const wrapper = mount(<div class="widget" />);
wrapper.props(); // Returns `{ children: [], className: 'widget' }`
wrapper.find('.widget').length; // Returns `1`

Usage with preact/compat

This package has the same interface as the official enzyme-adapter-react-$version packages. If you are using preact/compat, you can alias enzyme-adapter-react-$version to this package in the same way as preact/compat.

Usage with TypeScript

This package is compatible with TypeScript and ships with type declarations. In order to mix Enzymes types from @types/enzyme with Preact, you will need to include some extensions to the "preact" types which are provided by this project.

To do that, add the following line to one of the source files or .d.ts files for your project:

/// <reference types="enzyme-adapter-preact-pure" />

See the TypeScript example in examples/typescript for a runnable example.

Development

After cloning the repository, you can build it and run tests as follows:

# Install dependencies.
yarn install

# Build the adapter library.
yarn build

# Run tests.
yarn test

# Run tests against a custom build of Preact.
yarn test --preact-lib <path to Preact bundle>

Release process

New releases of this package are created using np.

  1. Check out the latest master branch
  2. Edit CHANGELOG.md to add notes for the version you are about to release.
  3. Commit the changes to CHANGELOG.md and push back to GitHub
  4. Run np <semver-type> to create the release, where <semver-type> is the category of release according to Semantic Versioning, typically minor.

FAQ

Can I use this library to test components that use hooks?

Yes. This library supports components that use the "Hooks" APIs available in Preact v10+. You may need to use the act function from preact/test-utils to flush effects synchronously in certain places. See the notes above about state updates in tests.

Why does the package name have a "-pure" suffix?

The name has a "-pure" suffix to distinguish it from enzyme-adapter-preact package which indirectly depends on React. This library is a "pure" Preact adapter which does not require Preact's React compatibility add-on.

changelog

Changelog

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

[4.1.0] - 2023-01-05

  • Adds a new shallow renderer that more closely matches the behavior of the React 16 shallow renderer. This new renderer can be enabled by importing CompatShallowRenderer from enzyme-adapter-preact-pure/compat and passing it in the ShallowRenderer Adapter option.

    The previous shallow renderer rendered components into a DOM and modified the component's output so that all children return null to prevent rendering further down the tree. The compat shallow renderer is a custom implementation of Preact's diffing algorithm that only shallow renders the given component and does not recurse down the VDOM tree. It's behavior more closely matches the React 16 Enzyme adapter and it well suited for migrating an Enzyme test suite from React to Preact.

  • Support more return types (e.g. booleans, numbers, BigInts) from components

  • Add an option (renderToString) to allow passing in a custom string renderer to use for Enzyme's 'string' renderer instead of rendering into the DOM and reading the HTML output. It is expected that renderToString from preact-render-to-string is passed into this option. This change enables using the string renderer in non-DOM environments and more closely matches the React adapter's behavior.

  • Add a feature flag (simulateEventsOnComponents) for supporting simulating events on Components #211

    This new feature flag turns on behavior that enables calling .simulate directly on Components. For shallow rendering, this directly calls the component's corresponding prop. For mount rendering, it finds the first DOM node in the Component, and dispatches the event from it.

    NOTE: This flag changes the behavior of calling simulate on shallow rendered host (a.k.a DOM) nodes. When this flag is off, simulate dispatches a native DOM event on the host node. When this flag is turned on, simulate directly calls the prop of the event handler with arguments passed to simulate.

    The behavior turned on by this flag matches the behavior of the React 16 Enzyme adapter.

[4.0.1] - 2022-04-15

  • Added a partial fix for an incompatibility between Preact's JSX element type and the JSX element type from @types/react v18. #177.

[4.0.0] - 2022-04-13

  • The CommonJS build of this package now targets ES 2020, which is the same target as the ESM build #166.

    If running tests against a pre-2020 browser or version of Node, you may need to add a polyfill for Array.prototype.flatMap in your own project.

[3.4.0] - 2022-02-24

  • Support wrappingComponent and wrappingComponentProps options for full (mount) and shallow rendering. Thanks @kevinweber. #157

[3.3.0] - 2021-11-09

  • simulateEvent now initializes the bubbles, cancelable and composed properties of dispatched events as they would be in real events. #131.

[3.2.0] - 2021-11-03

  • Add an ES module build of the package for modern browsers and bundlers. #151

[3.1.0] - 2021-04-08

  • Add support for invoke wrapper method. The Preact adapter currently only supports this for full (mount) rendering #135

[3.0.0] - 2021-01-11

  • This release removes support for Preact v8 to simplify ongoing maintenance. See #117.

    Users of Preact v8 will need to either stick with the last 2.x release of this package or upgrade their applications to Preact v10.

[2.2.4] - 2021-01-09

  • Fix error when setting certain event properties when calling simulate() in an environment that uses JSDOM #125

[2.2.3] - 2020-08-11

  • Fix a regression in 2.2.1 when a component that is stubbed out during shallow rendering is passed a number as a child #120

[2.2.2] - 2020-08-08

  • Fix a regression in 2.2.1 when a component that is stubbed out during shallow rendering is passed multiple children #119

[2.2.1] - 2020-07-19

  • Fix exception when shallow rendering a component that uses the "render prop" pattern #107.

[2.2.0] - 2019-11-10

  • Improve support for projects written in TypeScript by integrating with the @types/enzyme package #84. See the Usage with TypeScript section in the README and example project in examples/typescript.

[2.1.0] - 2019-10-03

  • Fix simulateError under Preact 10.0.0 #75
  • Make Preact v10 the default version internally. Preact v8 support will eventually be removed in a future major release. #76

[2.0.2] - 2019-08-08

  • Remove a workaround for old beta releases of Preact 10 which could cause an error about mutating a read-only property in certain environments #69

[2.0.1] - 2019-07-18

  • Fix an incompatibility with preact-compat for Preact v8 #62

[2.0.0] - 2019-06-17

  • The adapter no longer patches setState to make it synchronous #57.

Breaking Changes

Calls to setState on components rendered by Enzyme are no longer synchronous but are batched as Preact normally does outside of tests. Pending updates are automatically flushed when an Enzyme wrapper is updated, either as a result of an Enzyme API call (eg. wrapper.simulate, wrapper.setProps) or when wrapper.update() is called.

Most tests should be unaffected as they will trigger updates either through Enzyme API methods or will have needed to call wrapper.update() anyway. Tests can no longer depend on the tree being updated immediately after wrapper.setState returns however. Instead they should wait for the optional callback to setState to be invoked.

[1.13.4] - 2019-06-10

  • Prepare for upcoming internal changes to fragments and components in the next Preact 10 release (#55)

[1.13.3] - 2019-06-04

  • Fix shallow-rendering compatibility with Enzyme v3.10 (#51)

[1.13.2] - 2019-06-01

  • Support Preact 10.0.0-beta.2 (#49)

[1.13.1] - 2019-04-24

  • Fix exception with native (non-transpiled) arrow function components (#37)

[1.13.0] - 2019-04-17

  • Synchronously execute effects or state updates created with hooks after dispatching simulated events (#36)

[1.12.0] - 2019-04-14

  • Synchronously execute effects created with useEffect or useLayoutEffect hooks after the initial render (#34)

[1.11.0] - 2019-04-14

  • Support attachTo option for mount rendering to render into an existing DOM element

[1.10.4] - 2019-04-09

  • Avoid accessing children property of vnodes in Preact 10, as this triggers an error when using preact/debug

[1.10.3] - 2019-04-05

  • Work around issue where component type names are shown incorrectly when using preact-compat (for Preact v8) and document a limitation which is resolved in Preact 10 (#27).

[1.10.2] - 2019-03-29

  • Fix exception when wrapper.text() is called on an Enzyme wrapper around a text node (#15).

[1.10.1] - 2019-03-22

  • Made the Preact 10 adapter compatible with preact/compat by removing an instanceof Component check, which breaks if the Component class comes from the 'preact/compat' bundle
  • Made the adapter the default export of the package. The previous named exports have been kept for backwards compatibility

[1.9.0] - 2019-03-15

  • Changed the name of the package's main export to Adapter. The export is also exported under its previous name (PreactAdapter) for backwards compatibility

[1.8.0] - 2019-03-12

Changed

  • Internal cleanups to make the adapter less reliant on Preact internals and better separate Preact version-specific code

[1.7.1] - 2019-03-05

Fixed

  • Fix repository link in package.json

  • Mark Preact 10 as a dev dependency rather than a runtime dependency and fix the version number

[1.7.0] - 2019-03-05

Changed

  • Support using with production builds of the current version of Preact 10 (10.0.0-alpha0).

[1.6.0] - 2019-02-22

Added

  • Support Enzyme wrapper methods which take an element tree as an argument, such as wrapper.contains(...).

[1.5.0] - 2019-02-21

Added

  • Add support for simulating errors.

Changed

  • Children passed to non-rendered components during shallow-rendering are now present in the output, for consistency with how shallow rendering works in React.

Fixed

  • Shallow rendering now only renders the root element passed to shallow, not any child component elements passed in the call to shallow.

    In other words shallow(<Parent><Child/></Parent>) will render <Parent> but only a stub for <Child>.

[1.4.0] - 2019-02-19

Added

  • Add support for fragments. Children of fragments are presented to Enzyme as if they were children of their nearest non-fragment ancestor. In other words, fragments do not appear in the component tree exposed to Enzyme in the same way that they do not appear in the DOM tree in the browser.

[1.3.0] - 2019-02-18

Added

  • Initial support for Preact 10 and later. Preact 10 has an entirely different rendering implementation and a different VNode shape. The adapter will detect at runtime which version of Preact is in use and use an appropriate method to convert the render tree into the format that Enzyme expects.

  • Support running tests against a custom build of Preact using yarn test --preact-lib <path>.

Fixed

  • Keys and refs of components and DOM nodes are now exposed to Enzyme.

[1.2.0] - 2019-02-15

Changed

  • Calls to setState on fully-rendered components now trigger synchronous updates, for consistency with shallow rendering.

Fixed

  • Components that render only strings are now handled correctly.

  • Work around a bug in Enzyme that caused wrapper.get() to fail when using full rendering.

[1.1.0] - 2019-02-14

  • Map class prop to className so that Enzyme class selectors work.

[1.0.0] - 2019-02-14

  • Initial release.