Mock import() in jest - javascript

I'm struggling to test dynamic imports and I am wondering if there's a way to mock import() so I could simply mock the return value with Promise.resolve(mockComponent)?
The hook I want to test:
useEffect(() => {
async function setup() {
const { default: Player } = await import('#vimeo/player');
playerRef.current = new Player(
playerRef.current,
playerConfig,
);
playerRef.current.on('loaded', () => setIsLoading(false));
}
if (playerRef?.current) {
setup();
}
return () => playerRef.current?.destroy && playerRef.current.destroy();
}, [playerRef]);

Related

jest fn mock isnt working if not assigned in it and assigned in for each

i am trying to write tests using jest
the integration is a call that have a private function called test- gets called by funcTest
trying to mock implementation in before each how ever the mock does not work and it goes to the real function "test".
when i put the assignment (integration['test']=mockFn;) inside the "it" it works perfectly .
example for working code:
describe('test', () => {
const mockFn: jest.Mock = jest.fn();
beforeEach(async () => {
const integration = new integrationTest();
})
afterEach(() => {
jest.restoreAllMocks();
});
it('call mock implemntaion', async () => {
integration['test']=mockFn;
mockFn.mockImplementation(() => {
throw new Error('error');
});
try {
await integration.funcTest();
} catch (e) {
expect(e).toBeInstanceOf(Error);
}
});
})
example of not working code:
describe('test', () => {
const mockFn: jest.Mock = jest.fn();
beforeEach(async () => {
const integration = new integrationTest();
integration['test']=mockFn;
})
afterEach(() => {
jest.restoreAllMocks();
});
it('call mock implemntaion', async () => {
mockFn.mockImplementation(() => {
throw new Error('error');
});
try {
await integration.funcTest();
} catch (e) {
expect(e).toBeInstanceOf(Error);
}
});
})
why does this happen
and how to fix
thanks

get new Instance for function each test

I have some tests in one file,
I check my reducer with some case
My code looks like this
my code
import axiosInstance from '~/utils/network';
const fetcher = axiosInstance();
const fetchMiddleware = () => {
switch (type) {
case 'LOGOUT':{
try {
await fetcher.get(API.GET.LOGOUT_OPERATION);
dispatch({ type: 'LOGOUT_SUCCESS' });
} catch (err) {
dispatch({ type: 'LOGOUT_FAIL' });
}
});
}
}
}
my test
import axiosInstance from '../../src/utils/network';
import configureStore from 'redux-mock-store';
const middlewares = [fetchMiddleware, thunk];
const mockStore = configureStore(middlewares);
const store = mockStore(getInitialReducerState());
jest.mock('../../src/utils/network', () => {
const axiosInstance = jest.fn().mockImplementation(() => {
return {
get: jest.fn().mockImplementation(() => {
return {
headers: {},
};
}),
};
}) as any;
axiosInstance.configure = jest.fn();
return axiosInstance;
});
describe('test LOGOUT', () => {
beforeEach(() => {
store.clearActions();
});
it('should test be success', async () => {
await store.dispatch({
type: 'LOGOUT',
payload: { userName: 'testUserName' },
});
expect(store.getActions()).toContainEqual({
type: 'LOGOUT_SUCCESS',
});
});
it('should test be fail', async () => {
(axiosInstance as jest.Mock).mockImplementation(() => {
return {
get: jest.fn().mockImplementation(() => {
throw new Error(' ');
}),
};
});
await store.dispatch({
type: 'LOGOUT',
payload: { userName: 'testUserName' },
});
expect(store.getActions()).toContainEqual({
type: 'LOGOUT_FAIL',
});
});
});
I want to test two scenarios: success & fail,
I mock the axiosInstance function.
But even I override the mock in the second test I get the first mock because my code loads axiosInstance only once.
what can I do?
You need to use jest.isolateModules
Let's say we have 2 files:
./lib.js - this is your ~/utils/network
./repro.js - this is your file with the code under test
./lib.js:
export default function lib() {
return () => 10;
}
./repro.js:
import lib from './lib';
const fnInstance = lib();
export const fn = () => {
return fnInstance();
};
And the ./repro.test.js:
function getRepro(libMock) {
let repro;
// Must use isolateModules because we need to require a new module everytime
jest.isolateModules(() => {
jest.mock('./lib', () => {
return {
default: libMock,
};
});
repro = require('./repro');
});
// If for some reason in the future the behavior will change and this assertion will fail
// We can do a workaround by returning a Promise and the `resolve` callback will be called with the Component in the `isolateModules` function
// Or we can also put the whole test function inside the `isolateModules` (less preferred)
expect(repro).toBeDefined();
return repro;
}
describe('', () => {
it('should return 1', () => {
const { fn } = getRepro(function lib() {
return () => 1
});
expect(fn()).toEqual(1);
});
it('should return 2', () => {
const { fn } = getRepro(function lib() {
return () => 2
});
expect(fn()).toEqual(2);
});
});
It's preferable to use existing library to mock Axios, it saves from boilerplate code and potential mistakes in mock implementation; moxios has been already suggested.
It's inconvenient to mock axiosInstance per test because it has been already called on the import of tested module, so this requires it to be re-imported per test; another answer explains how it's done with jest.isolateModules.
Since axiosInstance is evaluated only once and is supposed to return mocked object, it's convenient to mock it once per test and then change implementations:
jest.mock('~/utils/network', () => {
const axiosMock = { get: jest.fn(), ... };
return {
axiosInstance: () => axiosMock;
};
});
const axiosMock = axiosInstance();
...
(axiosMock.get axiosInstance as jest.Mock).mockImplementation(() => {
throw new Error(' ');
});
await store.dispatch(...);
This requires to use jest.restoreAllMocks in beforeEach or similar Jest configuration option to avoid test cross-contamination.
Notice that Axios doesn't throw errors but rather return rejected promises, this may affect test results, see the note regarding the benefits of libraries.

