I am mocking a function from a file which uses moment
, Here is the file contents:
./utils/dateUtils:
import moment from 'moment-timezone'
export function getToday() {
return moment().tz(commonTimeZone)
}
./containers/someContainer.js:
import { getToday } from 'utils/dateUtils'
// Uses getToday in the component
./containers/someContainer.spec.js:
import moment from 'moment-timezone'
jest.mock('utils/dateUtils', () => {
return {
getToday : moment(new Date('2018-01-01'))
}
})
test throws this error:
● Test suite failed to run
/Users/bharat/Documents/redmart-repo/partner-portalv2/app/containers/Orders/PickupsContainer.test.js: babel-plugin-jest-hoist: The module factory of `jest.mock()` is not allowed to reference any out-of-scope variables.
Invalid variable access: moment
Whitelisted objects: Array, ArrayBuffer, Boolean, DataView, Date, Error, EvalError, Float32Array, Float64Array, Function, Generator, GeneratorFunction, Infinity, Int16Array, Int32Array, Int8Array, InternalError, Intl, JSON, Map, Math, NaN, Number, Object, Promise, Proxy, RangeError, ReferenceError, Reflect, RegExp, Set, String, Symbol, SyntaxError, TypeError, URIError, Uint16Array, Uint32Array, Uint8Array, Uint8ClampedArray, WeakMap, WeakSet, arguments, expect, jest, require, undefined, DTRACE_NET_SERVER_CONNECTION, DTRACE_NET_STREAM_END, DTRACE_HTTP_SERVER_REQUEST, DTRACE_HTTP_SERVER_RESPONSE, DTRACE_HTTP_CLIENT_REQUEST, DTRACE_HTTP_CLIENT_RESPONSE, global, process, Buffer, clearImmediate, clearInterval, clearTimeout, setImmediate, setInterval, setTimeout, console.
Note: This is a precaution to guard against uninitialized mock variables. If it is ensured that the mock is required lazily, variable names prefixed with `mock` are permitted.
at invariant (node_modules/babel-plugin-jest-hoist/build/index.js:12:11)
at newFn (node_modules/babel-traverse/lib/visitors.js:276:21)
at NodePath._call (node_modules/babel-traverse/lib/path/context.js:76:18)
at NodePath.call (node_modules/babel-traverse/lib/path/context.js:48:17)
at NodePath.visit (node_modules/babel-traverse/lib/path/context.js:105:12)
at TraversalContext.visitQueue (node_modules/babel-traverse/lib/context.js:150:16)
at TraversalContext.visitMultiple (node_modules/babel-traverse/lib/context.js:103:17)
Not sure what am missing here, does someone know how to fix this error.
P.S. I tried jest.doMock
but it doesn't mock anything.
Your problem is that jest.mock
calls are hoisted, which means they are put at the very top of the file. It's kind of tricky to find it in the docs, but they say it under jest.doMock
.
That makes your executed code to look something like this:
jest.mock('utils/dateUtils', () => {
return {
getToday : moment(new Date('2018-01-01'))
}
})
import moment from 'moment-timezone'
And as you can see moment
is used before imported, and thus the error message about referencing out-of-scope variables.
There are multiple ways to avoid this.
However, using jest.doMock
should have avoided the hoisting. I wonder if the path is missing something like '../utils...
–note the initial ../
–
There's also the fact that you are defining getToday
's mock as a value instead of a function, which might have made your tests fail when the module was actually mocked.
Anyways, there are two main ways to mock the module
The idea is to first mock the import and then define the mocked implementation.
import moment from 'moment-timezone'
import * as dateUtils from 'utils/dateUtils'
jest.mock('utils/dateUtils')
dateUtils.getToday = () => moment(new Date('2018-01-01'))
Here you create a mock file with the mocked implementation of the module that will be imported wherever you mock the module. That mock file has to live in a __mocks__
folder which needs to be at the same level of the file you want to mock. For example:
├── utils
│ ├── __mocks__
│ │ └── dateUtils.js
│ └── dateUtils.js
│
├── other folders
the code would look like this:
// utils/__mocks__/dateUtils.js
import moment from 'moment-timezone'
export const getToday = () => moment(new Date('2018-01-01'))
And the tests:
// containers/someContainer.spec.js
import * from './path/to/utils/dateUtils'
jest.mock('./path/to/utils/dateUtils')
// your tests here
You need to require the packages locally in a mock, this is to ensure no external variables are used -
jest.mock('utils/dateUtils', () => {
const moment = require("moment-timezone");
return {
getToday : moment(new Date('2018-01-01'))
}
})
Here's the link to the relevant issue - https://github.com/facebook/jest/issues/2567.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With