Preact: How to write tests easily?

Created on 20 Apr 2017  路  36Comments  路  Source: preactjs/preact

Are there any guides or best practices how to write unit tests for preact components easily? In the past I was used to use Enzyme to write tests for my React components. Unfortunately Enzyme does not support any libraries other than React itself 馃槥

Do you have any tips or library recommendations?

Most helpful comment

Hey everyone! @mzgoddard and I have a 1.0 release candidate of an "enzyme-ish" preact-render-spy. If people would please give some 馃憖 and see if you like testing with the library.

Please check out https://www.npmjs.com/package/preact-render-spy and file any feedback/issues on https://github.com/mzgoddard/preact-render-spy/

Here is a short example from our README

import {h} from 'preact';
import {shallow} from 'preact-render-spy';
import Testable from './testable';

it('lets you do cool things with preact components', () => {
  const context = shallow(<Testable />);
  expect(context.find('div').contains(<a>link</a>)).toBeTruthy();
  context.find('[onClick]').simulate('click');
  expect(context.find('a').text()).toBe('clicked');
});

(Also tweet to RT if you want to help publicize: https://twitter.com/zofgames/status/883044147967537152)

All 36 comments

Good timing, I just answered this on Twitter haha.
There are a few options:

First and most important is preact-jsx-chai (JSX Assertions). It lets you assert that components, when rendered, produce a given Virtual DOM tree (deeply or only a single level down):
https://github.com/developit/preact-jsx-chai/

Then there's the option of using preact-jsx-chai to test stateful components by instantiating them _(careful with this one though, since it bypasses lifecycle methods for the manually instantiated component)_:
https://gist.github.com/developit/9b0bb57b3e001de67814c7f4de9cbfbf

The third is to test using Preact's normal DOM renderer against the a DOM (browser, undom, jsdom, etc). Most preact-* repos are tested using a combination of this technique and preact-jsx-chai. Example:
https://github.com/developit/preact-router/blob/master/test/dom.js

I use jsdom (don't know if it's the recommended option). Basically mounting the component and testing against the DOM.

Yup! For everything except dimensions/layout, JSDom is great. It's also the default in Jest, which is now the officially recommended testing solution in preact-boilerplate.

Thank you for your help :+1: Unfortunately I don't use Chai / Mocha for my tests. I'm using AVA. So both options with preact-jsx-chai does not work in my environment.

I think jsdom is not needed anymore since Google announced Chrome Headless a few days ago :wink: PhantomJS for example dropped it's development immediately at that day.

So the only option for me is to render my components to a real DOM and compare the real DOM against my expectations? That would work but it's only half so funny as expected 馃槄

I've been writing unit tests for Preact components using Karma and this code to do shallow rendering.

Ok. I will give it a shot tomorrow

You can use the preact-compat-enzyme pkg and preact-test-utils pkg for alias react,react-dom and react-test-utils. Only add code in webpack like following:

webpack.resolve.alias = {
      'react-dom/server': 'preact-render-to-string',
      'react-addons-test-utils': 'preact-test-utils',
      'react-addons-transition-group': 'preact-transition-group',
      'react': 'preact-compat-enzyme',
      'react-dom': 'preact-compat-enzyme'
    }

And then you can write test case use enzyme under mount mode. But need care about setProps, it's async under preact but sync under react.

Any issues you can report here

@windyGex we should get this documented somewhere. Maybe on the preactjs.com site under a new testing guide.

Before writing doc, a little something need do. Can preact export constants ? Because it be needed at this.

Should we close this issue? It would be really awesome if this could be added to the docs at http://preactjs.com 馃槈

Agreed, thanks @windyGex for submitting developit/preact-www#121!

@windyGex that property will never change going forward, it was only changed in 8.0 in order to prevent bundlers from polyfilling Symbol. Exporting it would add some weight 馃

Ok, I got it.

Even with the above configuration:

webpack.resolve.alias = {
      'react-dom/server': 'preact-render-to-string',
      'react-addons-test-utils': 'preact-test-utils',
      'react-addons-transition-group': 'preact-transition-group',
      'react': 'preact-compat-enzyme',
      'react-dom': 'preact-compat-enzyme'
    }

I get the errors:

Error in ./~/enzyme/build/react-compat.js

Module not found: 'react/addons' in '/Users/danoved/Source/app/node_modules/enzyme/build'

Error in ./~/enzyme/build/react-compat.js

Module not found: 'react/lib/ReactContext' in '/Users/danoved/Source/app/node_modules/enzyme/build'

Error in ./~/enzyme/build/react-compat.js

Module not found: 'react/lib/ExecutionEnvironment' in '/Users/danoved/Source/app/node_modules/enzyme/build'

Add following code:

webpack.externals = {
        'react/lib/ExecutionEnvironment': true,
        'react/lib/ReactContext': true,
        'react/addons': true
      }

I needed support for shallow rendering (which sadly does not currently work in enzyme + preact) so I've hacked together an eznyme-like testing framework for preact. Might be worth taking a look: https://github.com/rkostrzewski/pretest

@windyGex I updated my webpack to look like:

var webpack = {
  resolve: {
    alias: {
      "react": "preact-compat",
      "react-dom": "preact-compat",
      "create-react-class": "preact-compat/lib/create-react-class"
    },
  externals: {
    'react-dom/lib/ReactTestUtils': true,
    'react/lib/getNextDebugID': true,
    'react/lib/ReactCurrentOwner': true,
    'react/lib/ReactComponentTreeHook': true,
    'react/lib/React': true,
    'react/lib/ExecutionEnvironment': true,
    'react/lib/ReactContext': true,
    'react/addons': true,
    'react-dom/test-utils': true
  }
};

And now get the error:

Warning: ReactTestUtils has been moved to react-dom/test-utils. Update references to remove this warning.
react-addons-test-utils is an implicit dependency in order to support [email protected]. Please add the appropriate version to your devDependencies. See https://github.com/airbnb/enzyme#installation
RUNTIME EXCEPTION Exception occurred while loading your tests

var webpack = {
  resolve: {
    alias: {
      'react-dom/server': 'preact-render-to-string',
      'react-addons-test-utils': 'preact-test-utils',
      'react-addons-transition-group': 'preact-transition-group',
      'react': 'preact-compat-enzyme',
      'react-dom': 'preact-compat-enzyme'
    },
  externals: {
     'react/lib/ExecutionEnvironment': true,
     'react/lib/ReactContext': true,
     'react/addons': true
  }
};

@oveddan

Thank you @windyGex!

Now I'm getting the error:

WEBPACK Compiled with 2 warning(s)

Warning in ./~/enzyme/build/react-compat.js

Module not found: 'react-dom/test-utils' in '/Users/danoved/Source/app/node_modules/enzyme/build'

Warning in ./~/enzyme/build/react-compat.js

Module not found: 'react-test-renderer/shallow' in '/Users/danoved/Source/app/node_modules/enzyme/build'

Is there an example application out there with preact and enzyme working?

I think @windyGex has one, can't find it

Here is an example. You can ignore warning, because enzyme using try&catch to import modules and it will not effect test result. @oveddan @developit .

@mzgoddard and I have started working on some enzyme-ish API's for doing render testing with preact, if anyone wants to chime in on API ideas/proposal, we have an open issue here:

mzgoddard/preact-render-spy#9

Hi,
I've managed to run the tests with a combination of preact-render-to-json, enzyme and jest .toMatchSnapshot(). It works great. But now I need to simulate click but it doesn't seem to work with enzyme.
I try to shallow render my component but the enzyme find function doesn't work.
What would be the right way to simulate click with preact ?

@mparpaillon this is exactly the scenario that made @mzgoddard and I want to make our library!

We have already gotten it working enough to do simulate: https://github.com/mzgoddard/preact-render-spy/blob/8d8fcf437d516c979e4015abcc60965a2bc8a819/src/preact-render-spy.test.js#L81-L102

Please come check out what we are working on / the open issues and add some comments? I'm really interested in getting some feedback from other users that ourselves :)

@gnarf Looks cool. I'm gonna give it a try :) thx

EDIT: Works great

Hey everyone! @mzgoddard and I have a 1.0 release candidate of an "enzyme-ish" preact-render-spy. If people would please give some 馃憖 and see if you like testing with the library.

Please check out https://www.npmjs.com/package/preact-render-spy and file any feedback/issues on https://github.com/mzgoddard/preact-render-spy/

Here is a short example from our README

import {h} from 'preact';
import {shallow} from 'preact-render-spy';
import Testable from './testable';

it('lets you do cool things with preact components', () => {
  const context = shallow(<Testable />);
  expect(context.find('div').contains(<a>link</a>)).toBeTruthy();
  context.find('[onClick]').simulate('click');
  expect(context.find('a').text()).toBe('clicked');
});

(Also tweet to RT if you want to help publicize: https://twitter.com/zofgames/status/883044147967537152)

Looks awesome, I'm going to try this out. We're have a scaffolded preact test command in preact-cli and I'd love to ship this as part of the default test suite we generate for people.

For anyone looking to do this using JSDOM without test frameworks or babel:

const Style = require('../dist/component').default
const { render, h } = require('preact')
const Window = require('window')
const window = new Window()

// needed by preact to run render()
const document = global.document = window.document

// mount for the first time (componentWillMount)
render(
  h(Style, null, ['button { background: red; }']),
  document.body,
  document.body.lastChild
)
// update (componentWillUpdate)
render(
  h(Style, null, ['button { background: blue; }']),
  document.body,
  document.body.lastChild
)

// get the resulting HTML
console.log(document.documentElement.outerHTML)

@gnarf I got preact-render-spy working and immediately hit a problem where I couldn't verify (within a single test) that a certain component was rendering itself as a div. In enzyme, I would go expect(wrapper.type()).to.equal('div'), here I can't write this test so I have to keep looking for other solutions.

http://airbnb.io/enzyme/docs/api/ReactWrapper/type.html

Opening an issue on preact render spy would be nice, i could probably add a method to make it a little easier but you could always check that wrapper.output().nodeName is div.

Our stuff isn't enzyme compatible, it's its own api

I think the expression you provided is simple enough, thanks. After some thought I decided to use Jest to cover all markup assertions and fallback to preact spy for is-component-in-tree and input simulation. This approach seems to have less roadblocks.

@gnarf very nice approach with preact-render-spy, thanks a lot!! 馃帀

I'm getting this error. ReferenceError: TestUtils is not defined.
I'm using jest preact and trying to setup enzyme with it

import { h, render, Component } from "preact";
import Input from "../components/input"; // It is a input component
import { mount } from "enzyme";
let value;
const input = mount(<Input changeCallback={val => value = val}/>);
input.simulate('change');

I get the above error TestUtils is not defined. I'm facing below issues,
1) when i look in the preactEnzymeAdapter.js, there is no TestUtils. How to work with this library.
2) when i try to run input.setProps() method, I get this error
TypeError: instance.setChildProps is not a function

Has anyone ever experienced such error: cannot find 'react-dom' from 'index.js', while testing a component connected to redux-store ? Where index.js is just a local file. I got this error in Preact based project while testing an action object too, which was importing store (in that scenario, it was cannot find 'react-dom' from 'react-data-grid-addons.js'). I think both can store can be mocked for testing, but in former scenario, I am not sure how to use Redux-mock-store for testing a connected component. ... any suggestions ? - basically testing a
redux-connected component?
@developit @gnarf .

Hello,

I've been working on a new adapter for Enzyme which allows it to be used "natively" with Preact, ie. without requiring React-compatibility libraries or indirectly requiring React (as enzyme-adapter-preact does): https://github.com/robertknight/enzyme-adapter-preact-pure. It supports full, shallow and static rendering.

I would appreciate any help I can get with testing this adapter with real components.

We have updated our docs with a section about the mentioned enzyme adapter:

Was this page helpful?
0 / 5 - 0 ratings

Related issues

paulkatich picture paulkatich  路  3Comments

matuscongrady picture matuscongrady  路  3Comments

adriaanwm picture adriaanwm  路  3Comments

kay-is picture kay-is  路  3Comments

mizchi picture mizchi  路  3Comments