Brian Nystrom
Brian Nystrom

Reputation: 105

How to unit test an api call and assert state change in react and enzyme?

I'm having trouble getting a test to pass in enzyme. When the component mounts, I make an API call to get some data then update the state. I want to assert that the child component renders the data properly.

I have tried setTimeout and calling update on the component and that has not done anything for me. I can print out the updated state but my assertions do not reflect that.

Here's my test:

describe('' () => {
  beforeEach(() => {
    let mock = new MockAdapter(axios);                                                    
    let eventModel = [                                                                    
      { 
        id: 1, 
        title: 'LFD',                                                               
        description: '',
        start_date: new Date(),                                                           
        end_date: new Date()                                                              
      }                                                                                  
    ]
    mock.onGet('/events').reply(200, eventModel);                                         
  });              

  test('renders events', () => {
    let component = shallow(<ForecastPage />);   

    component.update();           

    expect(component.find(EventRow).length).toEqual(1);                                    
  })
})

My react component

class ForecastPage extends React.Component {
  constructor (props) {
    super(props);
    this.state = {
      events: []
    };
  }

  componentDidMount() {
    api.getEvents()
      .then((data) => {
        this.setState({
          events: data
        })
      })
      .catch((error) => {
        console.log(error);
      })
  }

  render () {
    return (
      <div>
        <div>
          <h1>Data Forecast</h1>

        <div>
          <table>
            <tr>
              <th>Start Date</th>
              <th>End Date</th>
              <th>Title</th>
            </tr>
          </table>
          {
            this.state.events.map((index, event) => {
              return <EventRow key={index} event={event}/>;
            })
          }
        </div>
      </div>
    );
  }
}

Even though I call update, nothing happens. If I print out to the console the state in the render function, I can see that the state has been updated, but my test does not catch that somehow. setTimeout throws a false positive and passes the test regardless.

How do I confidently test this?

Upvotes: 0

Views: 1423

Answers (1)

Andrew Miroshnichenko
Andrew Miroshnichenko

Reputation: 2074

Update

First of all, check rendering of your EventRows. As I know, in map function callback first receives array element, and then - element's index. So your code probably should look like this.

{
  this.state.events.map((event, index) => {  // here is the difference
    return <EventRow key={index} event={event}/>;
  })
}

If this won't help, try to use raw mock, without additional mocking modules.

// import your api module used in ForecastPage component
import api from '/path/to/your/api/module';

describe('' () => {
  beforeEach(() => {                                     
    let eventModel = [                                                                    
      { 
        id: 1, 
        title: 'LFD',                                                               
        description: '',
        start_date: new Date(),                                                           
        end_date: new Date()                                                              
      }                                                                                  
    ]
    // assuming you use jest
    api.getEvents = jest.fn(() => {
      return Promise.resolve(eventModel);
    });

  });              

  test('renders events', async () => {
    let component = await shallow(<ForecastPage />);   

    component.update();           

    expect(component.find(EventRow).length).toEqual(1);                                    
  })
})

Upvotes: 1

Related Questions