Skip to content

Commit

Permalink
Rip out sinon, mocha, and jsdom dependencies
Browse files Browse the repository at this point in the history
This refactor addresses several issues regarding enzyme working in a variety of environments, and
the library just generally not making any assumptions about the environment that tests will be
run in.

For the most part, this amounts to:

- remove direct dependency on jsdom
- remove direct dependency on sinon
- remove assumed dependency on mocha

In addition to this, I would like to create several "example" projects that are some basic boilerplate
to getting enzyme up and running with some combination of bundler/test runner/etc.  These projects
can end up being devDependencies to enzyme and we can run their tests as part of our tests, which will
ensure that changes we make to enzyme will be compatible with environments we claim to support moving
forward.

Lastly, as a matter of organization, tests have been moved from `src/__tests__/*` to `tests/*`.

Left to do for this to be mergable is:

  [ ] Add a "guides" section in the docs explaining how to use enzyme in different environments
  [ ] Add example projects as dev dependencies, include their tests in enzyme's test script
  • Loading branch information
lelandrichardson committed Feb 7, 2016
1 parent ac165c8 commit 1105c81
Show file tree
Hide file tree
Showing 26 changed files with 393 additions and 289 deletions.
48 changes: 33 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,16 @@ If you are interested in using enzyme with custom Chai.js assertions and conveni
testing your React components, you can consider using [chai-enzyme](https://github.com/producthunt/chai-enzyme).


[Using Enzyme with Mocha](/docs/guides/mocha.md)
[Using Enzyme with Karma](/docs/guides/karma.md)
[Using Enzyme with Jasmine](/docs/guides/jasmine.md)
[Using Enzyme with Browserify](/docs/guides/browserify.md)
[Using Enzyme with WebPack](/docs/guides/webpack.md)
[Using Enzyme with JSDOM](/docs/guides/jsdom.md)
[Using Enzyme with React Native](/docs/guides/react-native.md)
[Using Enzyme with Jest](/docs/guides/jest.md)


### [Installation](/docs/installation/README.md)

To get started with enzyme, you can simply install it with npm:
Expand All @@ -46,6 +56,7 @@ Basic Usage
## [Shallow Rendering](/docs/api/shallow.md)

```jsx
import React from 'react';
import { shallow } from 'enzyme';
import sinon from 'sinon';

Expand Down Expand Up @@ -86,22 +97,14 @@ Read the full [API Documentation](/docs/api/shallow.md)



## [JSDOM Full Rendering](/docs/api/mount.md)
## [Full DOM Rendering](/docs/api/mount.md)

```jsx
import {
describeWithDOM,
mount,
spyLifecycle,
} from 'enzyme';

describeWithDOM('<Foo />', () => {
import React from 'react';
import sinon from 'sinon';
import { mount } from 'enzyme';

it('calls componentDidMount', () => {
spyLifecycle(Foo);
const wrapper = mount(<Foo />);
expect(Foo.prototype.componentDidMount.calledOnce).to.equal(true);
});
describe('<Foo />', () => {

it('allows us to set props', () => {
const wrapper = mount(<Foo bar="baz" />);
Expand All @@ -118,6 +121,13 @@ describeWithDOM('<Foo />', () => {
wrapper.find('button').simulate('click');
expect(onButtonClick.calledOnce).to.equal(true);
});

it('calls componentDidMount', () => {
sinon.spy(Foo.prototype, 'componentDidMount');
const wrapper = mount(<Foo />);
expect(Foo.prototype.componentDidMount.calledOnce).to.be.true;
Foo.prototype.componentDidMount.restore();
});

});
```
Expand All @@ -128,6 +138,7 @@ Read the full [API Documentation](/docs/api/mount.md)
## [Static Rendered Markup](/docs/api/render.md)

```jsx
import React from 'react';
import { render } from 'enzyme';

describe('<Foo />', () => {
Expand All @@ -148,9 +159,16 @@ describe('<Foo />', () => {
Read the full [API Documentation](/docs/api/render.md)


### [Future](/docs/future.md)
### Future

[Enzyme Future](/docs/future.md)


### Contributing

See the [Contributors Guide](/CONTRIBUTING.md)


### [Contributing](/CONTRIBUTING.md)

### License

Expand Down
9 changes: 8 additions & 1 deletion docs/README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
## Table of Contents

* [Introduction](/README.md)
* [Guides](/docs/guides.md)
* [Browserify](/docs/guides/browserify.md)
* [WebPack](/docs/guides/webpack.md)
* [JSDOM](/docs/guides/jsdom.md)
* [Jest](/docs/guides/jest.md)
* [Karma](/docs/guides/karma.md)
* [Mocha](/docs/guides/mocha.md)
* [React Native](/docs/guides/react-native.md)
* [Installation](/docs/installation/README.md)
* [Working with React 0.13.x](/docs/installation/react-013.md)
* [Working with React 0.14.x](/docs/installation/react-014.md)
* [Working with jsDom](/docs/installation/jsdom.md)
* [API Reference](/docs/api/README.md)
* [Shallow Rendering](/docs/api/shallow.md)
* [find(selector)](/docs/api/ShallowWrapper/find.md)
Expand Down
7 changes: 5 additions & 2 deletions docs/api/mount.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@ Full DOM rendering is ideal for use cases where you have components that may int
or may require the full lifecycle in order to fully test the component (ie, `componentDidMount`
etc.)

Full DOM rendering depends on a library called [jsdom](https://github.com/tmpvar/jsdom) which is
essentially a headless browser implemented completely in JS.
Full DOM rendering requires that a full DOM API be available at the global scope. This means that
it must be run in an environment that at least "looks like" a browser environment. If you do not
want to run your tests inside of a browser, the recommended approach to using `mount` is to depend
on a library called [jsdom](https://github.com/tmpvar/jsdom) which is essentially a headless browser
implemented completely in JS.

```jsx
import { mount } from 'enzyme';
Expand Down
13 changes: 7 additions & 6 deletions docs/future.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,6 @@ There are several things we'd like to address with Enzyme that often get asked.
of projects that we plan on addressing in the near future:


#### React Native Support

We would like to have enzyme provide full support for react components created with React Native,
and potentially some RN-specific methods to facilitate testing there.


#### Improved CSS Selector Support

Currently, "hierarchical" CSS selectors are not supported in Enzyme. That means that the only CSS
Expand All @@ -25,3 +19,10 @@ we would like to provide a more complete subset of all valid CSS selectors.
Event simulation is limited for Shallow rendering. Event propagation is not supported, and one must
supply their own event objects. We would like to provide tools to more fully simulate real
interaction.


### Improved Keyboard + Mouse Simulation

Many react components involve simulating form input or complex mouse interaction. Simulating this
using the event simulation API that Enzyme provides is cumbersome and impractical. We are looking for
an expressive way to solve this problem, even if it is a library that lives outside of enzyme.
9 changes: 9 additions & 0 deletions docs/guides.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Enzyme Guides

- [*Using Enzyme with Browserify*](guides/browserify.md)
- [*Using Enzyme with WebPack*](guides/webpack.md)
- [*Using Enzyme with JSDOM*](guides/jsdom.md)
- [*Using Enzyme with React Native*](guides/react-native.md)
- [*Using Enzyme with Jest*](guides/jest.md)
- [*Using Enzyme with Karma*](guides/karma.md)
- [*Using Enzyme with Mocha*](guides/mocha.md)
38 changes: 38 additions & 0 deletions docs/guides/browserify.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Using Enzyme with Browserify

If you are using a test runner that runs code in a browser-based environment, you may be using
[browserify]() in order to bundle your React code.

Browserify uses static analysis to create a dependency graph at build-time of your source code to
build a bundle. Enzyme has a hand full of conditional `require()` calls in it in order to remain
compatible with React 0.13 and React 0.14.

Unfortunately, these conditional requires mean there is a bit of extra setup with bundlers like
browserify.

In your browserify configuration, you simply need to make sure that the following two files are
labeled as "external", which means they will be ignored:

```
react/lib/ReactContext
react/lib/ExecutionEnvironment
```

Here is an example piece of configuration code marking these as external:

```js
var browserify = require('browserify');

var b = browserify();

// make sure to mark these as external!
b.external('react/lib/ReactContext');
b.external('react/lib/ExecutionEnvironment');

// the rest of your browserify configuration
```


## Example Projects

- [enzyme-example-karma](https://github.com/lelandrichardson/enzyme-example-karma)
32 changes: 32 additions & 0 deletions docs/guides/jest.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Using Jest with Enzyme

If you are using Jest with enzyme and using Jest's "automocking" feature, you will need to mark
several modules to be unmocked in your `package.json`:

```js
/* package.json */

"jest": {
"scriptPreprocessor": "<rootDir>/node_modules/babel-jest",
"unmockedModulePathPatterns": [
"react",
"react-dom",
"react-addons-test-utils",
"fbjs",
"enzyme",
"cheerio",
"htmlparser2",
"underscore",
"lodash",
"domhandler",
"object.assign",
"define-properties",
"function-bind",
"object-keys"
]
}
```

## Example Projects

- [enzyme-example-ject](https://github.com/lelandrichardson/enzyme-example-jest)
98 changes: 98 additions & 0 deletions docs/guides/jsdom.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# Using Enzyme with JSDOM

JSDOM is a JavaScript based headless browser that can be used to create a realistic testing environment.

Since enzyme's [`mount`](../api/mount.md) API requires a DOM, JSDOM is required in order to use
`mount` if you are not already in a browser environment (ie, a Node environment).

For the best experience with enzyme, it is recommended that you load a document into the global
scope *before* requiring React for the first time. It is very important that the below script
gets run *before* React's code is run.

As a result, a standalone script like the one below is generally a good approach:

```js
/* setup.js */

var jsdom = require('jsdom').jsdom;

var exposedProperties = ['window', 'navigator', 'document'];

global.document = jsdom('');
global.window = document.defaultView;
Object.keys(document.defaultView).forEach((property) => {
if (typeof global[property] === 'undefined') {
exposedProperties.push(property);
global[property] = document.defaultView[property];
}
});

global.navigator = {
userAgent: 'node.js'
};

documentRef = document;
```


## `describeWithDOM` API and clearing the document after every test

In previous versions of enzyme, there was a public `describeWithDOM` API which loaded in a new
JSDOM documnent into the global namespace before every test, ensuring that tests were deterministic
and did not have side-effects.

This approach is no longer recommended. React's source code makes several assumptions about the
environment it is running in, and one of them is that the `global.document` that is found at
"require time" is going to be the one and only document it ever needs to worry about. As a result,
this type of "reloading" ends up causing more pain than it prevents.

It is important, however, to make sure that your tests using the global DOM APIs do not have leaky
side-effects which could change the results of other tests. Until there is a better option, this is
left to you to ensure.


## JSDOM + Mocha

When testing with JSDOM, the `setup.js` file above needs to be run before the test suite runs. If
you are using mocha, this can be done from the command line using the `--require` option:

```bash
mocha --require setup.js --recursive path/to/test/dir
```


## Node.js Compatibility

Jsdom requires node 4 or above. As a result, if you want to use it with `mount`, you will need to
make sure node 4 or iojs is on your machine. If you are stuck using an older version of Node, you
may want to try using a browser-based test runner such as [Karma](../guides/karma.md).


### Switching between node versions

Some times you may need to switch between different versions of node, you can use a CLI tool called
`nvm` to quickly switch between node versions.

To install NVM:

```bash
brew install nvm
nvm install 4
```

Now your machine will be running Node 4. You can use the `nvm use` command to switch between the two
environments:

```bash
nvm use 0.12
```

```bash
nvm use 4
```



## Example Projects

- [enzyme-example-mocha](https://github.com/lelandrichardson/enzyme-example-mocha)
59 changes: 59 additions & 0 deletions docs/guides/karma.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# Using Enzyme with Karma



## Enzyme + Karma + Webpack

See the [webpack guide](webpack.md).

```js
/* karma.conf.js */
browserify: {
debug: true,
transform: [
['babelify', { presets: ['airbnb'] }]
],
configure: function(bundle) {
bundle.on('prebundle', function() {
bundle.external('react/lib/ReactContext');
bundle.external('react/lib/ExecutionEnvironment');
});
}
},
```

## Enzyme + Karma + Browserify

See the [browserify guide](browserify.md).


```js
/* karma.conf.js */

webpack: { //kind of a copy of your webpack config
devtool: 'inline-source-map', //just do inline source maps instead of the default
module: {
loaders: [
{
test: /\.js$/,
exclude: /\/node_modules\//,
loader: 'babel',
query: {
presets: ['airbnb']
}
}
]
},
externals: {
'cheerio': 'window',
'react/lib/ExecutionEnvironment': true,
'react/lib/ReactContext': true
}
},
```


## Example Projects

- [enzyme-example-karma](https://github.com/lelandrichardson/enzyme-example-karma)
- [enzyme-example-karma-webpack](https://github.com/lelandrichardson/enzyme-example-karma-webpack)
Loading

0 comments on commit 1105c81

Please sign in to comment.