Skip to main content
Version: 29.7

与 webpack 一起使用

Jest 可用于使用 webpack 管理资源、样式和编译的项目。与其他工具相比,webpack 确实带来了一些独特的挑战,因为它直接与你的应用集成,以允许管理样式表、图片和字体等资源,以及编译为 JavaScript 语言和工具的广阔生态系统。

¥Jest can be used in projects that use webpack to manage assets, styles, and compilation. webpack does offer some unique challenges over other tools because it integrates directly with your application to allow managing stylesheets, assets like images and fonts, along with the expansive ecosystem of compile-to-JavaScript languages and tools.

一个 webpack 示例

¥A webpack example

让我们从一种常见的 webpack 配置文件开始,并将其转换为 Jest 设置。

¥Let's start with a common sort of webpack config file and translate it to a Jest setup.

webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.jsx?$/,
exclude: ['node_modules'],
use: ['babel-loader'],
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
{
test: /\.gif$/,
type: 'asset/inline',
},
{
test: /\.(ttf|eot|svg)$/,
type: 'asset/resource',
},
],
},
resolve: {
alias: {
config$: './configs/app-config.js',
react: './vendor/react-master',
},
extensions: ['.js', '.jsx'],
modules: [
'node_modules',
'bower_components',
'shared',
'/shared/vendor/modules',
],
},
};

如果你有由 Babel 转换的 JavaScript 文件,你可以通过安装 babel-jest 插件来 启用对 Babel 的支持。非 Babel JavaScript 转换可以使用 Jest 的 transform 配置选项来处理。

¥If you have JavaScript files that are transformed by Babel, you can enable support for Babel by installing the babel-jest plugin. Non-Babel JavaScript transformations can be handled with Jest's transform config option.

处理静态资源

¥Handling Static Assets

接下来,让我们配置 Jest 以优雅地处理样式表和图片等资源文件。通常,这些文件在测试中并不是特别有用,因此我们可以安全地模拟它们。但是,如果你使用 CSS 模块,那么最好为你的 className 查找模拟代理。

¥Next, let's configure Jest to gracefully handle asset files such as stylesheets and images. Usually, these files aren't particularly useful in tests so we can safely mock them out. However, if you are using CSS Modules then it's better to mock a proxy for your className lookups.

jest.config.js
module.exports = {
moduleNameMapper: {
'\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$':
'<rootDir>/__mocks__/fileMock.js',
'\\.(css|less)$': '<rootDir>/__mocks__/styleMock.js',
},
};

以及模拟文件本身:

¥And the mock files themselves:

__mocks__/styleMock.js
module.exports = {};
__mocks__/fileMock.js
module.exports = 'test-file-stub';

模拟 CSS 模块

¥Mocking CSS Modules

你可以使用 ES6 代理 来模拟 CSS 模块

¥You can use an ES6 Proxy to mock CSS Modules:

npm install --save-dev identity-obj-proxy

然后,样式对象上的所有 className 查找都将按原样返回(例如 styles.foobar === 'foobar')。这对于 React 快照测试 来说非常方便。

¥Then all your className lookups on the styles object will be returned as-is (e.g., styles.foobar === 'foobar'). This is pretty handy for React Snapshot Testing.

jest.config.js (for CSS Modules)
module.exports = {
moduleNameMapper: {
'\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$':
'<rootDir>/__mocks__/fileMock.js',
'\\.(css|less)$': 'identity-obj-proxy',
},
};

如果 moduleNameMapper 无法满足你的要求,你可以使用 Jest 的 transform 配置选项来指定资源的转换方式。例如,返回文件基本名称的转换器(例如 require('logo.jpg'); 返回 'logo')可以写为:

¥If moduleNameMapper cannot fulfill your requirements, you can use Jest's transform config option to specify how assets are transformed. For example, a transformer that returns the basename of a file (such that require('logo.jpg'); returns 'logo') can be written as:

fileTransformer.js
const path = require('path');

module.exports = {
process(sourceText, sourcePath, options) {
return {
code: `module.exports = ${JSON.stringify(path.basename(sourcePath))};`,
};
},
};
jest.config.js (for custom transformers and CSS Modules)
module.exports = {
moduleNameMapper: {
'\\.(css|less)$': 'identity-obj-proxy',
},
transform: {
'\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$':
'<rootDir>/fileTransformer.js',
},
};

我们告诉 Jest 忽略与样式表或图片扩展名匹配的文件,而是需要我们的模拟文件。你可以调整正则表达式以匹配 webpack 配置处理的文件类型。

¥We've told Jest to ignore files matching a stylesheet or image extension, and instead, require our mock files. You can adjust the regular expression to match the file types your webpack config handles.

提示

如果你希望将默认的 babel-jest 转换器与其他代码预处理器一起使用,请记住显式包含它:

¥Remember to include the default babel-jest transformer explicitly, if you wish to use it alongside with additional code preprocessors:

