Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I 'mock' state value in ReactJS component unittest?

I am trying to unit test my ReactJS component. Basically it is a simple component consisting of an input and a button. When clicking on the button it triggers an event called 'onSave' and this calls 'this.props.addTodo' only if the state.textValue is not empty:

import React, {Component, PropTypes} from 'react';

export default class Invoer extends Component {

    static propTypes = {
        saveTodo: PropTypes.func.isRequired
    }

    constructor(props) {
        super();
        this.props = props;
        this.state = {textValue: ''};
    }


    onChange = (event) => {
        if (event.target.value !== '') {
            this.setState({textValue: event.target.value});
            console.log(event.target.value);
        }
    }

    onSave = () => {
        if (this.state.textValue!== '') {
            this.props.saveTodo(this.state.textValue);
        }
    }

    render() {
        return (
            <header>
                <input type="text" value={this.state.textValue} onChange={this.onChange}/>
                <button onClick={this.onSave}>save</button>
            </header>
        );
    }
}

I wrote a unit test for the onSave event. The only issue is that I could not figure out how to 'mock' the this.state.textValue in order to set the state on line 26 see above:

import React from 'react';
import Invoer from "../components/Invoer";
import {createRenderer} from 'react-test-renderer/shallow';
it('should call this.props.saveTodo event when clicking on button on non empty value', () => {
    const props = {
        saveTodo: jest.fn()
    }

    const renderer = createRenderer();
    renderer.render(<Invoer {...props} />)
    const output = renderer.getRenderOutput()

    //tried to mock the state.textValue, results in error:
    //output.props.children[0].value = 'hoera';

    output.props.children[1].props.onClick();

    expect(props.saveTodo).toBeCalled()
});

When running this test I get this error:

should call this.props.saveTodo event when clicking on button on non empty value
    expect(jest.fn()).toBeCalled()    
    Expected mock function to have been called.

Which was expected of course. How can I 'mock' this this.state.textValue? Or is this totally the wrong approach?

like image 814
bier hier Avatar asked Sep 20 '17 07:09

bier hier


People also ask

How do you mock a state in React?

To enable us to mock useState, we use React. useState (line #5) instead of using the usual named import (i.e. import { useState } from 'react'). Below is our Jest unit test for the component. Before rendering the component for testing, we create a constant 'setStateMock' and mock it with a jest function jest.

How do you get the value of a state in React?

The state and props in React are always in an object format. This means that the value could be accessed from the state and props via key-value pair. To access the normal state object, you can use the key name from the object.

How do you mock React a component?

To mock a React component, the most straightforward approach is to use the jest. mock function. You mock the file that exports the component and replace it with a custom implementation. Since a component is basically a function, the mock should also return a function.

How do you pass a state in component?

Sending state/props to another component using the onClick event: So first we store the state/props into the parent component i.e in which component where we trigger the onClick event. Then to pass the state into another component, we simply pass it as a prop.


1 Answers

For anyone else hitting this problem (I assume the OP solved this by now) - if using enzyme you can call setState directly on your component:

// assuming props and mockState are set in a beforeEach()
it('adds state to the component', () => {
  const myComponent = shallow(<MyComponent {...props} />);
  myComponent.setState({ ...mockState });
  const instance = myComponent.instance();
  expect(instance.state).toEqual(mockState);

  // you can then directly call instance methods - e.g. mocking 
  // previous props/state to test changes are handled as expected
  instance.componentDidUpdate(prevProps, prevMockState);
});

Note that, depending on your requirements, you may need to use mount() rather than shallow().

like image 52
blindfish Avatar answered Sep 21 '22 13:09

blindfish