Mocking globals in Jest

末鹿安然 提交于 2019-11-26 17:47:43

问题


Is there any way in Jest to mock global objects, such as navigator, or Image*? I've pretty much given up on this, and left it up to a series of mockable utility methods. For example:

// Utils.js
export isOnline() {
    return navigator.onLine;
}

Testing this tiny function is simple, but crufty and not deterministic at all. I can get 75% of the way there, but this is about as far as I can go:

// Utils.test.js
it('knows if it is online', () => {
    const { isOnline } = require('path/to/Utils');

    expect(() => isOnline()).not.toThrow();
    expect(typeof isOnline()).toBe('boolean');
});

On the other hand, if I am okay with this indirection, I can now access navigator via these utilities:

// Foo.js
import { isOnline } from './Utils';

export default class Foo {
    doSomethingOnline() {
        if (!isOnline()) throw new Error('Not online');

        /* More implementation */            
    }
}

...and deterministically test like this...

// Foo.test.js
it('throws when offline', () => {
    const Utils = require('../services/Utils');
    Utils.isOnline = jest.fn(() => isOnline);

    const Foo = require('../path/to/Foo').default;
    let foo = new Foo();

    // User is offline -- should fail
    let isOnline = false;
    expect(() => foo.doSomethingOnline()).toThrow();

    // User is online -- should be okay
    isOnline = true;
    expect(() => foo.doSomethingOnline()).not.toThrow();
});

Out of all the testing frameworks I've used, Jest feels like the most complete solution, but any time I write awkward code just to make it testable, I feel like my testing tools are letting me down.

Is this the only solution or do I need to add Rewire?

*Don't smirk. Image is fantastic for pinging a remote network resource.


回答1:


As every test suite run its own environment you can mock globals by just overwrite them. All global vars can be accessed by the global name space.

global.navigator = {
  onLine: true
}

The overwrite has only effects in your current test and will not effect others. This also a good way to handle Math.random or Date.now

Note, that through some changes in jsdom it could be possible that you have to mock globals like this:

Object.defineProperty(globalObject, key, { value, writable: true });



回答2:


Jest may have changed since the accepted answer was written, but Jest does not appear to reset your global after testing. Please see the testcases attached.

https://repl.it/repls/DecentPlushDeals

As far as I know, the only way around this is with an afterEach() or afterAll() to clean up your assignments to global.




回答3:


If someone needs to mock a global with static properties then my example chould help:

beforeAll(() => {
    global.EventSource = jest.fn(() => ({
      readyState: 0,
      close: jest.fn()
    }))

    global.EventSource.CONNECTING = 0
    global.EventSource.OPEN = 1
    global.EventSource.CLOSED = 2
  })



回答4:


If you are using react-testing-library and you use the cleanup method provided by the library. It will remove all global declarations made in that file once all tests in the file have run. This will then not carry over to any other tests run.

ex:

import { cleanup } from 'react-testing-library'

afterEach(cleanup)

global.getSelection = () => {

}

describe('test', () => {
  expect(true).toBeTruthy()
})


来源:https://stackoverflow.com/questions/40449434/mocking-globals-in-jest

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!