"transform": {
"\\.[jt]sx?$": "babel-jest",
"\\.css$": "some-css-transformer",
}

配置 Jest 来查找我们的文件

¥Configuring Jest to find our files

现在 Jest 知道如何处理我们的文件,我们需要告诉它如何找到它们。对于 webpack 的 modulesextensions 选项,Jest 的 moduleDirectoriesmoduleFileExtensions 选项中有直接的类似物。

¥Now that Jest knows how to process our files, we need to tell it how to find them. For webpack's modules, and extensions options there are direct analogs in Jest's moduleDirectories and moduleFileExtensions options.

jest.config.js
module.exports = {
moduleFileExtensions: ['js', 'jsx'],
moduleDirectories: ['node_modules', 'bower_components', 'shared'],

moduleNameMapper: {
'\\.(css|less)$': '<rootDir>/__mocks__/styleMock.js',
'\\.(gif|ttf|eot|svg)$': '<rootDir>/__mocks__/fileMock.js',
},
};
注意

<rootDir> 是一个特殊的令牌,它会被 Jest 替换为项目的根目录。大多数情况下,这将是 package.json 所在的文件夹,除非你在配置中指定自定义 rootDir 选项。

¥<rootDir> is a special token that gets replaced by Jest with the root of your project. Most of the time this will be the folder where your package.json is located unless you specify a custom rootDir option in your configuration.

同样,Jest 的 Webpack resolve.roots(设置 NODE_PATH 的替代方案)的对应项是 modulePaths

¥Similarly, Jest's counterpart for Webpack's resolve.roots (an alternative to setting NODE_PATH) is modulePaths.

jest.config.js
module.exports = {
modulePaths: ['/shared/vendor/modules'],
moduleFileExtensions: ['js', 'jsx'],
moduleDirectories: ['node_modules', 'bower_components', 'shared'],
moduleNameMapper: {
'\\.(css|less)$': '<rootDir>/__mocks__/styleMock.js',
'\\.(gif|ttf|eot|svg)$': '<rootDir>/__mocks__/fileMock.js',
},
};

最后,我们必须处理 webpack alias。为此,我们可以再次使用 moduleNameMapper 选项。

¥And finally, we have to handle the webpack alias. For that, we can make use of the moduleNameMapper option again.

jest.config.js
module.exports = {
modulePaths: ['/shared/vendor/modules'],
moduleFileExtensions: ['js', 'jsx'],
moduleDirectories: ['node_modules', 'bower_components', 'shared'],

moduleNameMapper: {
'\\.(css|less)$': '<rootDir>/__mocks__/styleMock.js',
'\\.(gif|ttf|eot|svg)$': '<rootDir>/__mocks__/fileMock.js',

'^react(.*)$': '<rootDir>/vendor/react-master$1',
'^config$': '<rootDir>/configs/app-config.js',
},
};

就是这样!webpack 是一个复杂而灵活的工具,因此你可能需要进行一些调整才能满足特定应用的需求。幸运的是,对于大多数项目来说,Jest 应该足够灵活来处理你的 webpack 配置。

¥That's it! webpack is a complex and flexible tool, so you may have to make some adjustments to handle your specific application's needs. Luckily for most projects, Jest should be more than flexible enough to handle your webpack config.

提示

对于更复杂的 webpack 配置,你可能还需要研究以下项目:babel-plugin-webpack-loaders

¥For more complex webpack configurations, you may also want to investigate projects such as: babel-plugin-webpack-loaders.

与 webpack 一起使用

¥Using with webpack

除了如前所述安装 babel-jest 之外,你还需要添加 @babel/preset-env,如下所示:

¥In addition to installing babel-jest as described earlier, you'll need to add @babel/preset-env like so:

npm install --save-dev @babel/preset-env

然后,你需要按如下方式配置 Babel:

¥Then, you'll want to configure Babel as follows:

.babelrc
{
"presets": ["@babel/preset-env"]
}
提示

Jest 缓存文件以加快测试执行速度。如果你更新了 .babelrc 并且 Jest 未按预期工作,请尝试通过运行 jest --clearCache 来清除缓存。

¥Jest caches files to speed up test execution. If you updated .babelrc and Jest is not working as expected, try clearing the cache by running jest --clearCache.

提示

如果你使用动态导入(import('some-file.js').then(module => ...)),则需要启用 dynamic-import-node 插件。

¥If you use dynamic imports (import('some-file.js').then(module => ...)), you need to enable the dynamic-import-node plugin.

.babelrc
{
"presets": [["env", {"modules": false}]],

"plugins": ["syntax-dynamic-import"],

"env": {
"test": {
"plugins": ["dynamic-import-node"]
}
}
}

有关如何将 Jest 与 webpack 与 React 结合使用的示例,你可以查看 此处

¥For an example of how to use Jest with webpack with React, you can view one here.