在 Jest 测试中使用 webpack 的工作加载器解决导入问题

问题描述 投票:0回答:5

我正在编写一个 Jest 测试,但在解决此使用 webpack 的

worker-loader

的导入时遇到问题
import ImageInfoWorker from 'worker-loader?name=image_info!@WORKERS/image-info';

我还有一些其他别名在我的测试中可以正确解析,例如:

import Store from '@SUPPORT/store';
import * as api from '@SUPPORT/api';

这是来自

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"
  }
}

这是我的 webpack 配置的

resolve
部分:

        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')
        }
      },
webpack loader jestjs worker
5个回答
6
投票

如果不需要解析路径,可以使用

"moduleNameMapper"
忽略导入。

首先,创建一个包含

export default ''
的空模块。

接下来,将以下内容添加到您的

package.json

"jest": {
    "moduleNameMapper": {
        "^worker-plugin/loader.+$": "<rootDir>/EmptyModule"
    }
}

4
投票

这个解决方案对我有用。

在名为

__mocks__
的文件夹中创建一个包含您需要的模拟实现的workerMock.js 文件(当然您可以在任何您喜欢的地方创建它):

module.exports = Object.create(null);

然后在你的 jest 配置中添加以下配置:

"moduleNameMapper": {
  "\\.worker.js":"<rootDir>/__mocks__/workerMock.js"
}

2
投票

根据 cpojer Jest 不支持网络工作者。你应该使用模拟,阅读更多这里


1
投票

这种方法对我来说适用于内联样式和配置样式的工作导入。

Jest 尚不支持 Webpack 捆绑的 WebWorkers(据我所知),因此您必须嘲笑该工作人员。只需将工作程序的功能提取到外部文件,然后在工作程序文件中仅执行工作程序 y 位。

@WORKERS/imageInfo.js
— 你工人的“肉”:

export default imageInfoFunction(data) {
    //...
}

@WORKERS/imageInfo.worker.js
,工人肉汁:

import imageInfoFunction from "./imageInfo";

self.onmessage = async function (e) {
  self.postMessage(imageInfoFunction(e.data));
};

通过这种方式,您可以在测试实际功能时仅模拟实现的 Worker 部分:

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) });
  }
}

现在在

jest.config.js

module.exports = {
  moduleNameMapper: {
    "@WORKERS/(.*\\.worker\\.js)$": "<rootDir>/mocks/$1",
    "@WORKERS/(.*)$": "<rootDir>/js/workers/$1",
  },
};

注意,我没有包含内联

worker-loader
配置,但我跳过了
^(.*)
。这是有效的,因为我们不再需要
worker-loader
,因为我们正在嘲笑工人。第一个路径用于我们想要模拟的 .worker.js 文件,另一个路径用于我们想要测试的实际功能。以下也可以工作:

    "^(.*?)@WORKERS/(.*\\.worker\\.js)$": "<rootDir>/mocks/$2",
    "^(.*?)@WORKERS/(.*)$": "<rootDir>/js/workers/$2",

这个解决方案可能会被推广,这样所有的工人都会立即被嘲笑,欢迎提出建议。


0
投票

我对 html-loader 也有类似的问题。对我来说最简单的解决方案就是用虚拟的模拟导入:

jest.mock('worker-loader?name=image_info!@WORKERS/image-info', () => ({
  default: {
    // ... mock worker here
  }
}), { virtual: true });
© www.soinside.com 2019 - 2024. All rights reserved.