ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

用 ts-jest 在 Jest 中测试 TypeScript 项目:带 Source Map 支持的类型检查型 Transformer 全解析

用 ts-jest 在 Jest 中测试 TypeScript 项目:带 Source Map 支持的类型检查型 Transformer 全解析 测试开发工具【免费下载链接】ts-jestA Jest transformer with source map support that lets you use Jest to test projects written in TypeScript.项目地址https://gitcode.com/gh_mirrors/ts/ts-jest点击查看免费下载ts-jest是一个带 Source Map 支持的 Jest transformer为核心骨架结合仓库源码与配套文档为你梳理 ts-jest 的能力边界、与 Babel 方案的取舍、快速上手步骤、核心配置以及底层处理流程读完后你将能独立完成 TypeScript 项目的 Jest 测试环境搭建与调优。ts-jest 是什么根据项目官方定位见 README.md 与 website/docs/introduction.mdts-jest 是一个带 Source Map 支持的 Jest transformer它让你可以使用 Jest 测试用 TypeScript 编写的项目。围绕这一定位有三个关键能力值得展开它是一个 Jest transformer在 Jest 的代码转换链路中ts-jest 通过 Jest 的transform配置被挂载到.ts/.tsx等文件的处理流程上负责把这些文件编译成 Jest 可以执行的 JavaScript。带 Source Map 支持编译产物会携带 Source Map因此当测试失败或抛出异常时Jest 能够把堆栈信息映射回原始的.ts源文件错误定位准确、调试体验友好。支持 TypeScript 的全部特性包括类型检查这是 ts-jest 区别于纯转译方案如 Babel的核心卖点——它不只是去掉类型注解而是真正以 TypeScript 编译器 API 驱动在测试运行的同时进行类型检查见 website/docs/babel7-or-ts.md。一个值得注意的细节是ts-jest 项目自身也使用 ts-jest 来测试自己README 的 Built With 一节明确写了ts-jest uses itself for its tests。这意味着该项目每天都要在自己编译自己、自己测试自己的场景下运行其 transformer 的正确性与健壮性由项目自身的测试套件背书。入口与实现一个 createTransformer 的包从源码结构看ts-jest 的对外入口非常简洁。在 src/index.ts 中包默认导出了一个包含createTransformer(tsJestConfig?)方法的对象该方法返回TsJestTransformer实例export default { createTransformer(tsJestConfig?: TsJestTransformerOptions) { return new TsJestTransformer(tsJestConfig) }, }TsJestTransformer的核心实现位于 src/legacy/ts-jest-transformer.ts它实现了 Jest 的SyncTransformer接口提供了process/processAsync/getCacheKey/getCacheKeyAsync等方法并在构造时缓存ConfigSet、维护编译器实例与依赖图depGraphs从而保证同一测试进程中多次转换可以复用编译结果。为什么需要 transformerJest 并不原生理解 TypeScriptJest 本身只能直接执行 JavaScript。对于.ts/.tsx文件Jest 需要借助 transformer 在require()之前将其转换为 JavaScript。ts-jest 正是承担这一职责的官方推荐的 TypeScript transformer。安装并配置好 ts-jest 后Jest 对每个文件的处理流程大致是判断该文件是否有对应的 transform 规则若 transformer 提供了getCacheKey则用它计算缓存键若命中缓存则直接使用缓存内容否则调用transformer.process(...)编译文件并更新缓存最终require()编译后的产物。这一流程的详细 PlantUML 描述见仓库内部文档 website/docs/processing.md。ts-jest 与 Babel7 babel/preset-typescript 的对比2018 年 9 月 Babel 7 发布带来了babel/preset-typescript目标是让 Babel 用户无需迁移即可通过添加一个 preset 来尝试 TypeScript。那么既然 Babel 也能处理 TypeScript 语法为什么还需要 ts-jest官方文档 website/docs/babel7-or-ts.md 系统性地列出了babel/preset-typescript的局限——以下这些 TypeScript与 ts-jest能做到、而 Babel 做不到的事情正是选择 ts-jest 的关键理由。没有类型检查这是使用 TypeScript而非 Babel的最大优势开箱即用的类型检查。在使用 ts-jest 时文件在编译的同时会被类型检查从而获得更流畅的 TDD测试驱动开发体验。下面这段代码TypeScript 会直接报错而 Babel 则不会const str: string 42Babel 将文件当作相互孤立的模块逐一转译不存在项目的概念而 TypeScript 中文件属于一个项目project是在项目作用域内统一编译的。这意味着跨文件的类型关系、import类型推断等都能被正确校验。不支持namespacenamespace app { export const VERSION 1.0.0 export class App { /* ... */ } }Babel 的preset-typescript无法处理这种命名空间语法。不支持const enumconst enum Directions { Up, Down, Left, Right, }const enum会被 TypeScript 编译器内联展开Babel 按文件独立转译时无法完成这种跨文件的内联。不支持声明合并Babel 无法处理enum、namespace等类型的声明合并declaration merging特性。不支持 legacyimport/exportimport lib require(lib) // ... export myVar这类历史遗留的导入导出语法同样超出 Babel preset 的能力范围。开启 JSX 时不支持尖括号类型断言const val stringinput当 TSX/JSX 开启时尖括号会被解析为 JSX 语法Babel 无法把它当作类型断言处理而 ts-jest 基于 TypeScript 编译器则没有这个问题。总结如果你的项目用到了上述任一特性或者希望在测试运行过程中同步获得类型检查保障ts-jest 是比 Babel preset-typescript更完整的选择。快速开始安装、配置与运行以本仓库官方文档 website/docs/getting-started/installation.md 为准最快三步即可跑通。1. 安装依赖将 jest、typescript、ts-jest 与 types/jest 一次性安装为开发依赖npm install --save-dev jest typescript ts-jest types/jest如果你的项目使用 TypeScript 7不要直接安装typescript而应遵循官方推荐的并排side-by-side编译器方案详见 website/docs/guides/typescript-7.md。2. 创建 Jest 配置默认情况下 Jest 无需任何配置文件即可运行但它不会编译.ts文件。要让 Jest 使用 ts-jest 转译 TypeScript需要创建一份告知 Jest 使用 ts-jest preset 的配置文件。ts-jest 可以自动生成配置文件npx ts-jest config:init使用 yarn 时对应yarn ts-jest config:init该命令会创建一份基础的 Jest 配置文件告知 Jest 如何正确处理.ts文件。如果你在安装时遇到npx: command not found之类的报错可以把npx XXX替换为node node_modules/.bin/XXX在项目根目录下执行。此外你也可以使用create-jest命令同样以npx或yarn前缀来获得更多 Jest 相关选项但对其中的 TypeScript 询问要回答no然后在生成的jest.config.js中手动加入一行preset: ts-jest。官方给出的全流程速查表如下步骤npmyarn前置依赖TypeScript 4.3–6npm i -D jest typescriptyarn add --dev jest typescript安装npm i -D ts-jest types/jestyarn add --dev ts-jest types/jest创建配置npx ts-jest config:inityarn ts-jest config:init运行测试npm test或npx jestyarn test或yarn jest3. 运行测试直接执行npm test或npx jest即可。此时.ts/.tsx文件会被 ts-jest 转译且转换产物携带 Source Map错误堆栈会指向原始 TypeScript 源码。相关配置入口如需进一步定制 Jest请参考 Jest 官方配置指南ts-jest 特有的配置项汇总在 website/docs/getting-started/options.md。若使用 ESM 项目还需要阅读 website/docs/guides/esm-support.md。核心配置选项一览所有 ts-jest 专属选项都可以定义在 Jest 的transform配置对象中既可以写在package.json里也可以通过jest.config.js或jest.config.ts文件提供。当使用 TypeScript 编写 Jest 配置文件时Jest 会借助ts-node来编译该配置文件ts-jest 不参与这一过程见 website/docs/getting-started/options.md 的注意事项。官方列出的选项总表如下选项说明类型默认值compiler用作编译器的 TypeScript 模块stringtypescripttsconfigTypeScript 编译相关配置string|object|booleanautoisolatedModules关闭类型检查按隔离模块编译booleandisabledastTransformers自定义 TypeScript AST 转换器objectautodiagnostics诊断信息相关配置boolean|objectenabledbabelConfigBabel(Jest) 相关配置boolean|string|objectdisabledstringifyContentPathRegex匹配的文件将变成返回自身内容的模块string|RegExpdisableduseESM启用 ESM 支持booleanauto注意如果你使用自定义的transform配置请从 Jest 配置中移除preset避免 Jest 不能正确转换文件官方文档明确警告过这一点。tsconfig 选项的三种用法tsconfig选项允许你指定要使用的tsconfigJSON 文件也可以直接内联一份 compilerOptions 对象详见 website/docs/getting-started/options/tsconfig.md。默认情况下ts-jest 会在你的项目中查找tsconfig.json若找不到则使用 TypeScript 默认的 compilerOptions唯一例外是target使用ES2015而不是默认的ES5。如果你希望即使项目里存在tsconfig.json也强制使用默认值可以将该选项设为false。指定配置文件路径路径相对于启动 Jest 的目录也支持rootDir前缀import type { Config } from jest const jestConfig: JestConfigWithTsJest { // [...] transform: { // ^.\\.[tj]sx?$ 处理 ts,js,tsx,jsx // ^.\\.m?[tj]sx?$ 处理 ts,js,tsx,jsx,mts,mjs,mtsx,mjsx ^.\\.tsx?$: [ ts-jest, { tsconfig: tsconfig.test.json, }, ], }, } export default jestConfig内联 compilerOptions等同于写在tsconfig.json的compilerOptions里的对象const jestConfig: Config { // [...] transform: { ^.\\.tsx?$: [ ts-jest, { tsconfig: { importHelpers: true, }, }, ], }, }禁用自动查找const jestConfig: Config { // [...] transform: { ^.\\.tsx?$: [ ts-jest, { tsconfig: false, }, ], }, }isolatedModules以性能换取类型检查默认情况下 ts-jest 在项目上下文中使用 TypeScript 编译器具备完整的类型检查与全部特性。但它也可以把每个文件当作独立的隔离模块分别编译这就是isolatedModules选项默认false的作用详见 website/docs/getting-started/options/isolatedModules.md。开启后会失去类型检查能力以及const enum等特性但在配合jest --no-cache运行时测试会明显更快const jestConfig: Config { // [...] transform: { ^.\\.tsx?$: [ ts-jest, { isolatedModules: true, }, ], }, }注意该配置页已被标记为 DEPRECATED官方建议改用tsconfig.json中的isolatedModules选项未来大版本中会移除 ts-jest 侧的isolatedModules配置。性能提示与注意事项使用isolatedModules: false即开启类型检查时性能相对更慢可以通过收窄tsconfig.json中include的文件范围来提升性能——include提供的文件越少测试运行能获得的性能提升越大{ // ...其他配置 include: [my-typings/*, my-global-modules/*] }但代价是 ts-jest 可能无法识别所有打算配合 Jest 使用的文件自定义类型、全局模块等可能出问题。官方给出的建议是让测试环境真正需要的文件被include的 glob 模式覆盖到从而兼顾性能提升与不破坏现有行为。预设Presets与编程式配置Jest 中的 preset 是预定义的配置用来标准化测试环境的搭建。ts-jest 提供了多组高度定制化的 preset官方推荐的最佳实践是调用 preset 创建函数来生成并可扩展配置而将旧的字符串形式 preset 视为 legacy 方案详见 website/docs/getting-started/presets.md。以最常用的createDefaultPreset为例其实现见 src/presets/create-jest-preset.tsimport { createDefaultPreset, type JestConfigWithTsJest } from ts-jest const presetConfig createDefaultPreset({ //...options }) const jestConfig: JestConfigWithTsJest { ...presetConfig, } export default jestConfigcreateDefaultPreset(options)返回一个包含transform属性的对象将^..tsx?$映射到[ts-jest, TsJestTransformerOptions]。可选参数包括tsconfig、isolatedModules、compiler、astTransformers、diagnostics、stringifyContentPathRegex每个参数都有独立的官方说明页见 website/docs/getting-started/options 下的子页面。除默认 preset 外ts-jest 还提供createDefaultLegacyPresetlegacy 版默认配置transform 指向ts-jest/legacycreateDefaultEsmPresetESM 配置处理.ts/.mts/.tsx/.mtsx并额外设置extensionsToTreatAsEsm与useESM: truecreateJsWithTsPreset同时处理 JS 与 TS 文件.js/.jsx/.ts/.tsxcreateJsWithTsEsmPresetESM 版 JSTS 配置createJsWithBabelPreset及 ESM/legacy 变体TS 文件交给 ts-jestJS 文件交给babel-jest。从源码可以看到这些函数的真实返回结构例如createJsWithBabelPreset在 src/presets/create-jest-preset.ts 中同时设置了[JS_TRANSFORM_PATTERN]: babel-jest与[TS_TRANSFORM_PATTERN]: [ts-jest, ...]两条规则。旧式字符串 preset如ts-jest/presets/default、ts-jest/presets/js-with-ts等仍可使用但官方明确警告ts-jest 不推荐使用 legacy preset因为这种方式不利于灵活配置 Jest且会在下个大版本中移除用户被强烈建议迁移到上述函数式写法。底层处理流程从源文件到可执行代码如果你关心 ts-jest 内部到底做了什么仓库内部文档 website/docs/processing.md 给出了完整的处理流程该文档定位为贡献者内部文档。结合 src/legacy/ts-jest-transformer.ts 的实现整个转换链路可以概括为入口tsJest.process(source)Jest 调用 transformer 的process方法传入源文件内容与转换配置。可选的字符串化若命中stringifyContentPathRegex文件内容会被 JSON 序列化为模块常用于把.json、模板等文件直接变成返回自身内容的模块。.d.ts声明文件直接清空内容定义文件无需编译直接产出空内容。编译器选择若未开启隔离模块则创建并缓存 TypeScript Language Service以项目上下文编译若开启则逐文件用transpileModule独立编译。持久缓存检查命中持久缓存则直接恢复内存缓存否则执行编译。自定义 AST transformers在这里执行jest.mock的提升hoisting以及用户基于配置定义的 AST 转换对应astTransformers选项。修复 Source Map对编译产物修正 Source Map更新内存缓存与持久缓存。可选 Babel 二次处理若配置了babelConfig调用babel-jest的 process 再次转换。afterProcess钩子若存在该钩子且返回了内容则以其返回值作为新源码。从 src/legacy/ts-jest-transformer.ts 可以看到TsJestTransformer实现了 Jest 的SyncTransformer并通过静态缓存_cachedConfigSets在不同测试运行之间复用ConfigSet与编译器实例这正是 ts-jest 在 watch 模式下依然能保持较快编译速度的实现基础。版本策略与注意事项ts-jest不采用语义化版本SemVer。官方在 website/docs/introduction.md 中特别强调我们不进行语义化版本管理23.10是一次重写。运行npm i -D ts-jest23.10.0可以回退到之前的版本。这意味着从旧版本升级到23.10及以上时需要留意可能的行为变化如果需要兼容旧行为可以用上面的命令锁定23.10.0版本。项目主版本号跟随 Jest 的主版本但整体版本策略并非严格 SemVer详见 README.md 的 Versioning 一节。另外website/docs/getting-started/version-checking.md 记载了一个已被标记 DEPRECATED 的版本检查机制ts-jest 默认支持一个范围的 jest/typescript 版本使用不兼容版本时会收到警告可通过设置环境变量TS_JEST_DISABLE_VER_CHECKERtrue关闭Linux/macOS 用exportWindows 用set。该机制已废弃未来将由package.json中原生的peerDependencies检查取代。TypeScript 7 用户的特别说明如果你的项目使用 TypeScript 7官方建议采用并排编译器方案详见 website/docs/guides/typescript-7.mdTypeScript 7.0 自带原生tsc但不提供 ts-jest 转换所需的 JavaScript 编译器 API。应通过 npm 别名同时安装两个编译器npm install --save-dev typescript/nativenpm:typescript^7.0.2 typescriptnpm:typescript/typescript6^6.0.2这样npx tsc运行原生 TypeScript 7 编译器而 ts-jest 通过typescript别名获得其需要的 TypeScript 6 JavaScript API。不要将 ts-jest 的compiler选项指向typescript/native因为 TypeScript 7.0 没有兼容的 JavaScript APIts-jest 会在加载该包时提前停止并给出可操作的配置错误。小结ts-jest 以带 Source Map 支持的 Jest transformer为定位提供了 Babel 方案所不具备的完整类型检查与全部 TypeScript 特性支持。通过本文你可以理解 ts-jest 与 Babel7 babel/preset-typescript的取舍类型检查、namespace、const enum、声明合并、legacy 导入导出、JSX 下尖括号断言等按速查表完成安装、config:init配置与测试运行掌握tsconfig、isolatedModules、diagnostics、astTransformers等核心选项及其默认行为了解底层编译流程与缓存机制为性能调优和问题排查打基础明确非 SemVer 版本策略与 TypeScript 7 的并排安装方案。需要继续深入时可依次阅读仓库中的 website/docs/getting-started/installation.md、website/docs/getting-started/options.md、website/docs/getting-started/presets.md 以及 website/docs/processing.md并结合 src/legacy/ts-jest-transformer.ts 与 src/presets/create-jest-preset.ts 阅读源码实现。赞分享测试开发工具【免费下载链接】ts-jestA Jest transformer with source map support that lets you use Jest to test projects written in TypeScript.项目地址https://gitcode.com/gh_mirrors/ts/ts-jest点击查看免费下载相关推荐掌握RecyclerViewAnimators4cq Controller的7个配置方法duration/firstOnly/偏移参数完整参考掌握RecyclerViewAnimators4cq Controller的7个配置方法duration/firstOnly/偏移参数完整参考 Recycle测试开发工具ts-jest 入门指南用 Jest 测试 TypeScript 项目的 Transformer 配置与实践ts jest 入门指南用 Jest 测试 TypeScript 项目的 Transformer 配置与实践 ts jest 是一个带源码映射source测试开发工具UE4SS终极指南10分钟解锁虚幻引擎游戏无限可能UE4SS终极指南10分钟解锁虚幻引擎游戏无限可能 还在为虚幻引擎游戏的Mod安装而烦恼吗每次看到精彩的游戏修改内容却因为复杂的安装流程而望而却步今天游戏开发逆向工程上一篇OSS-Fuzz 术语指南ClusterFuzz、Fuzz Target、Job Type、Sanitizer 与架构体系详解下一篇Knip扫描规则原理如何自定义检测逻辑适配业务需求创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表