Rush Stack商店博客活动
跳到主要内容

Jest 插件

插件包@rushstack/heft-jest-plugin
插件名称jest-pluginJestPlugin.ts 实现
插件配置文件Jest 的 jest.config.json@rushstack/heft-config-file 加载用于 rigging
heft.json 选项IJestPluginOptions

此插件调用 Jest 测试框架进行单元测试。

何时使用它

我们推荐 Jest 有以下几个原因

  • 一体化:与 mocha 等需要多个组件组合在一起的框架不同,Jest 为您的测试运行器、断言库、模拟/间谍 API、代码检测、代码覆盖率和报告提供了单一的集成解决方案。Jest 还对 React 提供一流的支持。

  • 交互式:Jest 支持“监视模式”,以便在保存文件时自动重新运行测试,以及 快照测试,当合约发生变化时可以自动更新断言。

  • 隔离的运行时:Jest 在 Node.js 环境中运行 Web 测试,而不是启动 Web 浏览器,并利用 Node.js VM 功能来防止测试泄漏状态。

也就是说,如果你出于某种原因需要在其他运行时(如 Android 客户端或真实的 Web 浏览器)中运行测试,Jest 可能不是最佳选择。

package.json 依赖项

如果您使用的是标准 rig,例如 @rushstack/heft-node-rig@rushstack/heft-web-rig,那么 Jest 已经加载并配置好了。

否则,您需要将插件包添加到您的项目中

# If you are using Rush, run this shell command in your project folder:
rush add --package @rushstack/heft-jest-plugin --dev

该插件直接依赖于它需要的 Jest 包,因此您无需将 Jest 添加到项目的 package.json 文件中。

您的项目应该从 @types/heft-jest 而不是 @types/jest 获取类型定义

# If you are using Rush, run this shell command in your project folder:
rush add --package @types/heft-jest --dev --exact

# Because @types packages don't follow SemVer, it's a good idea to use --exact

...然后在您的 tsconfig.json 文件中引用 @types/heft-jest,例如

{
"extends": "./node_modules/@rushstack/heft-node-rig/profiles/default/tsconfig-base.json",
"compilerOptions": {
"types": [
"heft-jest", // <---- ADD THIS
"node"
]
}
}

配置

如果 Jest 没有由 rig 提供,则您的 heft.json 配置文件 可以像此示例一样调用它

<项目文件夹>/config/heft.json

{
"$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json",

"phasesByName": {
"build": {
. . .
},
"test": {
"phaseDependencies": ["build"],
"tasksByName": {
"jest": {
"taskPlugin": {
"pluginPackage": "@rushstack/heft-jest-plugin"
}
}
}
}
}
}

Heft 在标准路径 config/jest.config.json 中查找 Jest 的配置文件。虽然 Jest 本身支持其他配置文件名,甚至在 package.json 文件中嵌入设置,但 Heft 需要 config/jest.config.json 名称。在大型单体代码库中,强制使用一个标准文件名可以更容易地搜索这些文件,执行批量编辑以及在项目之间复制配置方案。

对于简单的设置,您的 Jest 配置应该扩展 Heft 的 jest-shared.config.json,例如

<项目文件夹>/config/jest.config.json

{
"extends": "@rushstack/heft-jest-plugin/includes/jest-shared.config.json"
}

或者,如果您使用的是 rig 包,例如 @rushstack/heft-web-rig,请指定 rig,例如

<项目文件夹>/config/jest.config.json

{
"extends": "@rushstack/heft-web-rig/profiles/library/config/jest.config.json"
}

(如果您维护自己的 rig,它应该从 @rushstack/heft-jest-plugin 扩展,以确保 Jest 使用 Heft 的转换器和解析器。)

注意:如果您发现自己经常向 jest.config.json 添加大量自定义设置,请创建一个 GitHub 问题并告诉我们。我们的目标是提供一种配置,最大程度地减少对项目特定定制的需求。

“extends” 字段

jest.config.json 中的 "extends" 字段是 Heft 特定的增强功能,如果 Jest 命令行在没有 Heft 的情况下调用,则不会起作用。此设置取代了 Jest 的 "preset" 字段,该字段的模块解析能力有限,不支持 rig。Heft 使用 @rushstack/heft-config-file 引擎解析 jest.config.json,完全支持 属性继承指令

如果出于某种原因您的 jest.config.json 需要直接可读,则可以使用 disableConfigurationModuleResolution 插件设置来恢复标准行为,缺点是您的 Jest 配置将不可 rigging。

例如

<项目文件夹>/config/heft.json

{
"$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json",

"phasesByName": {
"build": {
. . .
},
"test": {
"phaseDependencies": ["build"],
"tasksByName": {
"jest": {
"taskPlugin": {
"pluginPackage": "@rushstack/heft-jest-plugin",
"options": {
// (Not recommended) Disable Heft's support for rigs and the "extends" field
"disableConfigurationModuleResolution": true
}
}
}
}
}
}
}

与 ts-jest 的区别

按照惯例,Jest 通过名为 转换器 的插件来支持 TypeScript 编译,这些插件被建模为接收单个 .ts 文件作为输入,并返回 .js 文件和 .map 文件作为输出。官方的 babel-jest 转换器实际上确实一次编译一个文件,但这种方法不支持 const enum 等需要分析导入类型的语言特性。流行的 ts-jest 转换器通过执行完整的编译器分析并在每次调用转换器时重复使用它来解决这个问题,但这不支持其他构建步骤,例如预处理器。babel-jestts-jest 还会通过在运行测试时再次调用编译器来产生重大的性能成本。

