javascriptreactjsjestjsenzyme

Jest: mocking console.error - tests fails


The Problem:

I have a simple React component I'm using to learn to test components with Jest and Enzyme. As I'm working with props, I added the prop-types module to check for properties in development. prop-types uses console.error to alert when mandatory props are not passed or when props are the wrong data type.

I wanted to mock console.error to count the number of times it was called by prop-types as I passed in missing/mis-typed props.

Using this simplified example component and test, I'd expect the two tests to behave as such:

  1. The first test with 0/2 required props should catch the mock calling twice.
  2. The second test with 1/2 required props should catch the mock called once.

Instead, I get this:

  1. The first test runs successfully.
  2. The second test fails, complaining that the mock function was called zero times.
  3. If I swap the order of the tests, the first works and the second fails.
  4. If I split each test into an individual file, both work.
  5. console.error output is suppressed, so it's clear it's mocked for both.

I'm sure I am missing something obvious, like clearing the mock wrong or whatever.

When I use the same structure against a module that exports a function, calling console.error some arbitrary number of times, things work.

It's when I test with enzyme/react that I hit this wall after the first test.

Sample App.js:

import React, { Component } from 'react';
import PropTypes from 'prop-types';

export default class App extends Component {

  render(){
    return(
      <div>Hello world.</div>
    );
  }
};

App.propTypes = {
  id : PropTypes.string.isRequired,
  data : PropTypes.object.isRequired
};

Sample App.test.js

import React from 'react';
import { mount } from 'enzyme';
import App from './App';

console.error = jest.fn();

beforeEach(() => {
  console.error.mockClear();
});

it('component logs two errors when no props are passed', () => {
  const wrapper = mount(<App />);
  expect(console.error).toHaveBeenCalledTimes(2);
});

it('component logs one error when only id is passed', () => {
  const wrapper = mount(<App id="stringofstuff"/>);
  expect(console.error).toHaveBeenCalledTimes(1);
});

Final note: Yeah, it's better to write the component to generate some user friendly output when props are missing, then test for that. But once I found this behavior, I wanted to figure out what I'm doing wrong as a way to improve my understanding. Clearly, I'm missing something.


Solution

  • You didn't miss anything. There is a known issue (https://github.com/facebook/react/issues/7047) about missing error/warning messages.

    If you switch your test cases ('...when only id is passed' - the fisrt, '...when no props are passed' - the second) and add such console.log('mockedError', console.error.mock.calls); inside your test cases, you can see, that the message about missing id isn't triggered in the second test.