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:
Instead, I get this:
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.
I ran into a similar problem, just needed to cache the original method
const original = console.error
beforeEach(() => {
  console.error = jest.fn()
  console.error('you cant see me')
})
afterEach(() => {
  console.error('you cant see me')
  console.error = original
  console.error('now you can')
})
                        Given the behavior explained by @DLyman, you could do it like that:
describe('desc', () => {
    beforeAll(() => {
        jest.spyOn(console, 'error').mockImplementation(() => {});
    });
    afterAll(() => {
        console.error.mockRestore();
    });
    afterEach(() => {
        console.error.mockClear();
    });
    it('x', () => {
        // [...]
    });
    it('y', () => {
        // [...]
    });
    it('throws [...]', () => {
        shallow(<App />);
        expect(console.error).toHaveBeenCalled();
        expect(console.error.mock.calls[0][0]).toContain('The prop `id` is marked as required');
    });
});
                        What guys wrote above is correct. I've encoutered similar problem and here's my solution. It takes also into consideration situation when you're doing some assertion on the mocked object:
beforeAll(() => {
    // Create a spy on console (console.log in this case) and provide some mocked implementation
    // In mocking global objects it's usually better than simple `jest.fn()`
    // because you can `unmock` it in clean way doing `mockRestore` 
    jest.spyOn(console, 'log').mockImplementation(() => {});
  });
afterAll(() => {
    // Restore mock after all tests are done, so it won't affect other test suites
    console.log.mockRestore();
  });
afterEach(() => {
    // Clear mock (all calls etc) after each test. 
    // It's needed when you're using console somewhere in the tests so you have clean mock each time
    console.log.mockClear();
  });
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With