Heft 采取了不同的方法,执行传统的构建,然后对输出调用 Jest。如果您的构建目标是浏览器运行时,您需要使用 additionalModuleKindsToEmit 设置在辅助文件夹中发出 CommonJS 输出。(发出额外文件仍然比两次调用编译器快得多。)除了避免冗余的编译器调用,Heft 的策略确保您的单元测试使用您的完整构建过程进行编译,包括任何预处理任务,例如 Sass 类型生成

heft-node-jest-tutorial 项目文件夹中可以找到一些关于模拟和其他 Jest 技术的有用示例。

使用 Jest 与 Heft 时的一些重要区别

  • 使用 heft 命令行调用 Jest。直接调用 jest 命令行不会调用 TypeScript,并且与 jest.config.json 中的 "extends" 字段不兼容。

  • 不要将 ts-jestbabel-jest 作为项目的依赖项添加。

  • 不要使用 import { mocked } from "ts-jest/utils";,而是使用由 @types/heft-jest 提供的全局 mocked() 函数。除了这个区别,ts-jest 的 API 文档 仍然适用于 Heft 的实现。

  • ts-jest 转换器将神奇地“提升”对 jest.mock(); 的调用。Heft 并不认为这是最佳实践。相反,请使用 @rushstack/hoist-jest-mock lint 规则来提醒开发人员手动提升他们的调用。它默认启用,使用 @rushstack/eslint-config

调试 Jest 测试

要调试您的 Jest 测试,建议创建 VS Code launch.json 文件,例如

<项目文件夹>/.vscode/launch.json

{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Debug Jest tests",
"program": "${workspaceFolder}/node_modules/@rushstack/heft/lib/start.js",
"cwd": "${workspaceFolder}",
"args": ["--debug", "test", "--clean"],
"console": "integratedTerminal",
"sourceMaps": true
},
]
}

这会在您的调试器中启动完整的 Heft 工具链。--debug 开关会阻止 Jest 作为单独的进程生成。--clean 标志是可选的,但会修复在罕见情况下 Jest 的“haste-map”可能会因运行中止而损坏的问题。

要将调试器限制为运行一个特定的测试,您可以添加 --test-name-pattern 参数。(有关命令行文档,请参阅 此处。)另一个选择是使用 Jest 的 test.only() API。

CLI 参数

heft-jest-plugin/heft-plugin.json 定义了这些参数

  --config RELATIVE_PATH
Use this parameter to control which Jest
configuration file will be used to run Jest tests. If
not specified, it will default to "config/jest.config.
json". This corresponds to the "--config" parameter
in Jest's documentation.
--debug-heft-reporter
Normally Heft installs a custom Jest reporter so that
test results are presented consistently with other
task logging. If you suspect a problem with the
HeftJestReporter, specify "--debug-heft-reporter" to
temporarily disable it so that you can compare with
how Jest's default reporter would have presented it.
Include this output in your bug report. Do not use
"--debug-heft-reporter" in production.
--detect-open-handles
Attempt to collect and print open handles preventing
Jest from exiting cleanly. This option has a
significant performance penalty and should only be
used for debugging. This corresponds to the
"--detectOpenHandles" parameter in Jest's
documentation.
--disable-code-coverage
Disable any configured code coverage. If code
coverage is not configured, this parameter has no
effect.
--find-related-tests SOURCE_FILE
Find and run the tests that cover a source file that
was passed in as an argument. This corresponds to the
"--findRelatedTests" parameter in Jest's
documentation. This parameter is not compatible with
watch mode.
--max-workers COUNT_OR_PERCENTAGE
Use this parameter to control maximum number of
worker processes tests are allowed to use. This
parameter is similar to the parameter noted in the
Jest documentation, and can either be an integer
representing the number of workers to spawn when
running tests, or can be a string representing a
percentage of the available CPUs on the machine to
utilize. Example values: "3", "25%"
--silent
Prevent tests from printing messages through the
console. This corresponds to the "--silent" parameter
in Jest's documentation.
-t REGEXP, --test-name-pattern REGEXP
Run only tests with a name that matches a regular
expression. The REGEXP is matched against the full
name, which is a combination of the test name and all
its surrounding describe blocks. This corresponds to
the "--testNamePattern" parameter in Jest's
documentation.
--test-path-ignore-patterns REGEXP
Avoid running tests with a source file path that
matches one ore more regular expressions. On Windows
you will need to use "/" instead of "\". This
corresponds to the "--testPathIgnorePatterns"
parameter in Jest's documentation.
--test-path-pattern REGEXP
Run only tests with a source file path that matches a
regular expression. On Windows you will need to use
"/" instead of "\". This corresponds to the
"--testPathPattern" parameter in Jest's documentation.
--test-timeout-ms TIMEOUT
Change the default timeout for tests; if a test
doesn't complete within this many milliseconds, it
will fail. Individual tests can override the default.
If unspecified, the default is normally 5000 ms. This
corresponds to the "--testTimeout" parameter in
Jest's documentation.
-u, --update-snapshots
Update Jest snapshots while running the tests. This
corresponds to the "--updateSnapshots" parameter in
Jest.

heft.json 插件选项

在您的 heft.json 中加载 @rushstack/heft-jest-plugin 时,可以使用 "options" 字段提供以下设置,这些设置可以内联提供

heft-plugins/heft-jest-plugin/src/JestPlugin.ts

export interface IJestPluginOptions {
configurationPath?: string;
debugHeftReporter?: boolean;
detectOpenHandles?: boolean;
disableCodeCoverage?: boolean;
disableConfigurationModuleResolution?: boolean;
findRelatedTests?: string[];
maxWorkers?: string;
passWithNoTests?: boolean;
silent?: boolean;
testNamePattern?: string;
testPathIgnorePatterns?: string;
testPathPattern?: string;
testTimeout?: number;
updateSnapshots?: boolean;
}

它们的功能与相应的命令行参数相同。

另请参阅