TypeScript+Jest - 如何将 jest.spyOn 与通用 TypeScript 方法一起使用?

标签 typescript jestjs

我定义了以下 TypeScript 对象:

// HttpClient.ts
export type HttpResponse<T> = Response & {
  data?: T;
}

async function get<T>(url: string, args: RequestInit = {}): Promise<HttpResponse<T>> {
  return fetchRequest<T>(url, {...args, method: 'get'}) // fetchRequest returns value of type Promise<HttpResponse<T>>
}

export default {get} // default export represents an HttpClient object

我还有另一个文件 getFeatureFlag.ts,它在其实现中使用了这个 HttpClient:

// getFeatureFlag.ts
import HttpClient from '../httpClient'

export type FetchResponse<T = any, E = any> = {
  data: Nullable<T>;
  error: Nullable<E>;
}

export type FeatureFlag = {
  toggleActive: boolean; // true/false denotes show/hide feature
}

export async function getFeatureFlag(flagName: string): Promise<FetchResponse<boolean, string>> {
  const response = await HttpClient.get<FeatureFlag>(`/v1/toggles/${flagName}/`)

  // ... rest of the implementation ...
}

我正在为 getFeatureFlag.test.ts 下的这个文件编写单元测试(使用 Jest),其中包含以下代码片段:

// getFeatureFlag.test.ts
import HttpClient, {HttpResponse} from '../httpClient'
import {getFeatureFlag, FLAG_STORE, FeatureFlag} from '../index'

describe('getFeatureFlag', () => {
  beforeEach(async () => {
    // vv === THIS LINE IS WHAT THIS POST IS ABOUT === vv
    jest.spyOn<HttpResponse<FeatureFlag>, 'get'>(HttpClient, 'get').mockImplementationOnce(() => ({
      ok: true,
      data: {
        toggleActive: true,
      },
    }))

    result = await getFeatureFlag(flagName)
  })

  it('then perform api request for feature flag data', () => {
    expect(HttpClient.get).toHaveBeenCalledWith('/v1/toggles/featureFlag/')
  })
})

@types/jest 定义文件中,spyOn 函数定义如下:

function spyOn<T extends {}, M extends FunctionPropertyNames<Required<T>>>(
        object: T,
        method: M
    ): Required<T>[M] extends (...args: any[]) => any
        ? SpyInstance<ReturnType<Required<T>[M]>, ArgsType<Required<T>[M]>>
        : never;

我很难让 TypeScript 编译器正确读取下面的代码片段而没有问题。

jest.spyOn<HttpResponse<FeatureFlag>, 'get'>(HttpClient, 'get').mockImplementationOnce(() => ({
      ok: true,
      data: {
        toggleActive: true,
      },
    }))

通过上述设置,编译器告诉我 get 不满足约束 never 并且我不知道如何解决此处的输入问题以获取我的测试编写/运行正确。我在这里尝试做的另一件事是只返回 HttpResponsePartial 因为我显然不想在单元测试中填写每个字段不需要它们。

有没有人能够通过泛型正确应用 jest.spyOn 来帮助解决这个问题?

最佳答案

认为你所缺少的只是这个词 async在您调用 mockImplementationOnce() 的电话中.然后您可以删除 jest.spyOn 的类型参数.你不会在你的模拟实现中自动获得类型安全,但如果你真的担心它,你可以添加 as HttpResponse<FeatureFlag> .

let result: FetchResponse<boolean, string>;

describe('getFeatureFlag', () => {
    beforeEach(async () => {
        //                                                  missing
        //                                                     ↓
        jest.spyOn(HttpClient, 'get').mockImplementationOnce(async () => ({
            ok: true,
            data: {
                toggleActive: true,
            },
        } as HttpResponse<FeatureFlag>));

        result = await getFeatureFlag(flagName);
    })
});

TS Playground

当然,这并没有回答标题中提出的问题,但它应该可以修复您的代码。我花了很长时间试图让你指定的泛型类型参数起作用,但最终放弃了。它可能是对 jest 中声明的限制命名空间。

关于TypeScript+Jest - 如何将 jest.spyOn 与通用 TypeScript 方法一起使用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62826474/

相关文章:

javascript - 开 Jest : resolves return undefined from Promise

visual-studio-code - VSCode 调试器在 Jest 测试中不起作用

javascript - 如何在 React Native 中使用 Jest 测试 lodash 的去抖功能?

javascript - Jest - 类中的模拟变量

javascript - 如何在 Jest 测试中比较(匿名)函数?

javascript - 在 Angular 中使用 Javascript 库

Angular 6 错误 : Cannot make XHRs from within a fake async test. 请求 URL : https://mlj0xk2yy. com/latest/static/videos

reactjs - React Native,类型错误: undefined is not an object When it is

javascript - 类型 'boolean' 不可分配给类型 'Promise<boolean>'

typescript - ES6 Promise 需要 typescript 2.0 中的参数?