简体   繁体   中英

Jest - Mock a constant property from a module for a specific test

So, I'm attempting to do something which on the surface should be very simple...

I have some constants defined in: ` //constants.js

module.exports = {
 MY_CONSTANT: "TEST"
}

` I have a file which I'm trying to test which has a branching statement like this:

`

//file to test
//...

if(CONSTANTS.MY_CONSTANT === "TEST")
{...}
...

`

And I have a test like this: `

//test


 it("Should do something when MY_CONSTANT === "TEST, () => {
    //This is fine as it is exported as TEST
    })


 it("Should do something else when MY_CONSTANT !== "TEST, () => {
    //This seems annoyingly difficult to get working...
    })

`

I've tried this - With no luck, it doesn't change the actual value

I've tried changing the constant export to export an object instead (that didn't work)

I've tried adding a jest.mock(..) for the constants in my test file and doing an unmock in the tests I don't need them mocked.

I've tried adding a jest.doMock(...) within the test function I need to change the value. (along with jest.resetModules and another require)

I've tried adding a jest.doMock(...) to a tests beforeEach (along with jest.resetModules and another require)

I'm at a loss really...literally all I want to do is change a property value before a test runs 😂

Update So I've done some of the suggestions made:

I now have a mocks folder adjacent to the constant folder It contains a file named the same as the actual constants file and a custom export

I've then added jest.mock("../constants); inside the test.

I've then also added a const funcImTesting = require("../../file").testFunction inside the test.

Still the constant remains unchanged and the test fails

To mock for one test only:

jest.mock('./constants.js', () => ({
  MY_CONSTANT: 'something fake'
}));

https://jestjs.io/docs/en/manual-mocks


To provide a mock for every test:

  1. create a __mocks__ directory adiacent to the module you desire to mock
  2. provide implementation
  3. call jest.mock('./moduleName') in your test

https://jestjs.io/docs/en/manual-mocks#mocking-user-modules

File that exports a constant value that I want to mock:

// utils/deviceTypeUtils file
import DeviceInfo from 'react-native-device-info';

export const isTablet = DeviceInfo.isTablet();

In my test file, I use this code to mock the constant isTablet :

// file: deviceTypeUtils.spec
const DeviceTypeUtilsMock = jest.requireMock('../utils/deviceTypeUtils');
jest.mock('../utils/deviceTypeUtils', () => ({
  isTablet: false,
}));

describe('mock const example', () => {
  it('mock const `isTablet` to the value `true`', () => {
    DeviceTypeUtilsMock.isTablet = true;
  });

  it('mock const `isTablet` to the value `false`', () => {
    DeviceTypeUtilsMock.isTablet = false;
  });
});

Follow the guidance of the doc on jest.doMock()

The config.js file:

export const env = 'test';

The myComponent.js file:

import {env} from './config.js';

export const MyComponent = () => {
  if (env === 'prod') {
    return (<Text>Prod Env</Text>);
  } else if (env === 'test'){
    return (<Text>Test Env</Text>);
  } else {
    return (<Text>Dev Env</Text>);
  }
};

The myComponent.test.js file:

describe('Test MyComponent', () => {
  test('Test in prod env', () => {
    jest.doMock('./config', () => ({env: 'prod'}));
    const {MyComponent} = require('./myComponent.js');
    const myComp = mount(<MyComponent />);
    expect(myComp.find('Text')).toHaveText('Prod Env');
  });

  test('Test in test env', () => {
    jest.doMock('./config', () => ({env: 'test'}));
    const {MyComponent} = require('./myComponent.js');
    const myComp = mount(<MyComponent />);
    expect(myComp.find('Text')).toHaveText('Test Env');
  });

  test('Test in dev env', () => {
    jest.doMock('./config', () => ({env: 'dev'}));
    const {MyComponent} = require('./myComponent.js');
    const myComp = mount(<MyComponent />);
    expect(myComp.find('Text')).toHaveText('Dev Env');
  });
});

I just copy constants and assign them after each test case.

const constants = require('./constants');
const original = {...constants};
afterEach(() => {
    Object.assign(constants, original);
});
test('test1', () => {
    constants.ABC = 'whatever';
});
test('test2', () => {
    // constants.ABC is set back to original
});

I solved this by initializing constants from ContstantsFile.js in reducers. And placed it in redux store. As jest.mock was not able to mock the 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:
.......

Now we can easily mock the store in test.jsx and provide the values to constant that we want.

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', () => { .....

Now when the test runs it will always pick the constant value form mock store.

I have been able to do something similar by following the post at https://mikeborozdin.com/post/changing-jest-mocks-between-tests/

This creates a mock and then changes it for each test.

import * as constants from './constants'

jest.mock('./constants', () => ({
  __esModule: true,
  MY_CONSTANT: 'SOME OTHER DEFAULT',
}))

it("Should do something when MY_CONSTANT === "TEST, () => {
  constant.MY_CONSTANT = 'TEST'
  expect(constant.MY_CONSTANT).toBe('TEST')
})

it("Should do something else when MY_CONSTANT !== "TEST, () => {
  constant.MY_CONSTANT = 'NOT A TEST'
  expect(constant.MY_CONSTANT).toBe('NOT A TEST')
})

If you are using typescript then the mock needs to be cast to modify the mock values:

const mockConstants = constants as { MY_CONSTANT: string }
mockConstants.MY_CONSTANT = 'TEST'

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM