Jest: how to mock console when it is used by a third-party-library?

后端 未结 2 1753
长发绾君心
长发绾君心 2020-12-08 05:49

I am trying to mock console.warn/error but i can\'t. I use a third-party-library which calls console.warn inside it. I need to test was it called or wasn\'t. In my test case

相关标签:
2条回答
  • 2020-12-08 06:23

    You have to use global to access objects in the global context

    global.console = {warn: jest.fn()}
    expect(console.warn).toBeCalled()
    

    or use jest.spyOn added in 19.0.0

    jest.spyOn(global.console, 'warn')
    
    0 讨论(0)
  • 2020-12-08 06:33

    Use jest.spyOn() and spy.mockRestore().

    const spy = jest.spyOn(console, 'warn').mockImplementation();
    ...
    spy.mockRestore();
    

    The accepted answer does not restore the original console.warn() and will "compromise" the other tests inside the same file (if console.warn() is used inside the other tests or the code being tested).

    FYI if you use console.warn = jest.fn() in a test file, it won't affect other test files (e.g console.warn will be back to its original value in the other test files).

    Advice: you can call spy.mockRestore() inside afterEach()/afterAll() to be sure that even if a test crashes, it won't compromise the other tests from the same file (e.g ensures the tests inside the same file are fully isolated).

    Full example:

    const spy = jest.spyOn(console, 'warn').mockImplementation();
    console.warn('message1'); // Won't be displayed (mocked)
    console.warn('message2'); // Won't be displayed (mocked)
    expect(console.warn).toHaveBeenCalledTimes(2);
    expect(spy).toHaveBeenCalledTimes(2); // Another syntax
    expect(console.warn).toHaveBeenLastCalledWith('message2');
    expect(spy).toHaveBeenLastCalledWith('message2'); // Another syntax
    expect(spy.mock.calls).toEqual([['message1'], ['message2']]);
    expect(console.warn.mock.calls).toEqual([['message1'], ['message2']]);
    spy.mockRestore(); // IMPORTANT
    //console.warn.mockRestore(); // Another syntax
    
    console.warn('message3'); // Will be displayed (not mocked anymore)
    expect(spy).toHaveBeenCalledTimes(0); // Not counting anymore
    expect(spy.mock.calls).toEqual([]);
    //expect(console.warn.mock.calls).toEqual([]); // Crash
    

    You cannot write console.warn = jest.fn().mockImplementation() [...] console.warn.mockRestore() because it won't restore the original console.warn().

    /!\ With mockImplementationOnce() you will still need to call spy.mockRestore():

    // /!\
    const spy = jest.spyOn(console, 'warn').mockImplementationOnce(() => {});
    console.warn('message1'); // Won't be displayed (mocked)
    expect(console.warn).toHaveBeenCalledTimes(1);
    expect(spy).toHaveBeenCalledTimes(1); // Another syntax
    expect(console.warn).toHaveBeenLastCalledWith('message1');
    expect(spy).toHaveBeenLastCalledWith('message1'); // Another syntax
    expect(spy.mock.calls).toEqual([['message1']]);
    expect(console.warn.mock.calls).toEqual([['message1']]);
    
    console.warn('message2'); // Will be displayed (not mocked anymore)
    // /!\
    expect(console.warn).toHaveBeenCalledTimes(2); // BAD => still counting
    expect(spy.mock.calls).toEqual([['message1'], ['message2']]);
    expect(console.warn.mock.calls).toEqual([['message1'], ['message2']]);
    
    spy.mockRestore(); // IMPORTANT
    //console.warn.mockRestore(); // Another syntax
    console.warn('message3'); // Will be displayed (not mocked anymore)
    expect(spy).toHaveBeenCalledTimes(0); // Not counting anymore
    expect(spy.mock.calls).toEqual([]);
    //expect(console.warn.mock.calls).toEqual([]); // Crash
    

    You can also write:

    const assert = console.assert;
    console.assert = jest.fn();
    ...
    console.assert = assert;
    
    0 讨论(0)
提交回复
热议问题