我有一个依赖导出的const
变量的文件。此变量设置为true
但如果需要,可以手动设置为false
,以防止下游服务请求时出现某些行为。
我不确定如何在Jest中模拟const
变量,以便我可以更改它以测试true
和false
条件的值。
示例:
//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
});
});
答案 0 :(得分:22)
如果将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);
});
});
或者,你可以切换到原始的commonjs require
函数,并在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);
});
});
答案 1 :(得分:5)
由于@Luke,我能够根据我的需要扩展他的答案。我有以下要求:
事实证明,doMock()
与mock()
相似,但不会被吊起。另外,requireActual()
可用于获取原始数据。
我的config.js
文件-我只需要模拟其中的一部分
export const SOMETHING = 'blah'
export const OTHER = 'meh'
我的测试文件
// 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()
})
})
根据其他测试,您可能还需要在resetModules()
或beforeAll
之类的地方使用afterAll
。
文档:
答案 2 :(得分:4)
因为我们不能直接覆盖/模拟该值。我们可以使用下面的hack
// foo.js
export const foo = true; // could be expression as well
// spec file
import * as constants from './foo'
Object.defineProperty(constant, 'foo', {value: 1})
对于函数:
Object.defineProperty(store, 'doOneThing', {value: jest.fn()})
答案 3 :(得分:3)
不幸的是,没有一个发布的解决方案对我有用,或者更确切地说,有些解决方案确实起作用,但是抛出了掉毛,TypeScript或编译错误,因此我将发布我的解决方案,该解决方案对我来说都适用,并且符合当前的编码标准:>
// constants.ts
// configuration file with defined constant(s)
export const someConstantValue = true;
// module.ts
// this module uses the defined constants
import { someConstantValue } from './constants';
export const someCheck = () => someConstantValue ? 'true' : 'false';
// module.test.ts
// this is the test file for module.ts
import { someCheck } from './module';
const mockSomeConstantValueGetter = jest.fn();
jest.mock('./constants', () => ({
get someConstantValue() {
return mockSomeConstantValueGetter();
},
}));
describe('someCheck', () => {
it('returns "true" if someConstantValue is true', () => {
mockSomeConstantValueGetter.mockReturnValue(true);
expect(someCheck()).toEqual('true');
});
it('returns "false" if someConstantValue is false', () => {
mockSomeConstantValueGetter.mockReturnValue(false);
expect(someCheck()).toEqual('false');
});
});
答案 4 :(得分:2)
由于使用了getter和spyOn,在ES6 +和jest 22.1.0+中还有另一种方法。
默认情况下,您无法监视布尔值或数字之类的原始类型。您可以用自己的模拟代替导入的文件。 getter方法仍然像原始成员一样工作,但允许我们对其进行监视。监视我们的目标成员,基本上可以随便使用它,就像使用jest.fn()
模拟一样。
下面是一个例子
// 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)
})
})
答案 5 :(得分:1)
面对同一问题,我发现此博客文章非常有用,并且比@cyberwombat用例简单得多:
https://remarkablemark.org/blog/2018/06/28/jest-mock-default-named-export/
// esModule.js
export default 'defaultExport';
export const namedExport = () => {};
// esModule.test.js
jest.mock('./esModule', () => ({
__esModule: true, // this property makes it work
default: 'mockedDefaultExport',
namedExport: jest.fn(),
}));
import defaultExport, { namedExport } from './esModule';
defaultExport; // 'mockedDefaultExport'
namedExport; // mock function
答案 6 :(得分:0)
您还可以使用"Object.defineProperty"
来重新定义您的财产,而不是开玩笑并且没有吊装等麻烦。可以轻松地为每个测试用例重新定义它。
这是一个基于我拥有的某些文件的伪代码示例:
来自本地化文件:
export const locale = 'en-US';
在另一个文件中,我们使用的是语言环境:
import { locale } from 'src/common/localization';
import { format } from 'someDateLibrary';
// 'MMM' will be formatted based on locale
const dateFormat = 'dd-MMM-yyyy';
export const formatDate = (date: Number) => format(date, dateFormat, locale)
如何在测试文件中进行模拟
import * as Localization from 'src/common/localization';
import { formatDate } from 'src/utils/dateUtils';
describe('format date', () => {
test('should be in Danish format', () => {
Object.defineProperty(Localization, 'locale', {
value: 'da-DK'
});
expect(formatDate(1589500800000)).toEqual('15-maj-2020');
});
test('should be in US format', () => {
Object.defineProperty(Localization, 'locale', {
value: 'en-US'
});
expect(formatDate(1589500800000)).toEqual('15-May-2020');
});
});
答案 7 :(得分:0)
我最需要的场景是模拟一个类使用的常量(在我的情况下,是一个React组件,但实际上可以是任何ES6类)。
@Luke的答案对此非常有效,花了我一分钟的时间将它包裹起来,所以我想将其改写为更明确的示例。
关键是您的常量需要保存在import
的单独文件中,这样import
本身就可以被jest
插入/模拟。
以下内容对我来说很完美。
首先,定义常量:
// src/my-component/constants.js
const MY_CONSTANT = 100;
export { MY_CONSTANT };
接下来,我们有实际使用常量的类:
// src/my-component/index.jsx
import { MY_CONSTANT } from './constants';
// This could be any class (e.g. a React component)
class MyComponent {
constructor() {
// Use the constant inside this class
this.secret = MY_CONSTANT;
console.log(`Current value is ${this.secret}`);
}
}
export default MyComponent
最后,我们进行了测试。我们要在这里处理2个用例:
MY_CONSTANT
生成值MY_CONSTANT
的值使用测试文件顶部的jest.mock
可以实现第一部分。
通过使用jest.spyOn
进一步监视导出的常量列表,可以实现第二个。几乎就像是模拟之上的模拟。
// test/components/my-component/index.js
import MyComponent from 'src/my-component';
import allConstants from 'src/my-component/constants';
jest.mock('src/my-component/constants', () => ({
get MY_CONSTANT () {
return 30;
}
}));
it('mocks the value of MY_CONSTANT', () => {
// Initialize the component, or in the case of React, render the component
new MyComponent();
// The above should cause the `console.log` line to print out the
// new mocked value of 30
});
it('mocks the value of MY_CONSTANT for this test,', () => {
// Set up the spy. You can then use any jest mocking method
// (e.g. `mockReturnValue()`) on it
const mySpy = jest.spyOn(allConstants, 'MY_CONSTANT', 'get')
mySpy.mockReturnValue(15);
new MyComponent();
// The above should cause the `console.log` line to print out the
// new mocked value of 30
});
答案 8 :(得分:-1)
我通过在减速器中初始化ContstantsFile.js中的常量来解决此问题。并将其放在redux存储中。由于jest.mock无法模拟contstantsFile.js
constantsFile.js
-----------------
const MY_CONSTANTS = {
MY_CONSTANT1: "TEST",
MY_CONSTANT2: "BEST",
};
export defualt MY_CONSTANTS;
reducers/index.js
-----------------
import MY_CONST from "./constantsFile";
const initialState = {
...MY_CONST
}
export const AbcReducer = (state = initialState, action) => {.....}
ABC.jsx
------------
import { useSelector } from 'react-redux';
const ABC = () => {
const const1 = useSelector(state) => state. AbcReducer. MY_CONSTANT1:
const const2 = useSelector(state) => state. AbcReducer. MY_CONSTANT2:
.......
现在,我们可以轻松地在test.jsx中模拟存储并将值提供给所需的常量。
Abc.text.jsx
-------------
import thunk from 'redux-thunk';
import configureMockStore from 'redux-mock-store';
describe('Abc mock constants in jest', () => {
const mockStore = configureMockStore([thunk]);
let store = mockStore({
AbcReducer: {
MY_CONSTANT1 ="MOCKTEST",
MY_CONSTANT2 = "MOCKBEST",
}
});
test('your test here', () => { .....
现在,当测试运行时,它将始终从模拟存储中选择常量值。