Stuck testing your connected component? Make sure you export your 'plain' component as well!

Does this sound familiar to you?

You have a container component and you write a test for it:

import ShoppingCartContainer from './ShoppingCart';

test('it works', () => {
  const wrapper = shallow(<ShoppingCartContainer />);
  // test something
});

And then when you run it, the first thing you see is this error:

Invariant violation: Could not find "store" in either the context or props of Connect(ShoppingCart)

So, you’re thinking, oh, it makes sense, I just need to pass in the store.
So you include redux-mock-store, you wrap your component in a Provider and you’re good to go:

import ShoppingCartContainer from './ShoppingCart';
import configureMockStore from 'redux-mock-store';
const mockStore = configureMockStore();

test('it works', () => {
  const store = mockStore({});
  const wrapper = shallow(<Provider store={store}>
    <ShoppingCartContainer />
  </Provider>);
  // test something
});

But now when you run the test, the ShoppingCartContainer is no longer rendered! Only the Provider does.
And this is actually expected, because this is what Enyme’s shallow does, only renders the root component and mocks all the children.

So you think ... no problem, I can pass the store directly!

import ShoppingCartContainer from './ShoppingCart';
import configureMockStore from 'redux-mock-store';
const mockStore = configureMockStore();

test('it works', () => {
  const store = mockStore({});
  const wrapper = shallow(<ShoppingCartContainer store={mockStore} />);
  // test something
});

Ahaa! So now you can test you real logic. But wait, your actual component is never really rendered because you are using shallow. Should you just switch to mount instead of shallow? This will add too much complexity to your code and then you will no longer have a unit test, but an integration test, since your test will depend on too many things.

So what do to instead?

Test the logic of your ‘plain’ component by exporting it directly

The container itself doesn’t really hold that much logic - it just takes some props and passes them to the ‘plain’ component. So actually what you want to test is that one!

The easiest way to achieve this is to just export the plain component as well, and then you will have two components available in the file:

// default export points to Container component
import ShoppingCartContainer from './ShoppingCart'; 
// plain component is available through a named export
import { ShoppingCart } from './ShoppingCart';

The component code would look something like this:

import { getProducts } from './selectors.js';
import { addProduct } from './actions.js';

// Plain component
export const ShoppingCart = () => {
   return <div>Products here</div>;
} 

// Container
export connect({ products: getProducts(state) }, addProduct)(ShoppingCart);

This will make your code much easier to test, you will really have a unit test and you can focus on your business logic instead of testing Redux’s code.