如何在 Jest 的自定义测试环境文件中使用 TypeScript?

Posted

技术标签:

【中文标题】如何在 Jest 的自定义测试环境文件中使用 TypeScript?【英文标题】:How to use TypeScript in a Custom Test Environment file in Jest? 【发布时间】:2020-01-29 11:19:39 【问题描述】:

我需要为我的测试启用一些全局变量,因此我设置了一个自定义环境以在我的jest.config.json 中的testEnvironment 选项中使用以实现此目的。

对于我们的项目,我们有一个用于setupFilesAfterEnv 选项的 TypeScript 文件,它工作得很好,但是testEnvironment 似乎只支持 ES5。有没有办法在这样的选项中使用 TypeScript?

我使用 ES5 语法成功创建了自定义 Jest 环境,但是由于我们要注入全局变量,因此我需要 TypeScript 来声明全局命名空间,请参阅:https://***.com/a/42304473/4655076。


  ///...
  setupFilesAfterEnv: ['<rootDir>/test/setup.ts'], // This works with ts
  testEnvironment: '<rootDir>/test/customJestEnvironment.ts', // This doesn't work with ts

【问题讨论】:

【参考方案1】:

您可以在项目的根目录下创建一个global.d.ts 文件。

然后您可以定义全局变量,如下所示。在我的例子中,它是一个 NestJS 应用程序,但你可以定义任何东西。

declare global 
  namespace NodeJS 
    interface Global 
      app: INestApplication;
    
  


这是客户端项目的另一个例子,我们定义了像innerWidth这样的窗口属性;

declare namespace NodeJS 
    interface Global 
        innerWidth: number;
        dispatchEvent: Function;
    

【讨论】:

需要能够设置这些变量,而不仅仅是声明类型。问题 id 基本上是如何为 Jest 提供 environment.ts。【参考方案2】:

在您的 .d.ts 定义文件中:

type MyGlobalFunctionType = (name: string) => void

将成员添加到浏览器的窗口上下文中:

interface Window 
  myGlobalFunction: MyGlobalFunctionType

NodeJS 也一样:

declare module NodeJS 
  interface Global 
    myGlobalFunction: MyGlobalFunctionType
  

现在你声明根变量

declare const myGlobalFunction: MyGlobalFunctionType;

然后在一个常规的 .ts 文件中,但作为副作用导入,你实际实现它:

global/* or window */.myGlobalFunction = function (name: string) 
  console.log("Hey !", name);
;

最后在别处使用它:

global/* or window */.myGlobalFunction("Ayush");

myGlobalFunction("Ayush");

【讨论】:

感谢您提供实现跨测试功能共享的 hacky 解决方案。问题是关于如何使用 TypeScript 编写环境。 IE。 setupFile 但全局。【参考方案3】:

您可能会觉得这很有帮助:Configure Jest global tests setup with .ts file (TypeScript)

但基本上你只能将编译好的 JS 文件作为环境传入。

你可以按照那篇文章的建议去做。但这对我来说并没有开箱即用。所以我手动编译我的环境。

在 package.json 中

"test": "tsc --lib es6 --target es6 --skipLibCheck -m commonjs --esModuleInterop true path/to/env.ts && 
jest --config=jest.config.js",

在 jest.config.js 中


  testEnvironment: '<rootDir>/path/to/env.js', // Note JS extension.

【讨论】:

【参考方案4】:

您可能知道,typescript 文件只是 javascript 的超集,以提供强大的类型检查。然而,Jest 的引擎/运行时需要您的文件为 CommonJS 格式的 javascript 文件。

您可以为这个env.ts 设置一个单独的tsconfig.env.json。在运行 jest 测试之前编译它并在你的jest.config.js 中使用编译的env.js

tsc -p tsconfig.env.json && jest

我也从未见过有人在 TS 中编写配置文件。

为什么是 CommonJS ?因为 jest 本质上是在节点之上运行的。 node 支持 CommonJS 格式的 Javascript 文件。 Node 最近也开始支持 es 模块!这是一件大事!

【讨论】:

【参考方案5】:

我通过使用ts-node 和以下命令解决了这个问题:

node -r ts-node/register ./node_modules/jest/bin/jest.js

这实质上是即时编译打字稿,因此 jest 接收发出的 javascript,而无需实际将打字稿源编译为 js。

您需要启用esModuleInterop TS 编译器选项才能正常工作。

TestEnvironment.ts


import NodeEnvironment from 'jest-environment-node';
import type Config from '@jest/types';

class TestEnvironment extends NodeEnvironment 
    
    constructor(config: Config.ProjectConfig) 
        super(config);
        // this.testPath = context.testPath;
        // this.docblockPragmas = context.docblockPragmas;
    

    public async setup(): Promise<void> 
        await super.setup();

        console.log('SETTING UP...');
        // await someSetupTasks(this.testPath);
        // this.global.someGlobalObject = createGlobalObject();
    
        // // Will trigger if docblock contains @my-custom-pragma my-pragma-value
        // if (this.docblockPragmas['my-custom-pragma'] === 'my-pragma-value') 
        //   // ...
        // 
    

    public async teardown(): Promise<void> 
        await super.teardown();
        console.log('TEARING DOWN!');
        // this.global.someGlobalObject = destroyGlobalObject();
        // await someTeardownTasks();
        
    


export default TestEnvironment;

但是,此解决方案将破坏 globalSetup -- 如果您使用 jest-ts

【讨论】:

以上是关于如何在 Jest 的自定义测试环境文件中使用 TypeScript?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 jest 不能为我正在测试的自定义 React 钩子提供 useTranslation 钩子?

如何使用不同的jest.config.js进行单元和组件测试?

如何在多个文件中运行 Jest-Puppeteer 测试

使用 SetTimeout 测试自定义钩子,使用 Jest 测试 useEffect

如何在 JEST 单元测试中修复“SVG 未定义”

如何配置 jest jsdom 环境?