Resolving imports using webpack's worker-loader in Jest tests

▼魔方 西西 提交于 2020-01-03 07:09:42

问题


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')
        }
      },

回答1:


According to cpojer web-workers are not supported in Jest. You should use mocking, read more here




回答2:


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.



来源:https://stackoverflow.com/questions/42567535/resolving-imports-using-webpacks-worker-loader-in-jest-tests

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!