【问题标题】:Avoid the need to cast mocked typescript imports避免需要转换模拟的打字稿导入
【发布时间】:2017-06-23 18:01:35
【问题描述】:

我正在导入一个模拟函数,但由于 Typescript 似乎不知道 Jest 将导入更改为模拟,因此我必须先转换导入的函数,然后才能使用 mockReturnValue 等模拟方法。

jest.mock('../myImport');
import { thisFunctionIsMocked } from '../myImport'

/* ... */

(<Mock<any>>thisFunctionIsMocked).mockReturnValue(42);

如果我不强制导入,Typescript 声称模拟函数方法不存在。有没有更好的方法来做到这一点?

【问题讨论】:

    标签: typescript jestjs


    【解决方案1】:

    我一直在寻找相同的东西。不幸的是,关于如何处理这个问题似乎并不多。不过也有一些替代品。

    1) 你已经在做的语法略有不同:

    (thisFunctionIsMocked as jest.Mock).mockReturnValue(42);
    

    2) 使用require 并在那里转换:

    const thisFunctionIsMocked = require('../myImport') as jest.Mock;
    

    更新:

    ts-jest 现在有一个可以使用的mocked helper。引用 mocked 导入时仍然需要使用它,但这意味着原始源的类型签名不会丢失:

    import { mocked } from 'ts-jest/utils';
    
    test('direct', () => {
      foo.name();
      expect(mocked(foo.name).mock.calls).toHaveLength(1);
    });
    

    【讨论】:

      【解决方案2】:

      在 Jest 可以拦截 ES6 模块以应用模拟之前,这对于我的用例来说是最简单和最干净的方式。

      jest.mock('./some/resource', () => ({
        thisFunctionIsMocked: jest.fn()
      })
      
      const { thisFunctionIsMocked } = require('./some/resource');
      
      test('works', () => {
        thisFunctionIsMocked.mockReturnValue('cool result');
        expect(thisFunctionIsMocked()).toEqual('cool result');
      });
      

      注意使用require 而不是import

      如果您使用模块模拟,则需要使用 CommonJS 语法导出它们:

      module.exports = {
        thisFunctionIsMocked: jest.fn()
      };
      

      再次,因为 Jest 似乎没有拦截 ES6 模块。

      【讨论】:

        【解决方案3】:

        这是@lobati 对具有多个需要处理的导出的模拟模块的回答的一种变体:

        import * as myModuleMock from 'path/to/my/module';
        const { someExport, someOtherExport } = 
            require('path/to/my/__mocks__/module') as typeof myModuleMock;
        
        // `someExport` and `someOtherExport` will be cast correctly 
        /// using the type info from the actual mock
        

        这避免了从模拟模块复制类型信息并不得不处理每个导出。

        【讨论】:

          【解决方案4】:

          Module augmentation可以使用,但是如果你像这样导出函数就不行了:

          export function thisFunctionIsMocked() { .... }
          

          那是因为您只能添加到类型,而不能更改现有类型。
          但是如果你像这样导出:

          export interface MyMockedFunction {
              (): void;
          }
          
          export const thisFunctionIsMocked = function() { ... } as MyMockedFunction;
          

          那么你应该能够增强它:

          jest.mock('../myImport');
          import { thisFunctionIsMocked } from '../myImport'
          
          declare module "../myImport" {
              interface MyMockedFunction {
                  mockReturnValue(value: number): any;
              }
          }
          
          thisFunctionIsMocked.mockReturnValue(42);
          

          【讨论】:

          • 感谢您的建议。我不知道模块扩充。但老实说,考虑到这个和铸造之间的选择,我会输入 cast。我正在尝试减少编写测试所需的开销和视觉混乱。理想情况下,在调用jest.mock 之后,Typescript 会以某种方式知道导入的函数是不同的。也许工具级解决方案是唯一的选择?
          • 我从未与jest 合作过,所以对此我没有具体的答案。 “工具级解决方案”是什么意思?
          • 问题是jest.mock 修改了import 语句中加载的内容,但Typescript 编译器不知道这一点。通过“工具级解决方案”,我的意思是(例如)用某种插件增强 Typescript 编译器,以便它知道导入语句的修改行为。
          猜你喜欢
          • 2019-04-22
          • 2017-02-23
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-08-27
          相关资源
          最近更新 更多