Javascript 如何在玩笑中模拟导出的常量

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/42977961/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 01:33:44  来源:igfitidea点击:

How to mock an exported const in jest

javascriptreactjsunit-testingjestjs

提问by Mdd

I have a file that relies on an exported constvariable. This variable is set to truebut if ever needed can be set to falsemanually to prevent some behavior if downstream services request it.

我有一个依赖于导出const变量的文件。此变量设置为true但如果需要,可以false手动设置为防止下游服务请求时出现某些行为。

I am not sure how to mock a constvariable in Jest so that I can change it's value for testing the trueand falseconditions.

我不确定如何const在 Jest 中模拟一个变量,以便我可以更改它的值以测试truefalse条件。

Example:

例子:

//constants module
export const ENABLED = true;

//allowThrough module
import { ENABLED } from './constants';

export function allowThrough(data) {
  return (data && ENABLED === true)
}

// jest test
import { allowThrough } from './allowThrough';
import { ENABLED } from './constants';

describe('allowThrough', () => {
  test('success', () => {
    expect(ENABLED).toBE(true);
    expect(allowThrough({value: 1})).toBe(true);
  });

  test('fail, ENABLED === false', () => {
    //how do I override the value of ENABLED here?

    expect(ENABLED).toBe(false) // won't work because enabled is a const
    expect(allowThrough({value: 1})).toBe(true); //fails because ENABLED is still true
  });
});

回答by eur00t

This example will work if you compile ES6 modules syntax into ES5, because in the end, all module exports belong to the same object, which can be modified.

如果您将 ES6 模块语法编译为 ES5,则此示例将起作用,因为最终所有模块导出都属于同一个对象,可以修改。

import { allowThrough } from './allowThrough';
import { ENABLED } from './constants';
import * as constants from './constants';

describe('allowThrough', () => {
    test('success', () => {
        constants.ENABLED = true;

        expect(ENABLED).toBe(true);
        expect(allowThrough({ value: 1 })).toBe(true);
    });

    test('fail, ENABLED === false', () => {
        constants.ENABLED = false;

        expect(ENABLED).toBe(false);
        expect(allowThrough({ value: 1 })).toBe(false);
    });
});

Alternatively, you can switch to raw commonjs requirefunction, and do it like this with the help of jest.mock(...):

或者,您可以切换到原始 commonjsrequire函数,并在以下帮助下执行此操作jest.mock(...)

const mockTrue = { ENABLED: true };
const mockFalse = { ENABLED: false };

describe('allowThrough', () => {
    beforeEach(() => {
        jest.resetModules();
    });

    test('success', () => {
        jest.mock('./constants', () => mockTrue)
        const { ENABLED } = require('./constants');
        const { allowThrough } = require('./allowThrough');

        expect(ENABLED).toBe(true);
        expect(allowThrough({ value: 1 })).toBe(true);
    });

    test('fail, ENABLED === false', () => {
        jest.mock('./constants', () => mockFalse)
        const { ENABLED } = require('./constants');
        const { allowThrough } = require('./allowThrough');

        expect(ENABLED).toBe(false);
        expect(allowThrough({ value: 1 })).toBe(false);
    });
});

回答by Luke

There is another way to do it in ES6+ and jest 22.1.0+ thanks to getters and spyOn.

由于 getter 和 spyOn,还有另一种方法可以在 ES6+ 和 jest 22.1.0+ 中做到这一点。

By default, you cannot spy on primitive types like boolean or number. You can though replace an imported file with your own mock. A getter method still acts like a primitive member but allows us to spy on it. Having a spy on our target member you can basically do with it whatever you want, just like with a jest.fn()mock.

默认情况下,您不能窥探布尔或数字等原始类型。您可以用自己的模拟替换导入的文件。getter 方法仍然像原始成员一样,但允许我们监视它。对我们的目标成员进行间谍活动,您基本上可以随心所欲地使用它,就像jest.fn()模拟一样。

Below an example

下面举个例子

// foo.js
export const foo = true; // could be expression as well
// subject.js
import { foo } from './foo'

export default () => foo
// subject.spec.js
import subject from './subject'

jest.mock('./foo', () => ({
  get foo () {
    return true // set some default value
  }
}))

describe('subject', () => {
  const mySpy = jest.spyOn(subject.default, 'foo', 'get')

  it('foo returns true', () => {
    expect(subject.foo).toBe(true)
  })

  it('foo returns false', () => {
    mySpy.mockReturnValueOnce(false)
    expect(subject.foo).toBe(false)
  })
})

Read more in the docs.

在文档中阅读更多内容。

回答by cyberwombat

Thanks to @Luke I was able to expand on his answer for my needs. I had the requirements of:

感谢@Luke,我能够根据我的需要扩展他的答案。我有以下要求:

  • Only mocking certain values in the file - not all
  • Running the mock only inside a single test.
  • 只模拟文件中的某些值 - 不是全部
  • 仅在单个测试中运行模拟。

Turns out that doMock()is like mock()but doesn't get hoisted. In addition requireActual()can be used to grab original data.

事实证明这doMock()就像mock()但没有被提升。另外requireActual()可以用来抓取原始数据。

My config.jsfile - I need to mock only part of it

我的config.js文件 - 我只需要模拟其中的一部分

export const SOMETHING = 'blah'
export const OTHER = 'meh'

My test file

我的测试文件

// import { someFunc } from  'some/file' // This won't work with doMock - see below
describe('My test', () => {

  test('someFunc() does stuff', async () => {

    // Here I mock the config file which gets imported somewhere deep in my code
    jest.doMock('config.js', () => {

      // Grab original
      const originalModule = jest.requireActual('config')

      // Return original but override some values
      return {
        __esModule: true, // Depends on your setup
        ...originalModule,
        SOMETHING: 'boom!'
      }
    })

    // Because `doMock` doesn't get hoisted we need to import the function after
    const { someFunc } = await import(
      'some/file'
    )

    // Now someFunc will use the original config values but overridden with SOMETHING=boom!
    const res = await someFunc()
  })
})

Depending on other tests you may also need to use resetModules()somewhere such as beforeAllor afterAll.

根据其他测试,您可能还需要使用resetModules()诸如beforeAll或 之类的地方afterAll

Docs:

文档: