Reputation: 4368
I'm writing a Jest test and am having trouble resolving this import which uses webpack's worker-loader
import ImageInfoWorker from 'worker-loader?name=image_info!@WORKERS/image-info';
I have some other aliases which are resolving properly in my tests, such as:
import Store from '@SUPPORT/store';
import * as api from '@SUPPORT/api';
Here is the relevant snippet from package.json
"jest": {
"moduleFileExtensions": ["js", "jsx"],
"moduleNameMapper": {
"^@CSS/(.*)$": "<rootDir>/css/$1",
"^@COMPONENTS/(.*)$": "<rootDir>/js/components/$1",
"^@MODELS/(.*)$": "<rootDir>/js/models/$1",
"^@STORES/(.*)$": "<rootDir>/js/stores/$1",
"^@SUPPORT/(.*)$": "<rootDir>/js/support/$1",
"^(.*?)@WORKERS/(.*)$": "$1<rootDir>/js/workers/$2"
}
}
And here is the resolve
section of my webpack config:
resolve: {
extensions: ['.js', '.jsx'],
modules: [process.env.NODE_PATH, 'node_modules'],
alias: {
'@CSS': path.join(projectRoot, 'css'),
'@COMPONENTS': path.join(projectRoot, 'js', 'components'),
'@MODELS': path.join(projectRoot, 'js', 'models'),
'@STORES': path.join(projectRoot, 'js', 'stores'),
'@SUPPORT': path.join(projectRoot, 'js', 'support'),
'@WORKERS': path.join(projectRoot, 'js', 'workers')
}
},
Upvotes: 22
Views: 8256
Reputation: 1
I had similar issue with html-loader. Simplest solution for me was to just mock the import with virtual one:
jest.mock('worker-loader?name=image_info!@WORKERS/image-info', () => ({
default: {
// ... mock worker here
}
}), { virtual: true });
Upvotes: 0
Reputation: 384
This solution worked for me.
Create a workerMock.js file with mocking implementation you need in a folder called __mocks__
(of course you can create it anywhere you like):
module.exports = Object.create(null);
Then in your jest config add configuration below:
"moduleNameMapper": {
"\\.worker.js":"<rootDir>/__mocks__/workerMock.js"
}
Upvotes: 4
Reputation: 1753
If you don't need the path to be resolved, you can use "moduleNameMapper"
to ignore the import.
First, create an empty module that contains export default ''
.
Next, add the following to your package.json
:
"jest": {
"moduleNameMapper": {
"^worker-plugin/loader.+$": "<rootDir>/EmptyModule"
}
}
Upvotes: 6
Reputation: 1594
This approach worked for me with both inline-style and config-style worker imports.
Webpack-bundled WebWorkers are not suported by Jest yet (not that I know of), so you have to mock the worker. Simply extract the functionality of your worker to an external file, and in the worker file perform just the worker-y bits.
@WORKERS/imageInfo.js
— the “meat” of your worker:
export default imageInfoFunction(data) {
//...
}
@WORKERS/imageInfo.worker.js
, the worker gravy:
import imageInfoFunction from "./imageInfo";
self.onmessage = async function (e) {
self.postMessage(imageInfoFunction(e.data));
};
This way you can mock just the Worker part of your implementation, while testing the actual functionality:
mocks/imageInfo.worker.js
import imageInfoFunction from "@WORKERS/imageInfo";
export default class ImageInfoWorker {
constructor() {
// should be overwritten by the code using the worker
this.onmessage = () => { };
}
// mock expects data: { } instead of e: { data: { } }
postMessage(data) {
// actual worker implementation wraps argument into { data: arg },
// so the mock needs to fake it
this.onmessage({ data: imageInfoFunction (data) });
}
}
Now in jest.config.js
:
module.exports = {
moduleNameMapper: {
"@WORKERS/(.*\\.worker\\.js)$": "<rootDir>/mocks/$1",
"@WORKERS/(.*)$": "<rootDir>/js/workers/$1",
},
};
Note I didn't include the inline worker-loader
config, but I skipped the ^(.*)
. This works because we don't need worker-loader
anymore since we are mocking the worker. The first path is for .worker.js files that we want to mock and the other is for actual functionality that we want to test. The following would also work:
"^(.*?)@WORKERS/(.*\\.worker\\.js)$": "<rootDir>/mocks/$2",
"^(.*?)@WORKERS/(.*)$": "<rootDir>/js/workers/$2",
This solution could probably be generalized so that all workers are mocked at once, suggestions welcome.
Upvotes: 1