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

Rip out sinon & mocha into separate modules #60

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,5 @@ node_modules
.idea

/build
packages/*/build
_book
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ node_js:
before_install:
- 'if [ "${TRAVIS_NODE_VERSION}" != "0.9" ]; then case "$(npm --version)" in 1.*) npm install -g npm@1.4.28 ;; 2.*) npm install -g npm@2 ;; esac ; fi'
- 'if [ "${TRAVIS_NODE_VERSION}" != "0.6" ] && [ "${TRAVIS_NODE_VERSION}" != "0.9" ]; then npm install -g npm; fi'
before_script: "sh install-relevant-react.sh"
before_script: "sh scripts/install-relevant-react.sh"
script:
- 'if [ "${TRAVIS_NODE_VERSION}" = "4.2" ]; then npm run lint && npm run travis ; elif [ "${TRAVIS_NODE_VERSION}" = "0.12" ]; then npm run travis ; else npm test ; fi'
after_script:
Expand Down
31 changes: 18 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ compatible with all major test runners and assertion libraries out there. The do
examples for enzyme use [mocha](https://mochajs.org/) and [chai](http://chaijs.com/), but you
should be able to extrapolate to your framework of choice.

[Using Enzyme with Mocha](/docs/guides/mocha.md)
[Using Enzyme with Karma](/docs/guides/karma.md)
[Using Enzyme with Jasmine](/docs/guides/jasmine.md)



### [Installation](/docs/installation/README.md)
Expand Down Expand Up @@ -42,6 +46,7 @@ Basic Usage
## [Shallow Rendering](/docs/api/shallow.md)

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

describe('<MyComponent />', () => {
Expand Down Expand Up @@ -81,22 +86,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.be.true;
});
describe('<Foo />', () => {

it('allows us to set props', () => {
const wrapper = mount(<Foo bar="baz" />);
Expand All @@ -113,6 +110,13 @@ describeWithDOM('<Foo />', () => {
wrapper.find('button').simulate('click');
expect(onButtonClick.calledOnce).to.be.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 @@ -123,6 +127,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 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 browswer, 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
21 changes: 21 additions & 0 deletions docs/guides/mocha.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Using Enzyme with Mocha

```bash
npm i --save-dev enzyme-mocha
```

```jsx
import { mount } from 'enzyme';
import { describeWithDOM } from 'enzyme-mocha';

describe('<Foo />', () => {

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

});

```
29 changes: 0 additions & 29 deletions docs/installation/jsdom.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,32 +26,3 @@ nvm use 0.12
```bash
nvm use 4
```

### Preventing tests from failing on old versions

If you are worried about tests not passing on versions of node that don't support jsdom, Enzyme
comes with a helper function to wrap your tests in a safety layer such that any tests written
inside of that function will be skipped if jsdom is not available. (Note that this is for mocha
only).

```jsx
import { mount, shallow } from 'enzyme';

describe('MyComponent', () => {
describeWithDOM('interaction', () => {
// these tests will get skipped if jsdom is not available...
it('should do something', () => {
const wrapper = mount(<MyComponent />);
// ...
});
});
describe('non-interaction', () => {
// these tests will always run
it('should do something', () => {
const wrapper = shallow(<MyComponent />);
// ...
});
});
});

```
24 changes: 13 additions & 11 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,15 @@
"postversion": "git push && git push --tags && npm run clean && npm run docs:publish",
"version": "npm run build",
"clean": "rimraf build",
"lint": "eslint src/**",
"test": "mocha --compilers js:babel/register --recursive src/**/__tests__/*.js",
"lint": "eslint src/** packages/**/src/**",
"check": "npm run lint && npm run test:all",
"build": "babel src --out-dir build",
"test:watch": "mocha --compilers js:babel/register --recursive src/**/__tests__/*.js --watch",
"build": "npm run build:core && npm run build:packages",
"build:core": "babel src --out-dir build",
"build:packages": "bash ./scripts/build-packages.sh",
"test": "npm run test:core && npm run test:packages",
"test:core": "mocha --compilers js:babel/register test/*.js",
"test:packages": "bash ./scripts/test-packages.sh",
"test:watch": "mocha --compilers js:babel/register test/*.js packages/**/test/*.js --watch",
"test:all": "npm run react:13 && npm test && npm run react:14 && npm test",
"react:clean": "rimraf node_modules/react node_modules/react-dom node_modules/react-addons-test-utils",
"react:13": "npm run react:clean && npm i react@0.13",
Expand All @@ -23,7 +27,7 @@
"docs:build": "npm run docs:prepare && gitbook build",
"docs:watch": "npm run docs:prepare && gitbook serve",
"docs:publish": "npm run docs:clean && npm run docs:build && cd _book && git init && git commit --allow-empty -m 'update book' && git fetch https://github.com/airbnb/enzyme.git gh-pages && git checkout -b gh-pages && git add . && git commit -am 'update book' && git push https://github.com/airbnb/enzyme.git gh-pages --force",
"travis": "istanbul cover _mocha -- --compilers js:babel/register --recursive src/**/__tests__/*.js"
"travis": "istanbul cover _mocha -- --compilers js:babel/register test/*.js packages/**/test/*.js"
},
"repository": {
"type": "git",
Expand All @@ -47,7 +51,6 @@
"license": "MIT",
"dependencies": {
"cheerio": "^0.19.0",
"sinon": "^1.15.4",
"underscore": "^1.8.3"
},
"devDependencies": {
Expand All @@ -60,14 +63,13 @@
"eslint-plugin-react": "^3.8.0",
"gitbook-cli": "^1.0.0",
"istanbul": "^0.4.0",
"jsdom": "^6.1.0",
"mocha": "^2.2.5",
"rimraf": "^2.4.3"
"mocha-jsdom": "^1.0.0",
"rimraf": "^2.4.3",
"sinon": "^1.15.4"
},
"peerDependencies": {
"react": "0.13.x || 0.14.x"
},
"optionalDependencies": {
"jsdom": "^6.1.0",
"mocha-jsdom": "^1.0.0"
}
}
1 change: 1 addition & 0 deletions packages/enzyme-mocha/.npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Left empty in order to include the build directory for npm publish
25 changes: 25 additions & 0 deletions packages/enzyme-mocha/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"name": "enzyme-mocha",
"version": "1.1.0",
"description": "Make Mocha and Enzyme play nice",
"main": "build/index.js",
"scripts": {
"build": "babel src --out-dir build",
"test": "mocha --compilers js:babel/register"
},
"repository": "https://github.com/airbnb/enzyme/tree/master/packages/enzyme-mocha",
"keywords": [
"mocha",
"enzyme"
],
"author": "Leland Richardson <leland.richardson@airbnb.com>",
"license": "MIT",
"dependencies": {
"jsdomify": "^1.0.2"
},
"peerDependencies": {
"react": "0.13.x || 0.14.x",
"mocha": ">= 2.0.0",
"enzyme": "^1.1.0"
}
}
33 changes: 33 additions & 0 deletions packages/enzyme-mocha/src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
let jsdomify;

try {
jsdomify = require('jsdomify');
jsdomify.create();
require('react'); // require react explicitly after jsdomify.create() has been called
jsdomify.destroy();
} catch (e) {
// jsdom is not supported
}

export function jsdomSetup() {
if (!jsdomify) return;
jsdomify.create();
}

export function jsdomTeardown() {
if (!jsdomify) return;
jsdomify.destroy();
}

export function describeWithDOM(a, b) {
describe('(uses jsdom)', () => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what happens when this is imported outside a test context, and then cached with the global describe set to undefined? I think perhaps this export may need to either take describe as an argument, or, actually be a function that takes describe and returns describeWithDOM?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we aren't caching describe anywhere? Every time describeWithDOM is called, it uses the describe that is in the global namespace.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the function retains a lexical reference to the one that's in the global namespace at the moment the function is defined, it's not freshly looked up. do you mean this to be global.describe then?

if (typeof jsdom === 'function') {
beforeEach(jsdomSetup);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these globals are also implicitly depended on

afterEach(jsdomTeardown);
describe(a, b);
} else {
// if jsdom isn't available, skip every test in this describe context
describe.skip(a, b);
}
});
}
3 changes: 3 additions & 0 deletions packages/enzyme-mocha/test/jsdom-spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
describe('jsdom', () => {
it.skip('TODO: set up tests');
});
1 change: 1 addition & 0 deletions packages/enzyme-sinon/.npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Left empty in order to include the build directory for npm publish
25 changes: 25 additions & 0 deletions packages/enzyme-sinon/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"name": "enzyme-sinon",
"version": "1.1.0",
"description": "Make Sinon and Enzyme play nice",
"main": "build/index.js",
"scripts": {
"build": "babel src --out-dir build",
"test": "mocha --compilers js:babel/register"
},
"repository": "https://github.com/airbnb/enzyme/tree/master/packages/enzyme-mocha",
"keywords": [
"sinon",
"enzyme"
],
"author": "Leland Richardson <leland.richardson@airbnb.com>",
"license": "MIT",
"dependencies": {
"sinon": "^1.17.2"
},
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should have a peerDep of enzyme itself

"peerDependencies": {
"react": "0.13.x || 0.14.x",
"mocha": ">= 2.0.0",
"enzyme": "^1.1.0"
}
}
20 changes: 20 additions & 0 deletions packages/enzyme-sinon/src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import Sinon from 'sinon';
import onPrototype from './onPrototype';

export let sinon = Sinon.sandbox.create();

export function spySetup() {
sinon = Sinon.sandbox.create();
}

export function spyTearDown() {
sinon.restore();
}

export function spyLifecycle(Component, sinonInstance = sinon) {
onPrototype(Component, (proto, name) => sinonInstance.spy(proto, name));
}

export function spyMethods(Component, sinonInstance = sinon) {
onPrototype(Component, null, (proto, name) => sinonInstance.spy(proto, name));
}
25 changes: 25 additions & 0 deletions packages/enzyme-sinon/src/onPrototype.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
export default function onPrototype(Component, lifecycle, method) {
const proto = Component.prototype;
Object.getOwnPropertyNames(proto).forEach((name) => {
if (typeof proto[name] !== 'function') return;
switch (name) {
case 'componentDidMount':
case 'componentWillMount':
case 'componentDidUnmount':
case 'componentWillUnmount':
case 'componentWillReceiveProps':
case 'componentDidUpdate':
case 'componentWillUpdate':
case 'shouldComponentUpdate':
case 'render':
if (lifecycle) lifecycle(proto, name);
break;
case 'constructor':
// don't spy on the constructor, even though it shows up in the prototype
break;
default:
if (method) method(proto, name);
break;
}
});
}
31 changes: 31 additions & 0 deletions packages/enzyme-sinon/test/onPrototype-spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { expect } from 'chai';
import sinon from 'sinon';
import onPrototype from '../src/onPrototype';

describe('onPrototype', () => {

it('makes the expected calls', () => {

class Foo {
a() {}
b() {}
componentDidUpdate() {}
}

const lifecycleSpy = sinon.spy();
const methodSpy = sinon.spy();

onPrototype(Foo, lifecycleSpy, methodSpy);

expect(lifecycleSpy.callCount).to.equal(1);
expect(lifecycleSpy.args[0][0]).to.equal(Foo.prototype);
expect(lifecycleSpy.args[0][1]).to.equal('componentDidUpdate');

expect(methodSpy.callCount).to.equal(2);
expect(methodSpy.args[0][0]).to.equal(Foo.prototype);
expect(methodSpy.args[0][1]).to.equal('a');
expect(methodSpy.args[1][1]).to.equal('b');

});

});
10 changes: 10 additions & 0 deletions scripts/build-packages.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/usr/bin/env zsh

# die on error
setopt -e

for pkg in packages/*/ ; do
pushd ${pkg} > /dev/null
npm run build
popd > /dev/null
done
File renamed without changes.
Loading