How to write simple Jest preset

How to write own Jest preset with common beforeAll and afterAll?
I'm quite confused, seems that there is no related documentation.
There is the environment that you can extend this way:
JEST config:
module.exports = {
testEnvironment: './suites/future/jest.myEnv.js',
};
The jest.myEnv.js:
const NodeEnvironment = require('jest-environment-node');
const start = async () => {
console.log('START');
};
const stop = async () => {
console.log('STOP');
};
class TestEnvironment extends NodeEnvironment {
constructor(config) {
super(config);
}
async setup() {
await super.setup();
await start();
}
async teardown() {
await stop();
await super.teardown();
}
runScript(script) {
return super.runScript(script);
}
}
module.exports = TestEnvironment;

Jest mocking module that exports a class and functions

I have a module that exports a class and 2 functions and that module is imported into a file that is being tested.
someFile.js
const {theclass, thefunction} = require("theModule");
const getSomeFileData = () => {
let obj = new theclass();
//some logic
return obj.getData();
}
In the test file, I want to mock the module "theModule" and return a known value when the function obj.getData() is called. How would I go about mocking this module("theModule") when testing file "someFile.js"?
Edit:
.spec.ts
import { someFunction } from './index-test';
jest.mock('lodash', () => {
return {
uniqueId: () => 2,
};
});
describe('', () => {
it('', () => {
expect(someFunction()).toBe(2);
});
});
index-test.ts
import { uniqueId } from 'lodash';
export const someFunction = () => {
return uniqueId();
};

How to mock a module method during detox testing?

I'm trying mock a module during detox e2e testing :
beforeEach(async () => {
function mockFunctions() {
const original = require.requireActual('react-native-device-info');
return {
...original,
getDeviceCountry: jest.fn(() => {
return 'DE'
})
}
}
await jest.mock('react-native-device-info', () => mockFunctions)
})
It's not working, so I'm wondering if it's even possible?

Categories