I bet this question has been asked a lot. I have searched for two hours and I am not able to find a solution. There doesn't seem to be much about preact with jest testing. I looked at the boilerplate and it uses Karma.
When trying to use Jest with Preact I get the following error:
FAIL src/widget/index.test.js
● Test suite failed to run
Cannot find module 'react/lib/ReactComponentTreeHook' from 'ReactDebugTool.js'
at Resolver.resolveModule (node_modules/jest-resolve/build/index.js:169:17)
at Object.<anonymous> (node_modules/react-test-renderer/lib/ReactDebugTool.js:16:30)
Test Suites: 1 failed, 1 total
Tests: 0 total
Snapshots: 0 total
Time: 0.601s
I followed the guidelines to setup babel with webpack. My .babelrc is
{
"plugins": [
["transform-react-jsx", { "pragma":"h" }],
"transform-class-properties"
],
"presets": [
["es2015", {
"modules": false
}]
],
"env": {
"test": {
"plugins": [
"transform-es2015-modules-commonjs",
["transform-react-jsx", { "pragma":"h" }],
"transform-class-properties"
]
}
}
}
package.json uses identity-obj-proxy as suggested
"jest": {
"moduleNameMapper": {
"\\.(css)$": "identity-obj-proxy"
}
}
And finally my test looks like
import Widget from './index';
import renderer from 'react-test-renderer';
test('Tests for widget to have been rendered', () => {
const tree = renderer.create(
<Widget href="http://test.com" target="_blank" data-variation="test"
innerHTML="<b>test</b> foo bar"/>
).toJSON();
expect(tree).toMatchSnapshot();
});
I am losing my mind. I added react but then I get a bunch of other errors.
react-test-renderer work with preact? Possibly related to https://github.com/developit/preact-compat/issues/249 and https://github.com/airbnb/enzyme/issues/715
react-test-renderer will likely never work with preact. preact-render-to-string support very similar functionality (including shallow rendering and JSX output with support for complex props). It doesn't currently support JSON output, which means Jest snapshots get double-encoded.
I'd _love_ an experimental PR for JSON output if anyone has the time - I haven't had time yet since I'm only just looking into Jest myself.
FWIW I think most people test Preact components using the preact-jsx-chai plugin. It uses preact-render-to-string under the hood, and has a nice syntax:
expect(
<Things items={['a', 'b']} />
).to.equal(
<div class="things">
<Item name="a" />
<Item name="b" />
</div>
);
(it also supports shallow rendering via .equal() and deep comparison via .deep.equal())
Great. This helps a lot. I'll close ticket. If I get time to play around with the code then I'll try sending a PR.
Might help someone: I've been testing my Preact components with Jest and html-looks-like. It works fine and is pretty easy to set up.
import { h } from 'preact';
import render from 'preact-render-to-string';
import htmlLooksLike from 'html-looks-like';
const Thing = () => (
<div class="some-class">
<span>Nope</span>
<span>Nope</span>
<span>Yep</span>
</div>
);
describe('Thing', () => {
it('has Yep', () => {
const actual = render(<Thing />);
const expected = `
<div>
{{ ... }}
<span>Yep</span>
</div>
`;
htmlLooksLike(actual, expected);
});
});
That is a ridiculously cool technique @rmsaksida - will be stealing it for some of my stuff haha. I love the syntax for ignoring parts of the tree!
For anyone interested in using Jest for Preact environments, I've set up a PR for this at preact-boilerplate.
Anyone could test components that use react components as childrens? I'm having a good trouble with react-intl and react-select
@armand1m shouldn't make a difference as long as you're aliasing preact-compat.
@developit So, I'm aliasing react with preact-compat into my .babel-rc and webpack.config.js. When bundling the project, everything were working nice. When running it with jest, it could render simple elements that didn't use third-party react components nicely, but when trying to run a specific component using react-select, it was asking for react to render it.
I started having this problem with 'react-intl', have migrated to 'preact-intl' and have trespassed this problem.
Then I started having problems with 'react-select'.
When trying to alias react into my package.json, inside the "jest" key, every test case was broken.
It was trowing an error like:
Type Error: ( 0, _preact.h ) is not a function
I didn't had much time and mocked the 'react-select' to render what I needed from my component.
I can send more detailed information later, but I couldn't find other easy way to render this component into a jest test harness.
Ah - that error makes it seem like your JSX Pragma setting is being applied to all of node_modules, which will not work. I'm not overly familliar with Jest, but there must be a way to tell it to only transpile first-party code (code in your repo). If you can get it to do that (babelrc:false maybe?) then it should work.
@developit Nice, I will try it later and give some feedback after. Thank you!
@developit Got it working. It was actually because when you specify a module to jest configuration in package.json, you're specifying actually a Regexp. When using like this:
{
"jest": {
"moduleNameMapper": {
"\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/__mocks__/fileMock.js",
"\\.(css|less|scss)$": "identity-obj-proxy",
"react": "preact-compat",
"react-dom": "preact-compat"
},
"collectCoverageFrom": [
"app/**/*.{js,jsx}"
],
"moduleFileExtensions": [
"js",
"jsx"
],
"moduleDirectories": [
"node_modules"
]
}
}
It will not even run a component, because it is looking actually at every component that has "react", for example, in its name, and replacing their calls to preact-compat.
Got it working using this jest config in my package.json:
{
"jest": {
"moduleNameMapper": {
"\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/__mocks__/fileMock.js",
"\\.(css|less|scss)$": "identity-obj-proxy",
"^react$": "preact-compat",
"^react-dom$": "preact-compat"
},
"collectCoverageFrom": [
"app/**/*.{js,jsx}"
],
"moduleFileExtensions": [
"js",
"jsx"
],
"moduleDirectories": [
"node_modules"
]
}
}
and this .babelrc:
{
"sourceMaps": true,
"presets": [
["es2015", {
"es2015": {
"loose": true,
"modules": false
}
}],
"stage-0"
],
"plugins": [
["transform-decorators-legacy"],
["transform-react-jsx", { "pragma":"h" }]
]
}
The slight difference is in the regex for aliasing react and react-dom
@rmsaksida That looks awesome! Do you have any repository with the whole setup that you can share? Thanks!
would love to see where he's used it too!
FWIW we just merged a PR that switched preact-boilerplate over to Jest. It's quite awesome!
I have been using preact-render-to-string like the example over here + jest-serializer-html-string to sanitize html output with quite some success until now
@ruyadorno that's a really nice solution. going to give it a try and maybe integrate it into the boilerplate!
@armand1m thanks. It works like a charm
@haikyuu I'm glad it helped you mate 😄
Most helpful comment
Might help someone: I've been testing my Preact components with Jest and html-looks-like. It works fine and is pretty easy to set up.