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

Use enzyme in tests #1481

Closed
gaearon opened this issue Mar 6, 2016 · 31 comments
Closed

Use enzyme in tests #1481

gaearon opened this issue Mar 6, 2016 · 31 comments

Comments

@gaearon
Copy link
Contributor

gaearon commented Mar 6, 2016

We should start using enzyme in component tests. It is great and the community seems to have converged on it. We should migrate all our existing tests from ReactTestUtils to enzyme, and use it for any new component tests.

I don’t plan to work on this, but if you’d like, please leave a comment stating your intention, and then send a PR when you have something to show so we keep a conversation. If you feel you don’t have the time, don’t worry—just let us know so another person can pick up the task.

Help wanted 😉

@fshowalter
Copy link
Contributor

I'll take it.

@mwilc0x
Copy link
Contributor

mwilc0x commented Mar 6, 2016

I've been working on updating the todomvc example. That example had some existing integration tests. I haven't had the opportunity to try enzyme yet. I can work on converting those existing tests over to enzyme.

@gaearon
Copy link
Contributor Author

gaearon commented Mar 6, 2016

@fshowalter

Thanks, please do! It seems that counter example is the best candidate right now. We plan to completely replace todomvc so it might not be worth trying there (and @mjw56 plans to take care of it anyway). Please send a PR after you’ve done with counter and we can figure out next steps.

@gaearon gaearon closed this as completed in 17ed918 Mar 6, 2016
gaearon added a commit that referenced this issue Mar 6, 2016
@gaearon gaearon reopened this Mar 6, 2016
@gaearon
Copy link
Contributor Author

gaearon commented Mar 6, 2016

@fshowalter

Thank you for the counter update! If you’d like, feel free to add enzyme tests to either of these examples:

They currently have no component tests at all.

@fshowalter
Copy link
Contributor

Will do.

@borisyankov
Copy link

Hey I am interested in adding enzyme tests too to the projects with none. May be I'll start with the real world one?

@gaearon
Copy link
Contributor Author

gaearon commented Mar 6, 2016

@fshowalter @borisyankov Please work it out between yourselves 😉

@fshowalter
Copy link
Contributor

@borisyankov real world is all yours 😉

@fshowalter
Copy link
Contributor

@gaearon did you want to keep the tests under /test or colocate them with the source in a tests folder ala React?

@gaearon
Copy link
Contributor Author

gaearon commented Mar 6, 2016

I would keep them under /test so we don’t need to change all other projects. We can rearrange later if we desire so.

@fshowalter
Copy link
Contributor

Sounds good.

On Sun, Mar 6, 2016 at 9:56 AM Dan Abramov notifications@github.com wrote:

I would keep them under /test so we don’t need to change all other
projects. We can rearrange later if we desire so.


Reply to this email directly or view it on GitHub
#1481 (comment).

@tomchentw
Copy link

Quick question here. Is there any codemod for transitioning from ReactTestUtils to enzyme? I thought it would be nice to have one to automate this procedure and benefits the community.

@mwilc0x
Copy link
Contributor

mwilc0x commented Mar 8, 2016

@tomchentw I don't think so, that would be cool though

I didn't see anyone mention todos, so I think I will work on adding those.

@duro
Copy link

duro commented Mar 8, 2016

I would love to see how one tests a Container Component with Enzyme. What is the best way to test that actions are called on certain events, etc.

timdorr added a commit that referenced this issue Mar 8, 2016
…ing_cart_example

add shopping cart example tests (for #1481)
@borisyankov
Copy link

@duro you can use sinon.js to 'spy' on a mock store.

@duro
Copy link

duro commented Mar 8, 2016

@borisyankov I can't seem to get the component to mount at all. Even using the <Provider /> component and giving it a fake store.

Here is the test I wrote:

import React from 'react';
import { mount } from 'enzyme';
import { expect } from 'chai';
import { Provider } from 'react-redux';
import { browserHistory } from 'react-router';
import createStore from 'redux/create';
import ApiClient from 'helpers/ApiClient';
import App from './App';
import sinon from 'sinon';

const client = new ApiClient();

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

  it('renders component', () => {
    const store = createStore(browserHistory, client);
    const onLayoutChange = sinon.spy();
    const renderer = mount(
      <Provider store={store} key="provider">
        <App layoutChange={onLayoutChange} />
      </Provider>
    );

    console.log(renderer.html());
  });

});

That console.log outputs this: LOG: '<div><div></div></div>'

That definitely not what it should be outputting, and lets me test nothing about the component.

Here is the component I am trying to test:

import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';
import { layoutChange } from 'redux/modules/layout';
import styles from './App.less';
import MainNav from './components/MainNav';

@connect(
  state => ({
    layout: state.layout
  }),
  { layoutChange }
)
export default class App extends Component {

  static propTypes = {
    children: PropTypes.object,
    layoutChange: PropTypes.func.isRequired
  }

  componentDidMount() {
    this.calculateLayout();
    window.addEventListener('resize', this.calculateLayout.bind(this));
  }

  componentWillUnmount() {
    window.removeEventListener('resize', this.calculateLayout.bind(this));
  }

