Enzyme: Webpack build issues

Created on 4 Dec 2015  Â·  73Comments  Â·  Source: enzymejs/enzyme

I'm trying to get enzyme working using a pretty standard webpack/karma setup. Webpack throws a bunch of errors related to the dependencies enzyme imports, including sinon, cheerio, and jsdom. Sinon gives webpack heartburn because it uses it's own require (which seems to be documented here: https://github.com/webpack/webpack/issues/304), and then there are a bunch of "Module not found" errors for jsdom and cheerio.

I'm importing enzyme as described in the docs and can't really think of anything else I might be missing, so I'm curious if anyone else is trying to use webpack and running into a similar issue, or if there's just something weird with my configuration. I'd expect to be able to just import it and have it work, but maybe I need to do something with those external libraries?

Here's my test file for reference:

import expect from 'expect';
import { shallow } from 'enzyme';
import React from 'react';
import Button from '../Button';

describe('Button', () => {
    it('should render children passed in', () => {
        const wrapper = shallow(
            <Button><div className="foo" /></Button>
        );

        expect(wrapper.contains(<div className="foo" />)).toBe(true);
    });
});

I won't paste the entire error log from webpack because it's pretty long, but here's a sample:


WARNING in ./~/enzyme/~/jsdom/~/acorn/dist/acorn.js
Critical dependencies:
1:478-485 This seems to be a pre-built javascript file. Though this is possible, it's not recommended. Try to require the original source to get better results.
 @ ./~/enzyme/~/jsdom/~/acorn/dist/acorn.js 1:478-485

WARNING in ./~/enzyme/~/jsdom/~/acorn/dist/walk.js
Critical dependencies:
1:503-510 This seems to be a pre-built javascript file. Though this is possible, it's not recommended. Try to require the original source to get better results.
 @ ./~/enzyme/~/jsdom/~/acorn/dist/walk.js 1:503-510

ERROR in ./~/enzyme/build/react-compat.js
Module not found: Error: Cannot resolve module 'react/lib/ExecutionEnvironment' in /Users/agoggin/www/vhosts/hammerhead/node_modules/enzyme/build
 @ ./~/enzyme/build/react-compat.js 22:2-43

ERROR in ./~/enzyme/~/cheerio/index.js
Module not found: Error: Cannot resolve module 'json' in /Users/agoggin/www/vhosts/hammerhead/node_modules/enzyme/node_modules/cheerio
 @ ./~/enzyme/~/cheerio/index.js 11:18-38

ERROR in ./~/enzyme/~/jsdom/lib/jsdom.js
Module not found: Error: Cannot resolve module 'fs' in /Users/agoggin/www/vhosts/hammerhead/node_modules/enzyme/node_modules/jsdom/lib
 @ ./~/enzyme/~/jsdom/lib/jsdom.js 6:9-22

My webpack/karma config is pretty vanilla, but it'd help I can post that, too.

Environment bug

Most helpful comment

with react 15, I had the following error:

ERROR in ./~/enzyme/build/react-compat.js
Module not found: Error: Cannot resolve module 'react/addons' in /Users/eddywashere/Code/node/reactstrap/node_modules/enzyme/build
 @ ./~/enzyme/build/react-compat.js 37:16-39

here's my work around in my current webpack config:

webpackConfig.externals = {};
webpackConfig.externals['react/lib/ExecutionEnvironment'] = true;
webpackConfig.externals['react/lib/ReactContext'] = true;
webpackConfig.externals['react/addons'] = true;

All 73 comments

Hey @kgoggin, thanks for reporting the issue.

It'd be helpful if I could have a small repro of the issue... If there's a repo that I can pull down on to my own machine, that would work... or alternatively a gist link with the relevant files needed to reproduce, that would be helpful.

I haven't tried using the library with a webpack/karma project yet. My best guess is that webpack is building a bundle of your tests, which include reagent, which then include jsdom... and bundling jsdom and passing to a browser is probably a nightmare. Since you are only using shallow at the moment, you might consider just marking jsdom as external to webpack.

In the long term, I'd like to either:

  1. Have everything "just work" with a vanilla webpack / karma project
  2. Have some notes in the documentation regarding how to configure the project so it will work

Sure thing, @lelandrichardson. I just forked a boilerplate repo and added the dependency, and I'm getting the same error. https://github.com/kgoggin/react-es6-webpack-karma-boilerplate.

You should be able to just clone it, npm install, then npm run test and see the errors generated.

Webpack is definitely building a bundle of the tests, so it's definitely trying to include all of reagent's deps. Hadn't considered that about jsdom, I'm sure that's at least part of the problem. But, I think even if I externalized that one I'd still have issues with sinon and cheerio. I haven't dug into this project enough to see how/why you're using those, but I think either one of your two solutions would be fantastic. This looks like a really helpful utility and I'd love to get it working!

Thanks for taking a look!

I have the same problem@@

There's a couple of things going on here.

Reagent was not really designed to be "bundled", as there are some conditional requires. This is mostly done in order to be compatible with both react 0.13 and react 0.14.

The conditional requires are the errors / warnings you're seeing related to "react-dom/server" and "react-addons-test-utils" etc. (since that boilerplate is using react 0.13. However, karma/webpack seems to swallow those errors and continue on just fine.

The other issue (which is what is stopping phantomjs in it's tracks) is the bundling of sinon and jsdom.

The jsdom thing isn't really a problem, and you can just set jsdom as an external in webpack and all will work fine since you're using phantomJS.

The sinon thing i can't seem to figure out. Sinon seems to be incompatible with webpack's bundling due to some conditional requires that it's doing underneath.

We will probably end up removing sinon as a dependency entirely very soon ( https://github.com/airbnb/reagent/issues/44 ), so that's the good news. In the interim, I'm trying to figure out a way to get webpack to not choke on sinon by following some of the advice in this thread: https://github.com/webpack/webpack/issues/177

Adding this to your karma config should get you essentially to where I am:

    webpack: {
      externals: {
        "jsdom": "window",
        "cheerio": "window"
      },
    }

Still working on the sinon issue. I will keep you updated.

Also, it looks like this may not be an issue with Sinon 2.0: https://github.com/sinonjs/sinon/issues/830

Updating reagent to the npm prerelease of sinon ([email protected]) gets us over that hurdle. Now I'm looking at the following, which is a little odd as I have "react": "^0.14.0" in my package.json..

ERROR in ./~/reagent/build/react-compat.js
Module not found: Error: Cannot resolve module 'react/lib/ExecutionEnvironment' in .../react-redux-starter-kit/node_modules/reagent/build
 @ ./~/reagent/build/react-compat.js 22:2-43

Semi-related.. I previously worked around the webpack/sinon issue by installing karma-sinon and including sinon as a framework in karma which injected it into my tests so I didn't need to require it. (this didn't work once I was using reagent in the tests though)

@lecstor you should be able to get around that error by just adding react/lib/ExecutionEnvironment to the list of externals. Webpack is attempting to bundle this since there is a conditional require call to it (only get's called for React 0.13). After that, you should be good to go!

To fix this officially, I'm thinking it makes sense to just wait until we remove the sinon dependency entirely. After that, webpack should be workable by just making jsdom and cheerio externals...

@lelandrichardson thanks, yes, that did the trick.. on to the next (unrelated) issue..

and yes, not worth trying to fix something you plan to remove anyway. :+1:

Sinon 2.0 seems like it's somewhat abandoned, we came up with some other workarounds for it here: https://github.com/sinonjs/sinon/pull/600#issuecomment-159373985

Glad to see the dependency is being removed

thanks for that @MattKunze, that looks like a much simpler solution!

My final webpack config to get enzyme running:

module: {
    noParse: [
        /node_modules\/sinon\//,
    ]
},
resolve: {
    alias: {
        'sinon': 'sinon/pkg/sinon'
    }
},
externals: {
    'jsdom': 'window',
    'cheerio': 'window',
    'react/lib/ExecutionEnvironment': true
}

Related issues:

thanks @vieron for sharing your config, I've just ran into the same issue (using vanilla js). Maybe it should be somehow reflected in the docs/readme?

@vieron thanks it works

Thanks @vieron for sharing the webpack config. I am working on a PR that will knock a few of these things out, and will include a "guides" section in the docs that will cover getting enzyme working with webpack/karma as well as some other setups. No doubt the work in this issue has been helpful for this effort!

I tried @vieron config but the errors are still here. I'm using sinon and jsdom outside enzyme, maybe this could cause some conflict?

@vieron thanks for the config man!

My final solution is the same as @vieron except I didn't have to put cheerio or react/lib/ExecutionEnvironment in my config as externals (at least not yet).

@javascriptjedi this may be because you're using a different version (React 0.13?)

I'm on 0.14.3.

Any other possible solutions? I'm getting similar errors, tried @vieron's solution, but am still not able to get it to run.

I'm getting errors like:

WARNING in ./~/enzyme/~/sinon/lib/sinon.js
Critical dependencies:
40:25-32 require function is used in a way in which dependencies cannot be statically extracted
 @ ./~/enzyme/~/sinon/lib/sinon.js 40:25-32

WARNING in ./~/enzyme/~/sinon/lib/sinon/assert.js
Critical dependencies:
216:25-32 require function is used in a way in which dependencies cannot be statically extracted
 @ ./~/enzyme/~/sinon/lib/sinon/assert.js 216:25-32

WARNING in ./~/enzyme/~/sinon/lib/sinon/behavior.js
Critical dependencies:
362:25-32 require function is used in a way in which dependencies cannot be statically extracted
 @ ./~/enzyme/~/sinon/lib/sinon/behavior.js 362:25-32

for sinon, and for cheerio and jsdom as well.

I must have got it somewhere else, but I also have

          {
            test: /sinon\.js$/,
            loader: 'imports?define=>false,require=>false'
          }

as one of my webpack loaders.

Hmmm, thanks for this @lecstor. I just realized I was adding @vieron and your configurations to my general webpack.config.js file instead of defining them in my karma.conf.js under the webpack: {} hash.

Without @lecstor's snippet I get the tests to work, with one issue:

Module not found: Error: Cannot resolve module 'react/lib/ReactContext' in /Users/liorbrauer/dapulse/node_modules/enzyme/build

(with @lecstor's snippet, my tests don't run)

@liorbrauer just add 'react/lib/ReactContext' in externals section of config. Works for me.

@liorbrauer here is what I did to make it work with react 0.14: new webpack.IgnorePlugin(/react\/lib\/ReactContext/)

yes, same, my externals are currently:

      externals: {
        jsdom: 'window',
        cheerio: 'window',
        'react/lib/ExecutionEnvironment': true,
        'react/lib/ReactContext': 'window',
        'text-encoding': 'window'
      },

full config here.. https://github.com/lecstor/react-startup-starter/blob/master/karma.conf.js

@smacker @vyorkin @lecstor thank you all! :) that fixed my last error.

adding this here as it seems related.

I'm getting TypeError: _cheerio2.default.load is not a function when trying to render a wrapped node.

I've tried many variations but it's still entirely possible I'm just not doing things right.. any pointers much appreciated.

(I know it shouldn't be, but this feels like a Babel6 issue with the "default" thing in _cheerio2.default.load is not a function or is that something else?)

Minimal example which replicates my test and the error:

import React from 'react';
import tape from 'blue-tape';
import { shallow } from 'enzyme';

const Alert = ({ error }) => (<div>{error}</div>);
const LoginForm = ({ error }) => (<form> <Alert error={error} /> </form>);

tape.only('Minimal test - Component', test => {
  const wrapper = shallow(<LoginForm error="Something is not right" />);
  test.equal(wrapper.html(), '<form> <div>Something is not right</div> </form>', 'wrapper html');
  test.equal(wrapper.find('Alert').length, 1, 'node has one alert');
  test.equal(wrapper.find('Alert').text(), '<Alert />', 'Alert.text() is <Alert />');
  wrapper.find('Alert').render();
  test.end();
});
'TAP version 13'
'# Minimal test - Component'
'ok 1 wrapper html'
'ok 2 node has one alert'
'ok 3 Alert.text() is <Alert />'
'not ok 4 TypeError: _cheerio2.default.load is not a function'
'  ---'
'    operator: error'
'    expected: |-'
'      undefined'
'    actual: |-'
'      [TypeError: _cheerio2.default.load is not a function]'
'    stack: |-'
'      TypeError: _cheerio2.default.load is not a function'
'          at ShallowWrapper.render (http://localhost:9876/base/webpack.tests.js?362c41005884915a2a13ed60547e0655c6dcd42a:38454:36)'
'          at Test.<anonymous> (http://localhost:9876/base/webpack.tests.js?362c41005884915a2a13ed60547e0655c6dcd42a:62370:618)'
'          at Test.bound [as _cb] (http://localhost:9876/base/webpack.tests.js?362c41005884915a2a13ed60547e0655c6dcd42a:24629:33)'
'          at Test.run (http://localhost:9876/base/webpack.tests.js?362c41005884915a2a13ed60547e0655c6dcd42a:39234:35)'
'          at Test.bound [as run] (http://localhost:9876/base/webpack.tests.js?362c41005884915a2a13ed60547e0655c6dcd42a:24629:33)'
'          at next (http://localhost:9876/base/webpack.tests.js?362c41005884915a2a13ed60547e0655c6dcd42a:26135:16)'
'          at onNextTick (http://localhost:9876/base/webpack.tests.js?362c41005884915a2a13ed60547e0655c6dcd42a:19901:13)'
'          at Item.run (http://localhost:9876/base/webpack.tests.js?362c41005884915a2a13ed60547e0655c6dcd42a:326:15)'
'          at drainQueue (http://localhost:9876/base/webpack.tests.js?362c41005884915a2a13ed60547e0655c6dcd42a:296:43)'
'  ...'
''
'1..4'
'# tests 4'
'# pass  3'
'# fail  1'

@lecstor I'm not sure, but try this plugin: https://www.npmjs.com/package/babel-plugin-add-module-exports

thanks @smacker, I did have a go adding it to my karma webpack config, but it made no difference. I assume this is because Babel doesn't touch node_modules in my setup and the issue seems to be between enzyme and cheerio somehow. (I tried commenting out the node_modules exclude as well, but that was a complete fail).

I gave up on compiling tests with webpack, too many modules fail :disappointed: (sinon, mocha-jsdom, es6-promise…)

I've resolved for now by creating a test bootstrap file which requires the webpack bundle, and there I set a global variable for enzyme so I can use it inside my tests:

// bootstrap.js
const jsdom = require('jsdom').jsdom;

global.document = jsdom('<!DOCTYPE html><html><head></head><body></body></html>');
global.window = document.defaultView;
global.XMLHttpRequest = window.XMLHttpRequest;
global.navigator = window.navigator;

global.enzyme = require('enzyme');
// sometest.js
import expect, { createSpy } from 'expect';
import React from 'react';

import Conversation from 'components/Conversation';

describe('<Conversation />', () => {
    it('should render correctly', () => {

        ..........

        const wrapper = enzyme.shallow(<Conversation open={false} messages={messages} />);


        const icon = toggle.find('i');
        expect(icon.hasClass('fa-arrows-v')).toBe(true);

        .........
    });
});

The only downside is that the test script wich is getting quite complicated:

{
  "webpack-mocha": "SET NODE_ENV=test&& webpack --config webpack.mocha.config.js",
  "mocha-run": "mocha test\\bootstrap.js -w -R min",
  "test": "npm-run-all --parallel webpack-mocha mocha-run"
}

I needed to install npm-run-all to run the two scripts in parallel.

Hope this can help someone!

@ingro this is a great solution, thanks!

You can manage scripts by extracting Mocha options to a mocha.opts file and having a single webpack.config.js file (the default filename, so no --config necessary) which dynamically puts together a configuration based on NODE_ENV. Take a look at react-redux-starter-kit for possible solutions.

Thanks for the suggestion @silvenon , will check that out!

@lecstor did you ever resolve your issue? We've got the same problem and are having to revert to using ReactDOM.findDOMNode(component.node) at present...

well, no, I didn't, but you prompted me to have another go and my karma must be good (excuse the pun) because I think I've just worked it out..

If you have cheerio in externals, remove it.

      externals: {
        jsdom: 'window',
        // cheerio: 'window',
        'react/lib/ExecutionEnvironment': true,
        'react/lib/ReactContext': 'window',
        'text-encoding': 'window'
      },

in your loaders add..

          {
            test: /\.json$/,
            loader: 'json',
          },

my previous test case now parses for me.

Brill, thanks for the reply. Will give it a go myself...

It works! bellissimo, thanks a lot @lecstor

@smacker @lecstor babel-plugin-add-module-exports just adds module.exports = exports['default'], so it wouldn't solve the issue of _cheerio2.default being undefined...thank you guys for everything you've figured out so far though!

@smacker @lecstor Aha, I fixed the _sinon2.default issue with Babel 6 by putting sinon: 'sinon' in the webpack externals and putting node_modules/sinon/pkg/sinon.js in the files section of my karma.conf.js.

The reality is that a module consumer should never have to deal with babel's interop - so the proper thing to do for any module is make sure its "main" uses module.exports. If you find packages with that problem, it's a bug and I'd recommend filing it :-)

@ljharb good point. That's not the problem with sinon though, the problem with sinon is that Webpack can't statically analyze the way it (or some of its deps, I forget) uses require.

Browserify config in karma.conf.js

browserify: {
    debug: true,
    configure: function(bundle) {
        bundle.exclude('react/lib/ReactContext');<-- or whatever file is the error
    }
}

Then the bundle works. Still, it crashes in phantomjs when reaching jsdom. Hope #73 fixes this.

Hello, after trying for a while to get the tests "webpacked" with the different solutions proposed here, I am currently sticking with a "hack" that a coworker made.

Depending on what kind of loader you use in your components this might be useful, or not, for you.

Here is an example where he just "hacks" the Module.require because of the svg-sprite loader.
In this case you don't need to bundle anything and use the component directly in your tests.

if (!Module.touched) {
  const Require = Module.prototype.require
  Module.prototype.require = function (path) {
    if (path.indexOf('svg-sprite!') === 0) {
      return path.substr(11)
    }
    return Require.apply(this, arguments)
  }
  Module.touched = true
}

I believe the root issue and potential correct fix is described in #285. Enzyme is requiring internal React modules that only exist in React 0.13. If you're using a later version of React where they've removed these internals you're getting errors when they are required.

A temporary workaround is to install the empty npm module and alias these bad requires to empty objects:

webpack.config.js

alias: {
  'react/lib/ExecutionEnvironment': 'empty/object',
  'react/lib/ReactContext': 'empty/object',
}

Empty objects will be loaded in their place.

For me, the externals and the alias configurations didn't help resolve the errors. The only thing that helped was adding the following plugins:

new webpack.IgnorePlugin(/react\/lib\/ReactContext/),
new webpack.IgnorePlugin(/react\/lib\/ExecutionEnvironment/),

with react 15, I had the following error:

ERROR in ./~/enzyme/build/react-compat.js
Module not found: Error: Cannot resolve module 'react/addons' in /Users/eddywashere/Code/node/reactstrap/node_modules/enzyme/build
 @ ./~/enzyme/build/react-compat.js 37:16-39

here's my work around in my current webpack config:

webpackConfig.externals = {};
webpackConfig.externals['react/lib/ExecutionEnvironment'] = true;
webpackConfig.externals['react/lib/ReactContext'] = true;
webpackConfig.externals['react/addons'] = true;

adding
alias = {
'cheerio': 'cheerio/lib/cheerio'
...}
seemed to work for me.

echoing @eddywashere, got the same issue, looks like enzyme is thinking my React version to be 13, versus 15 which is what I have.
In enzyme/src/react-compact.js, line 16, "if (REACT013) {...}" is reached where it shouldn't.
The workaround works, but if would be nice to fix it.

Thanks everyone for suggestions here. I gave a talk recently and setting things up with Enzyme was my biggest concern for newbies (and intermediates like myself too), so I want to get this cleared up so I can submit a PR for the webpack guide.

Here's what I had to do in my webpack config for React 0.14 (coffeescript):

module:
    loaders: [... your loaders here, including one for ".json" for sinon to work]
    noParse: [
        /\/sinon\.js/
    ]
externals: {
    'cheerio': 'window'
    'react-dom': 'window'
    'react/lib/ExecutionEnvironment': true,
    'react/lib/ReactContext': true
}
resolve:
    extensions: [...your extensions here, including ".json" for sinon to work]
    alias:
        sinon: 'sinon/pkg/sinon'

@shawnxusy Note how I had to add react/lib/ExecutionEnvironment and react/lib/ReactContext, which is supposedly, according to the enzyme webpack guide, only needed for React 0.13. I think that's not really true. I have a theory as to why: Importantly, it's not a runtime thing, it's a build-time/webpack-time thing. Without those set as externals, webpack will complain with e.g. Module not found: Error: Cannot resolve module 'react/lib/ReactContext'. This is merely due to their presence (require statements) in enzyme/src/react-compat.js as you mentioned. However, if you put debug lines in the REACT013 section, you won't see it, but debug statements in the else condition you will see (note that to put debug statements, you'd need to put them in build/react-compat.js, not src/react-compat.js), proving that the code does know you are not using React 0.13.

However, with my above theory, I'm not sure why I did not need to declare as externals the recommended react-addons-test-utils and react-dom, which are also in react-compat.js. Does anyone know?

For React 15, eddywashere's solution worked for me.

Update: I changed my external of react-dom/server to just react-dom. I'm not sure why I needed react-dom/server at some point on another project (as in, what error I was getting that using that fixed), but if I have it in with my current project, calling a shallow wrapper's render() method gives me this error:

undefined is not a function (evaluating '(0, _reactCompat.renderToStaticMarkup)(n)')

Thus, since react-dom is what's recommended to have in, I'll use that (although it doesn't seem to be needed for render() to work).

Thanks @tylercollier , mine now works fine with React 0.15
My externals are now (for 0.15):

externals: {
'jsdom': 'window',
'react/lib/ReactContext': 'window',   
'react/lib/ExecutionEnvironment': true,    
'react/addons': true,  
},

And having json in loader and resolve.extensions.
Adding cheerio in externals is no longer needed and will rather break it.

To get chai-enzyme & cheerio working in the tests for Victory I had to follow the suggestions made by @lecstor - that is to say I added a json loader and 'text-encoding': 'window'. Using the webpack config suggested by @tylercollier our tests woud _run_, but whenever I attempted to use a chai-enzyme assertion, which calls cheerio internally, or I attempted to use cheerio directly, I would get an error like TypeError: '[object DOMWindow]' is not a function (evaluating '(0, _cheerio2.default)(this.wrapper.html())').

We're currently using react 0.14.x in our tests. Relevant sections of webpack config:

resolve: {
  // Need to include ".json" for cheerio to load
  extensions: ["", ".js", ".jsx", ".json"],
  alias: {
    sinon: "node_modules/sinon/pkg/sinon.js"
  }
},
externals: {
  "react/lib/ExecutionEnvironment": true,
  "react/lib/ReactContext": true,
  'text-encoding': 'window'
},
module: {
  noParse: [
    /\/sinon\.js/
  ],
  loaders: [
    {
      test: /\.json$/,
      loader: 'json',
    },
    {
      test: /\.jsx?$/,
      include: [SRC, TEST],
      loader: require.resolve("babel-loader")
    }
  ]
}

Hope this helps!

@shawnxusy Your solution worked for me with Enzyme and React 0.15

I had to combine @eddywashere's comment with @lecstor's to get it to work using React 15. (Remember to npm install --save json-loader!). Thanks guys!

Is this something that webpack can help with?

Just a fair warning, this doesn't appear to be webpack exclusive ... I stumbled upon this discussion by searching for the exact same error that I'm getting from my tape setup with browserify and browser-run:

browserify -i 'react/lib/ReactContext' -i 'react/lib/ExecutionEnvironment' -t babelify test/index.js | browser-run2 | faucet

This works fine and dandy with React 0.14.8, but 15+ boinks with the error you are all familiar with:

Error: Cannot find module 'react/addons' from 'node_modules/enzyme/build'

Figured I would piggyback here instead of start my own issue since it appears to be identical.

Resolved on React 15 by adding the following to webpack test config:

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

Too many old tests, which depends on global variables, fails after adding ExecutionEnvironment.

When using Karma and React 15+, in karma config file, add externals as follows:

const webpackConfig = require('./webpack.config');

module.exports = function (config) {
    config.set({
        frameworks: ['jasmine'],
        files: [
            'tests.bundle.js',
            './node_modules/promise-polyfill/promise.js',
            './node_modules/rx/dist/rx.all.js'
        ],
        preprocessors: {
            'tests.bundle.js': ['webpack']
        },
        webpack: {
            resolve: webpackConfig.resolve,
            module: webpackConfig.module,
            externals: {
                'jsdom': 'window',
                'cheerio': 'window',
                'react/lib/ExecutionEnvironment': true,
                'react/lib/ReactContext': true
            },
        },
        webpackServer: {
            noInfo: true
        },
        reporters: ['spec'],
        port: 8089,
        colors: true,
        logLevel: config.LOG_INFO,
        autoWatch: false,
        browsers: ['PhantomJS'],
        singleRun: true,
        reportSlowerThan: 500
    });
};

Using React 0.13.3, webpack is statically requiring the React 0.14 requires withinreact-compat.js. This produces the errors:

WARNING in ./~/enzyme/build/react-compat.js
Module not found: Error: Cannot resolve module 'react-dom' in /srv/backoffice/jenkins/workspace/Backoffice-CI-JS/node_modules/enzyme/build
 @ ./~/enzyme/build/react-compat.js 107:17-37

WARNING in ./~/enzyme/build/react-compat.js
Module not found: Error: Cannot resolve module 'react-addons-test-utils' in /srv/backoffice/jenkins/workspace/Backoffice-CI-JS/node_modules/enzyme/build
 @ ./~/enzyme/build/react-compat.js 123:18-52

ERROR in ./~/enzyme/build/react-compat.js
Module not found: Error: Cannot resolve module 'react-dom/server' in /srv/backoffice/jenkins/workspace/Backoffice-CI-JS/node_modules/enzyme/build
 @ ./~/enzyme/build/react-compat.js 114:58-85

This was fixed by updating the webpack karma config with:

  externals: {
    'react-dom/server': true,
    'react-addons-test-utils': true,
    'react-dom': true
  }

Besides using externals, this should also work and is arguably more explicit, since what you really want is to ignore the requires, instead of marking them as externally available.

If you are using React 0.14+

plugins: [
    new webpack.IgnorePlugin(/react\/addons/),
    new webpack.IgnorePlugin(/react\/lib\/ReactContext/),
    new webpack.IgnorePlugin(/react\/lib\/ExecutionEnvironment/)
]

If you are using React 0.13

plugins: [
    new webpack.IgnorePlugin(/react-dom/),
    new webpack.IgnorePlugin(/react-addons-test-utils/),
    new webpack.IgnorePlugin(/react-dom\/server/)
]

Note that cheerio is not in the list, it looks like it is required regardless now. The above configuration was tested on Webpack 2.

@wyuenho PRs to improve the guides are always appreciated.

@ljharb I've updated my comment above. Here's the PR that clarifies what the Webpack configs do.

Here are the changes that helped in my case. I'm using react 15.4.1

  resolve: {
    alias: {
      // Conditional requires workaround
      // https://github.com/sinonjs/sinon/issues/830
      'sinon': 'sinon/pkg/sinon'
    },
  },
  module: {
    noParse: [
      // Conditional requires workaround
      // https://github.com/sinonjs/sinon/issues/830
      /node_modules\/sinon\//,
    ],
  },
  externals: {
    // Conditional requires workaround
    // https://github.com/airbnb/enzyme/issues/47
    // https://github.com/airbnb/enzyme/blob/master/docs/guides/webpack.md
    'cheerio': 'window',
    'react-dom/server': 'window',
  },
  plugins: [
    // Conditional requires workaround
    // https://github.com/airbnb/enzyme/issues/47
    // https://github.com/airbnb/enzyme/blob/master/docs/guides/webpack.md
    new webpack.IgnorePlugin(/react\/addons/),
    new webpack.IgnorePlugin(/react\/lib\/ReactContext/),
    new webpack.IgnorePlugin(/react\/lib\/ExecutionEnvironment/)
  ]

I'm not sure which of those are necessary. Maybe it may be simplified.

Hope it helps.

@blainekasten I could give some guidance on maybe wrapping some of the complexities in a plugin for this use with webpack. Let me know if we can help.

@Vanuan Does it work for you without the externals?

@wyuenho I suppose IgnorePlugin and externals are interchangeable. The difference is that externals actually expect the externalized variable to be present in the global scope. While IgnorePlugin just leaves import/require as is.

Can you guys please add a global build? I have this same problem trying to build a AMD or UMD module to use in a "legacy" RequireJS environment.

Here's a reproduction using browserify: https://github.com/airbnb/enzyme/pull/861

^ Just run npm i && npm run build-global to get the error.

This is a long thread; it'd be helpful to restate the problems.

Thanks to @trusktr, we now have #861 as a repro example for browserify. Let's see if we can't figure out how to fix that, and then document it for users of browserify - if users of other setups could provide similar repro examples, that'd also be helpful.

Here's a PR that has a global (UMD) successfully built with browserify: https://github.com/airbnb/enzyme/pull/863. But I don't know if it has any bad sideeffects from excluding the things that it does.

I am able to confirm that a test similar to the following basic test (in my case) works when I use the UMD-version of enzyme built based on #863 (build/global.js):

fixture('<NumberInput />', function () {
    test('onChange', function () {
        const wrapper = shallow(
            <NumberInput disabled={false} value={0} />
        )

        assert.equal(wrapper.find('input').length, 1)
    });
});

I'm not sure if some other parts of the API might be broken based on what's excluded in #863, but for now I can make basic tests.

Is this still relevant with v3?

I don't think so. Closing. If anyone still has issues, feel free to reopen.

Was this page helpful?
0 / 5 - 0 ratings