0

recently started using recompose (https://github.com/acdlite/recompose)

I wonder how should I approach unit testing components that are wrapped with some of hocs recompose provide? I love how entire class component can be replaced with functional approach but it totally not true in terms of unit tests.

For example with given list component

export const ListItem = toClass(pure(({ text }) => <li>{text}</li>));
const renderItems = R.map(t => <ListItem key={t} text={t} />);

export const ListComponent = toClass(({ todos, name, updateName, addTodo }) =>
  <div>
    <input onChange={updateName} value={name} />
    <button onClick={() => addTodo(name)}>add todo</button>
    <ul>
      {renderItems(todos)}
    </ul>
  </div>
);

...

const List = compose(
  withReducer("state", "dispatch", listReducer, props => ({
    ...initialState,
    ...props
  })),
  withHandlers({
    updateName: ({ dispatch }) => e =>
      dispatch({ type: "UPDATE_NAME", payload: e.target.value }),
    addTodo: ({ dispatch, name }) => name =>
      dispatch({ type: "ADD_TODO", payload: name })
  }),
  flattenProp("state")
)(ListComponent);

export default List;

How can I test children length with given props? I've tried something like this but it's not working.

it("renders todos list", () => {
    const component = shallow(<List todos={["todo1", "todo2", "todo3"]} />);
    expect(component.instance().children).toHaveLength(3);
  });
vrael560
  • 34
  • 1
  • 4

2 Answers2

4

Do not use mount instead of shallow. Use .dive() with shallow instead.

Mount renders all children as well which isn't good for unit tests.

Martin Dawson
  • 7,455
  • 6
  • 49
  • 92
1

You can definitely test your functions with recompose. You are just using your logic in a way that is non testable. Let me give you an example of how I would test updateName

I would create a function called updateName

export const updateName = props => event =>
  props.dispatch({ type: "UPDATE_NAME", payload: event.target.value })

Based on how you are using your function, it is important to understand that this is an integration test. not a unit test. We are testing if the dispatch function got called with the correct parameters. That is all. So our test file may look as follows

const mockDispatch =  jest.fn();
const props = {dispatch: mockDispatch}
const event = {
 target: {
  value:'john'
 }
}
updateName(props, event);
expect(mockDispatch.mock.calls).toEqual([{ type: "UPDATE_NAME", payload: 'john' }])

Ta da!

and in your container you would use it as so:

List = compose(
 withHandlers({
  updateName
 })
)
alaboudi
  • 3,187
  • 4
  • 29
  • 47
  • It is just important to understand that this is an integration test, not a unit test. That, in my opinion, was the reason you are struggling with testing your work – alaboudi May 31 '18 at 21:02