  calculateLayout() {
    const isIOS = /(iPad|iPhone|iPod)/g.test( window.navigator.userAgent );
    this.props.layoutChange({
      initialLoad: true,
      // navHeight: $('#main_nav').height(),
      notIOS: !isIOS,
      window: {
        width: window.innerWidth,
        height: window.innerHeight
      }
    });
  }

  render() {
    return (
      <div className={styles.container}>
        <MainNav />
        {this.props.children}
      </div>
    );
  }
}

@borisyankov
Copy link

I would suggest you test a component separately from a store.
This comes very naturally to React and Redux as most (or all) of your components will be pure functions - they get their input as parameters.

For example, you can take out the isIOS function in a separate module, and test only it.
You can also render your component and pass props manually (not from the real store)
And test the store totally separately from the component itself.

What you are trying to do, is close to systems or integration testing.
You might need jsdom or even karma, if you are trying to test overall system (for example window and api like localStorage are probably not available to you)

@duro
Copy link

duro commented Mar 8, 2016

I am using Karma, and I would like some ability to do some more integration
level testing.

On Tue, Mar 8, 2016 at 2:21 AM, Boris Yankov notifications@github.com
wrote:

I would suggest you test a component separately from a store.
This comes very naturally to React and Redux as most (or all) of your
components will be pure functions - they get their input as parameters.

For example, you can take out the isIOS function in a separate module, and
test only it.
You can also render your component and pass props manually (not from the
real store)
And test the store totally separately from the component itself.

What you are trying to do, is close to systems or integration testing.
You might need jsdom or even karma, if you are trying to test overall
system (for example window and api like localStorage are probably not
available to you)


Reply to this email directly or view it on GitHub
#1481 (comment).

gaearon added a commit that referenced this issue Mar 8, 2016
…view_example

add tree view example tests (for #1481)
@wharsojo
Copy link

Hi @duro , here is what I did if I want to use enzyme - mount into my test

import jsdom from 'jsdom';
global.document = jsdom.jsdom('<div id="container"/>');
global.window   = document.defaultView;
global.navigator= window.navigator;

// these imports place it after jsdom: https://github.com/airbnb/enzyme/issues/58
import React from 'react';
import test from 'tape';
import { mount } from 'enzyme';

test('<Sample/>', t => {
    var Sample = React.createClass({
        displayName: 'Sample',
        render: function() {
            return <div>
                    <h1 className='cblue'>My Component</h1>
                </div>;
        }
    });
    var wrapper= mount(<Sample/>);
    var $ = wrapper.find('.cblue');
    $.simulate('click');
    t.equal( /*..test uquality..*/ );
    t.end();
});

@duro
Copy link

duro commented Mar 10, 2016

@wharsojo this still doesn't get me there. I'm trying test react-redux connected containers.

@fshowalter
Copy link
Contributor

@gaearon do you want tests for the async example too?

@gaearon
Copy link
Contributor Author

gaearon commented Mar 14, 2016

@fshowalter Yes!

@borisyankov
Copy link

@gaearon The root reducer in real-world example does export only the combineReducers output.
In my own code I usually export the other reducers too, so I can test them separately.
What do you think about me adding 'export' to the 'entities', 'pagination' and 'errorMessage' ?

@fshowalter
Copy link
Contributor

@gaearon done in #1525.

@montogeek
Copy link

montogeek commented Apr 14, 2016

@fshowalter @gaearon Why if I add expect(p.text()).toMatch(/^Clicked: 1 times/) to https://github.com/reactjs/redux/blob/master/examples/counter/test/components/Counter.spec.js#L32 fails?

1) Counter component first button should call onIncrement:
     Error: Expected 'Clicked: 0 times + - Increment if odd Increment async' to match /^Clicked: 1 times/
      at assert (node_modules/expect/lib/assert.js:22:9)
      at Expectation.toMatch (node_modules/expect/lib/Expectation.js:140:28)
      at Context.<anonymous> (Counter.spec.js:34:22)

@gaearon
Copy link
Contributor Author

gaearon commented Apr 14, 2016

onIncrement is not a real action creator—it’s just a spy. There is no store, so it keeps saying Clicked: 0 times (rather than 1 as you expect).

@montogeek
Copy link

@gaearon Thanks :) How could I integrate the store? I think is a best test rather than check a function is called.

@jasan-s
Copy link

jasan-s commented May 13, 2016

Currently i have been using the following code in test_helper(see pic) , for TDD Redux and react components. But if i want to switch to airbnb Enzyme would this file be not required? I'm new to TDD so any help will be greatly appreciated.
test_helper

@colinlmcdonald
Copy link

are there any other examples that you were looking to have tests added for?

@borisyankov
Copy link

I have written tests for Real-World example. Will do a PR soon.
Not sure what else remains not covered.

@timdorr
Copy link
Member

timdorr commented Jan 5, 2017

Given that we've since switched over to Jest and it has first-class support for snapshots from react-test-renderer, I'm going to close this one out. I'll open up a new issue to track moving to react-test-renderer instead and to add some snapshot tests into the mix.

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

No branches or pull requests