integration tests for react redux redux-saga
Asked Answered
E

3

7

I have a project structure like this:

app/
  global/
    styles/
    components/
  scenes/
    Home/
      actions.js
      constants.js
      index.jsx
      reducer.js
      sagas.js
      styles.styl
      index.spec.jsx
    some-other-scene/
      actions.js
      constants.js
      index.jsx
      reducer.js
      sagas.js
      styles.styl
      index.spec.jsx

so I have no problem with unit test with this structure, but I'm pretty confused as to how to structure integration test. For my unit tests I am exporting each scene component as a class

export class SomeComponent extends Component {}

and as a redux connected component

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(SomeComponent)

So for the fist style of export (the class) I am unit testing it, but for the second way (the connected component way) I am unsure how to approach this specifically how to do integration testing in react/redux. I've searched the internet about this, but nothing that is close to this structure.

So:

  1. is integration testing in react/redux/middleware (in this case redux saga) how one component integrates with redux and middleware.
  2. Or is it about how the whole app works with all the components mounted?
  3. if it's #1 does that mean each component should have a single integration test file that tests how the component integrates with redux and middleware or if it's #2 then is it one test file that tests all components as one app?

also, if it's #1 then how should I test routes via react router?

Exist answered 12/7, 2018 at 0:36 Comment(3)
#2 is closer but not quite correctJaleesa
@AluanHaddad so would that mean that #1 is also unit testing?Exist
because it seems like knowing if one component can complete the redux/middleware lifecycle (call action, fetch data, pass to reducer, to store, then to the component) is like integrationExist
L
2

In the case of your example, what we do is export mapStateToProps and mapDispatchToProps and we write unit tests for those (when they are not trivial).

I suppose you already unit test your action creators, sagas and reducers on their own.

What's left as far as integration goes? You might want to mount the components in the context of a real store, to see if they react correctly to mutations of the redux store and whether they dispatch the correct actions or not. In my project, we use end-to-end browser automation tests to verify things like this.

Lowland answered 19/7, 2018 at 22:4 Comment(2)
This is what I do too. Just unit test each individual piece and then write automated end-to-end tests. Testing the "integration" of your connected component is basically just testing that react-redux is working. It's not worth the effort to write tests for dependencies. Test your own code and be careful when upgrading dependency versions.Confluence
yeah, that's what I was thinking in terms of testing the redux life cycle for an individual component. It seemed like it would be a good idea, but always gave me that feeling of testing 3rd party code (one of my golden rules: a 3rd party is responsible for testing their own crap)Exist
M
0

Ok this is one way to test your components that use Redux. Using storybook to demonstrate.
First you need to accept the initial state when you are configuring the store:

import { createStore, applyMiddleware } from 'redux';
import rootReducer from './combineReducers';
import thunk from 'redux-thunk'; // In your case use saga

const ConfigureStore = (initialState) => {    
    let middleware = applyMiddleware(thunk);
    const store = initialState ?
        createStore(rootReducer, initialState, middleware)
        : createStore(rootReducer, middleware);
    return store;
};

export default ConfigureStore;

This way you can inject your initial state to test some specific cases.
Now in order to test the user interactions, you need to dispatch the actions the user can execute, and then verify the state of your components.
See this example:

import React from 'react';
import configureStore from '../_setup';
import { storiesOf } from '@storybook/react';
import { Provider } from 'react-redux';
import { specs, describe, it } from 'storybook-addon-specifications'
import { configure,  mount } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import { expect } from 'chai';
import Greeting from '../components/Greeting';


let store = configureStore();// Here initializing the store, you can pass the initial state also.
configure({ adapter: new Adapter() });

storiesOf('Greetings with Redux', module)
    .add('User says hello', () => {
        // here you pass the store to the component
        const storyWithProvider = (
            <Provider store={store}>
                <Greeting />
            </Provider>
        );
        // Here you execute the action you want to test.
        store.dispatch({
            type: 'SayHelloAction',
            payload: 'Jhon Doe'
        });

        specs(() => describe('User says hello', function () {
            it('Should have greeting message with the user name', function () {
                const output = mount(storyWithProvider);
                // Here you verify the state of the component
                expect(output.text()).to.contains('Hello: Jhon Doe');
            });
        }));
        return storyWithProvider;
    });

Also you can execute several actions, to get the result you want.
e.g.

        store.dispatch({
            type: constants.actions.SHOW_VENDOR_PRODUCTS,
            payload: selectedVendor
        });
        store.dispatch({
            type: constants.actions.VENDOR_ACCEPTS_ORDER,
            payload: false
        });
        store.dispatch({
            type: constants.actions.ADD_PRODUCT,
            payload: selectedProduct
        });

And then verify the result:

expect(wrapper.find('.btn .btn-lg .btn-success')).to.have.length.of(1);

For reference see this example project, see the Specifications tab to validate the tests:
enter image description here

Here I'm using storybook to demostrate, but you can also do the same with simple mocha.
Hope this help.

Maim answered 20/7, 2018 at 15:47 Comment(0)
S
-2

If you want to write integration tests, consider writing UI tests for your app that will do full end to end testing. There are many web options:

or React Native:

As for unit testing, you should be able to do that on a file by file basis without having to export the whole component. See the redux saga unit testing example: https://github.com/redux-saga/redux-saga/blob/master/docs/advanced/Testing.md

Sessile answered 20/7, 2018 at 3:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.