Given an npm package that needs to dynamically load a dependency from the root of the parent/referencing package, and that location isn't known until runtime, it has to do a dynamic require:
// config-fetcher.js
const path = require('path');
const getRunningProjectRoot = require('./get-running-project-root');'
module.exports = filename =>
require(path.resolve(getRunningProjectRoot(), filename));
(There's no guarantee that the module will be in node_modules
. It could be symlinked or loaded globally. So it can't use a static require.)
This is simplified from the real code, so unless you know of a way to require files non-dynamically relative to the running project root, this has to be this way.
Now, to test this, I'd prefer not to depend on any file that's actually on disk. However, Jest seemingly won't let you mock a nonexistent file. So if I try this:
const mockFileContents = {};
jest.mock('/absolute/filename.blah', () => mockFileContents);
// in preparation for wanting to do this:
const result = require('./config-fetcher')('/absolute/filename.blah');
expect(result).toBe(mockFileContents);
then I get an error from jest-resolve
, with file Resolver.resolveModule
throwing Error: Cannot find module '/absolute/filename.blah'.
I need to test some of the functionality of this dynamic requiring module, as it handles some cases of relative paths vs. absolute paths, and allows you to specify a special path through a Symbol, with one being for example applicationRoot
, so the module config-fetcher
does the hard work instead of the caller.
Could anyone offer guidance on how to test this module, or how to restructure so dynamic requires aren't needed or they are easier to test?
You can pass { virtual: true }
as options
in jest.mock
to mock a module that does not exist:
const { myFunc } = require('does not exist');
jest.mock('does not exist',
() => ({
myFunc: () => 'hello'
}),
{ virtual: true }
);
test('mock file that does not exist', () => {
expect(myFunc()).toBe('hello'); // Success!
});
Details
Jest
completely takes over the require
system for the code under test.
It has its own module cache and keeps track of module mocks.
As part of this system, Jest
allows you to create mocks for modules that do not actually exist.
You can pass options
as the third parameter to jest.mock
. Currently the only option is virtual
, and if it is true
then Jest
will simply add the result of calling the module factory function to the module cache and return it whenever it is required in the code under test.
Anyone tried testing dynamic import? Below sample codes to test. If I'm not using dynamic import jest.mock + virtual: true works.
const Routes = React.lazy(() => import('app2/routes'));
jest.mock('does not exist',
() => ({
myFunc: () => 'hello'
}),
{ virtual: true }
);
test('mock file that does not exist', () => {
expect(myFunc()).toBe('hello'); // Failed!
});
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