Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Jest + Preact #560

Closed
amir20 opened this issue Feb 23, 2017 · 18 comments
Closed

Jest + Preact #560

amir20 opened this issue Feb 23, 2017 · 18 comments

Comments

@amir20
Copy link

amir20 commented Feb 23, 2017

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.

Problem

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

My setup

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.

Questions

  • Should react-test-renderer work with preact?
  • Is there a better way to do this?
@amir20
Copy link
Author

amir20 commented Feb 23, 2017

Possibly related to preactjs/preact-compat#249 and enzymejs/enzyme#715

@developit
Copy link
Member

developit commented Feb 24, 2017

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())

@amir20
Copy link
Author

amir20 commented Feb 24, 2017

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.

@amir20 amir20 closed this as completed Feb 24, 2017
@rsaksida
Copy link

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);
  });
});

@developit
Copy link
Member

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!

@KrofDrakula
Copy link
Contributor

For anyone interested in using Jest for Preact environments, I've set up a PR for this at preact-boilerplate.

@armand1m
Copy link

Anyone could test components that use react components as childrens? I'm having a good trouble with react-intl and react-select

@developit
Copy link
Member

@armand1m shouldn't make a difference as long as you're aliasing preact-compat.

@armand1m
Copy link

@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.

@developit
Copy link
Member

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.

@armand1m
Copy link

@developit Nice, I will try it later and give some feedback after. Thank you!

@armand1m
Copy link

armand1m commented Apr 18, 2017

@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

@eduardoboucas
Copy link

@rmsaksida That looks awesome! Do you have any repository with the whole setup that you can share? Thanks!

@developit
Copy link
Member

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!

@ruyadorno
Copy link

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

@developit
Copy link
Member

@ruyadorno that's a really nice solution. going to give it a try and maybe integrate it into the boilerplate!

@haikyuu
Copy link

haikyuu commented Jun 19, 2018

@armand1m thanks. It works like a charm

@armand1m
Copy link

@haikyuu I'm glad it helped you mate 😄

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants