Javascript 用打字稿在玩笑中模拟依赖

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/48759035/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 04:14:24  来源:igfitidea点击:

Mock dependency in jest with typescript

javascriptunit-testingtypescriptjestjs

提问by Philip Chmalts

When testing a module that has a dependency in a different file. When assigning that module to be jest.Mocktypescript gives an error that the method mockReturnThisOnce(or any other jest.Mock method) does not exist on the dependency, this is because it is previously typed. What is the proper way to get typescript to inherit the types from jest.Mock?

测试在不同文件中具有依赖项的模块时。当将该模块分配为jest.Mock打字稿时,会出现该方法mockReturnThisOnce(或任何其他 jest.Mock 方法)在依赖项上不存在的错误,这是因为它之前已键入。让打字稿从 jest.Mock 继承类型的正确方法是什么?

Here is a quick example.

这是一个快速示例。

Dependency

依赖

const myDep = (name: string) => name;
export default myDep;

test.ts

测试文件

import * as dep from '../depenendency';
jest.mock('../dependency');

it('should do what I need', () => {
  //this throws ts error
  // Property mockReturnValueOnce does not exist on type (name: string)....
  dep.default.mockReturnValueOnce('return')
}

I feel like this is a very common use case and not sure how to properly type this. Any help would be much appreciated!

我觉得这是一个非常常见的用例,不知道如何正确输入。任何帮助将非常感激!

回答by Artur Górski

You can use type casting and your test.tsshould look like this:

您可以使用类型转换,您test.ts应该如下所示:

import * as dep from '../dependency';
jest.mock('../dependency');

const mockedDependency = <jest.Mock<typeof dep.default>>dep.default;

it('should do what I need', () => {
  //this throws ts error
  // Property mockReturnValueOnce does not exist on type (name: string)....
  mockedDependency.mockReturnValueOnce('return');
});

TS transpiler is not aware that jest.mock('../dependency');changes type of depthus you have to use type casting. As imported depis not a type definition you have to get its type with typeof dep.default.

TS 转译器不知道jest.mock('../dependency');更改类型,dep因此您必须使用类型转换。由于导入dep不是类型定义,您必须使用typeof dep.default.

Here are some other useful patterns I've found during my work with Jest and TS

以下是我在使用 Jest 和 TS 时发现的其他一些有用的模式

When imported element is a class then you don't have to use typeof for example:

当导入的元素是一个类时,您不必使用 typeof 例如:

import { SomeClass } from './SomeClass';

jest.mock('./SomeClass');

const mockedClass = <jest.Mock<SomeClass>>SomeClass;

This solution is also useful when you have to mock some node native modules:

当您必须模拟某些节点本机模块时,此解决方案也很有用:

import { existsSync } from 'fs';

jest.mock('fs');

const mockedExistsSync = <jest.Mock<typeof existsSync>>existsSync;

In case you don't want to use jest automatic mock and prefer create manual one

如果您不想使用 jest 自动模拟而更喜欢创建手动模拟

import TestedClass from './TestedClass';
import TestedClassDependency from './TestedClassDependency';

const testedClassDependencyMock = jest.fn<TestedClassDependency>(() => ({
  // implementation
}));

it('Should throw an error when calling playSomethingCool', () => {
  const testedClass = new TestedClass(testedClassDependencyMock());
});

testedClassDependencyMock()creates mocked object instance TestedClassDependencycan be either class or type or interface

testedClassDependencyMock()创建模拟对象实例 TestedClassDependency可以是类或类型或接口

回答by Fran?ois Romain

Use the mockedhelper from ts-jestlike explained here

使用这里解释的mocked帮助器ts-jest

// foo.spec.ts
import { mocked } from 'ts-jest/utils'
import { foo } from './foo'
jest.mock('./foo')

// here the whole foo var is mocked deeply
const mockedFoo = mocked(foo, true)

test('deep', () => {
  // there will be no TS error here, and you'll have completion in modern IDEs
  mockedFoo.a.b.c.hello('me')
  // same here
  expect(mockedFoo.a.b.c.hello.mock.calls).toHaveLength(1)
})

test('direct', () => {
  foo.name()
  // here only foo.name is mocked (or its methods if it's an object)
  expect(mocked(foo.name).mock.calls).toHaveLength(1)
})

and if

而如果

  • you use tslint
  • ts-jestis in your dev-dependencies,
  • 你用 tslint
  • ts-jest在你的开发依赖中,

add this rule to your tslint.json: "no-implicit-dependencies": [true, "dev"]

将此规则添加到您的tslint.json"no-implicit-dependencies": [true, "dev"]

回答by adanilev

I use the pattern from @types/jest/index.d.ts just above the type def for Mocked (line 515):

我使用来自 @types/jest/index.d.ts 的模式就在 Mocked 的 type def 上方(第 515 行):

import { Api } from "../api";
jest.mock("../api");

const myApi: jest.Mocked<Api> = new Api() as any;
myApi.myApiMethod.mockImplementation(() => "test");

回答by Bruce Lee

Here's what I did with [email protected]and [email protected]:

这是我对[email protected][email protected] 所做的

source:

来源:

class OAuth {

  static isLogIn() {
    // return true/false;
  }

  static getOAuthService() {
    // ...
  }
}

test:

测试:

import { OAuth } from '../src/to/the/OAuth'

jest.mock('../src/utils/OAuth', () => ({
  OAuth: class {
    public static getOAuthService() {
      return {
        getAuthorizationUrl() {
          return '';
        }
      };
    }
  }
}));

describe('createMeeting', () => {
  test('should call conferenceLoginBuild when not login', () => {
    OAuth.isLogIn = jest.fn().mockImplementationOnce(() => {
      return false;
    });

    // Other tests
  });
});

This is how to mock a non-default class and it's static methods:

这是模拟非默认类及其静态方法的方法:

jest.mock('../src/to/the/OAuth', () => ({
  OAuth: class {
    public static getOAuthService() {
      return {
        getAuthorizationUrl() {
          return '';
        }
      };
    }
  }
}));

Here should be some type conversion from the type of your class to jest.MockedClassor something like that. But it always ends up with errors. So I just used it directly, and it worked.

这里应该是从你的类的类型到jest.MockedClass类似的类型的一些类型转换。但它总是以错误告终。所以我直接用了它,它奏效了。

test('Some test', () => {
  OAuth.isLogIn = jest.fn().mockImplementationOnce(() => {
    return false;
  });
});

But, if it's a function, you can mock it and do the type conversation.

但是,如果它是一个函数,您可以模拟它并进行类型对话。

jest.mock('../src/to/the/Conference', () => ({
  conferenceSuccessDataBuild: jest.fn(),
  conferenceLoginBuild: jest.fn()
}));
const mockedConferenceLoginBuild = conferenceLoginBuild as 
jest.MockedFunction<
  typeof conferenceLoginBuild
>;
const mockedConferenceSuccessDataBuild = conferenceSuccessDataBuild as 
jest.MockedFunction<
  typeof conferenceSuccessDataBuild
>;

回答by Black

I ended up doing this

我最终这样做了

import * as dep from './dependency';

jest.mock('./dependency');

const mockMyFunction = dep.myFunction as jest.MockedFunction<typeof dep.myFunction>;

You can then call any jest mock function on mockMyFunctionlike mockReturnValueor mockResolvedValuehttps://jestjs.io/docs/en/mock-function-api.html

然后,您可以在mockMyFunctionlikemockReturnValuehttps://jestjs.io/docs/en/mock-function-api.html上调用任何玩笑模拟函数mockResolvedValue

mockMyFunctioncan be used normally for expect expect(mockMyFunction).toHaveBeenCalledTimes(1);

mockMyFunction可以正常用于expect expect(mockMyFunction).toHaveBeenCalledTimes(1);

回答by exmaxx

Cast as jest.Mock

投掷 as jest.Mock

Simply casting the function to jest.Mockshould do the trick:

简单地将函数转换为jest.Mock应该可以解决问题:

(dep.default as jest.Mock).mockReturnValueOnce('return')

回答by mostruash

A recent library solves this problem with a babel plugin: https://github.com/userlike/joke

最近的一个库使用 babel 插件解决了这个问题:https: //github.com/userlike/joke

Example:

例子:

import { mock } from 'userlike/joke';
const { default: dep } = mock(import('../dependency'));

it('should do what I need', () => {
  dep.mockReturnValueOnce('return');
}