Reputation: 1089
Here is a sample code where I want to test the function buttonReducer. But the case names in the reducer functions are generated in another function. So, when I want to test my reducer alone, I want to override the RESET_TYPE, FETCH_TYPE, and SHOW_TYPE so that I am able to test all the scenarios.
//main reducer.js
import {getActionTypeName} from './functions';
export const RESET_TYPE = getActionTypeName('RESET');
export const FETCH_TYPE = getActionTypeName('RESET');
export const SHOW_TYPE = getActionTypeName('RESET');
const initialState = {
name: 'John'
};
export const buttonReducer = (state = {...initialState}, action){
switch(action.type){
case RESET_TYPE: {
const newState = {"some random change", ...initialState};
return newState;
}
case FETCH_TYPE: {
const newState = {"some random change", ...initialState};
return newState;
}
case SHOW_TYPE: {
const newState = {"some random change", ...initialState};
return newState;
}
default: {
return state;
}
}
}
Here are few things that I tried:
1.
jest.mock('./functions', ()=> {
return {
getActionTypeName: ()=>('return whatever I want')
}
}
But this doesn't work.
So essentially, I want to run the reducer by changing the values of the variables and not merely mock them just for the test case.
Upvotes: 0
Views: 8291
Reputation: 67
You can have your mock return a jest fn that you can later change the return value for. That way you don't have to do a new mock each time.
const getActionTypeName = jest.fn(() => {});
jest.mock('./pathToModule', () => {
return {
__esModule: true,
getActionTypeName: () => getActionTypeName(),
}
})
describe('functionBeingTested', () => {
it('should do something', () => {
getActionTypeName.mockReturnValue('RUNTIME_RESET_TYPE');
// test code...
// assertions...
});
});
Upvotes: 1
Reputation: 102237
Since the action types RESET_TYPE
, FETCH_TYPE
, and SHOW_TYPE
are defined and calculated in module scope at runtime, in order to eliminate the caching effect of the module import
, jest.resetModules() method is required. Before executing the test case, we need to call it. So that we can get a fresh module with fresh module variables. This prevents test cases from influencing each other.
Now, we can use jest.doMock(moduleName, factory, options) and mockFn.mockReturnValueOnce(value) methods to mock ./functions
module and getActionTypeName
function with different returned value for each test case.
E.g.
reducer.js
:
import { getActionTypeName } from './functions';
export const RESET_TYPE = getActionTypeName('RESET');
export const FETCH_TYPE = getActionTypeName('RESET');
export const SHOW_TYPE = getActionTypeName('RESET');
const initialState = {
name: 'John',
};
export const buttonReducer = (state = { ...initialState }, action) => {
switch (action.type) {
case RESET_TYPE: {
const newState = { a: 'a', ...initialState };
return newState;
}
case FETCH_TYPE: {
const newState = { b: 'b', ...initialState };
return newState;
}
case SHOW_TYPE: {
const newState = { c: 'c', ...initialState };
return newState;
}
default: {
return state;
}
}
};
functions.js
:
export function getActionTypeName() {
console.log('real implementation');
}
reducer.test.js
:
describe('68179950', () => {
beforeEach(() => {
jest.resetModules();
});
it('should return dynamic RESET_TYPE', () => {
jest.doMock('./functions', () => ({
getActionTypeName: jest.fn().mockReturnValueOnce('RUNTIME_RESET_TYPE'),
}));
const { buttonReducer } = require('./reducer');
const actual = buttonReducer({}, { type: 'RUNTIME_RESET_TYPE' });
expect(actual).toEqual({ name: 'John', a: 'a' });
});
it('should return dynamic FETCH_TYPE', () => {
jest.doMock('./functions', () => ({
getActionTypeName: jest.fn().mockReturnValueOnce('RUNTIME_RESET_TYPE').mockReturnValueOnce('RUNTIME_FETCH_TYPE'),
}));
const { buttonReducer } = require('./reducer');
const actual = buttonReducer({}, { type: 'RUNTIME_FETCH_TYPE' });
expect(actual).toEqual({ name: 'John', b: 'b' });
});
it('should return dynamic SHOW_TYPE', () => {
jest.doMock('./functions', () => ({
getActionTypeName: jest
.fn()
.mockReturnValueOnce('RUNTIME_RESET_TYPE')
.mockReturnValueOnce('RUNTIME_FETCH_TYPE')
.mockReturnValueOnce('RUNTIME_SHOW_TYPE'),
}));
const { buttonReducer } = require('./reducer');
const actual = buttonReducer({}, { type: 'RUNTIME_SHOW_TYPE' });
expect(actual).toEqual({ name: 'John', c: 'c' });
});
});
unit test result:
PASS examples/68179950/reducer.test.js (18.013 s)
68179950
✓ should return dynamic RESET_TYPE (12582 ms)
✓ should return dynamic FETCH_TYPE (1 ms)
✓ should return dynamic SHOW_TYPE (7 ms)
------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
------------|---------|----------|---------|---------|-------------------
All files | 93.33 | 60 | 100 | 92.86 |
reducer.js | 93.33 | 60 | 100 | 92.86 | 26
------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 3 passed, 3 total
Snapshots: 0 total
Time: 22.095 s
Upvotes: 1