开玩笑的typescript属性模拟类型不存在

时间:2018-09-22 14:24:07

标签: typescript jestjs

使用jest.fn()添加模拟时,通常可以访问.mock属性以访问详细信息,例如呼叫,类似于以下内容:

test('not working', () => {
    const foo = new Foo();
    foo.addListener = jest.fn();
    foo.func(); // will call addListener with a callback
    const callback = foo.addListener.mock.calls[0][0];
    expect(callback()).toEqual(1); // test the callback
});

当使用打字稿而不是普通的javascript实现测试时,出现错误:

  

错误TS2339:类型'((callback:()=> number)=> void')不存在属性'mock'。

我可以通过强制转换为any来消除错误,但是肯定有更好的方法:

const callback = (foo.addListener as any).mock.calls[0][0];

在这个简单的代码中,可以使用jest.fn(fn => { callback = fn; });重写模拟以存储参数,但是在使用foo.addListener.mockClear()时会发生相同的错误,无法以相同的方式进行修改。

那么如何摆脱错误,最好在不丢失类型安全的情况下?

3 个答案:

答案 0 :(得分:28)

对于任何到达这里的人来说,比强制转换为android { buildTypes { release { // Enables code shrinking, obfuscation, and optimization for only // your project's release build type. minifyEnabled true // Enables resource shrinking, which is performed by the // Android Gradle plugin. shrinkResources true } } } 更好一点可能是嘲笑。模拟

any

答案 1 :(得分:7)

您可以结合使用jest.spyOnmockImplementation之类的函数来模拟函数,同时在TypeScript中保留类型安全性:

class Foo {
  addListener = (callback: () => number) => { }
  func = () => {
    this.addListener(() => 1);
  }
}

test('working', () => {
  const foo = new Foo();
  const mockAddListener = jest.spyOn(foo, 'addListener'); // spy on foo.addListener
  mockAddListener.mockImplementation(() => { }); // replace the implementation if desired
  foo.func(); // will call addListener with a callback
  const callback = mockAddListener.mock.calls[0][0];
  expect(callback()).toEqual(1); // SUCCESS
});

答案 2 :(得分:1)

使用axios时出现以下错误。

TS2339(TS)属性'mockResolvedValueOnce'在类型上不存在 “ AxiosStatic”

尝试使用axios as jest.Mock,但出现以下错误:

TS2352(TS)将类型“ AxiosStatic”转换为类型“ Mock ” 可能是一个错误,因为这两种类型都无法与 其他。如果这是故意的,请将表达式转换为“未知” 第一。类型“ AxiosStatic”缺少以下属性 输入'Mock ':getMockName,mock,mockClear,mockReset和12 更多。

通过指定为axios as unknown as jest.Mock

解决了该问题

AxiosRequest.test.tsx

import axios from 'axios';
import { MediaByIdentifier } from '../api/mediaController';

jest.mock('axios', () => jest.fn());

test('Test AxiosRequest',async () => {
    const mRes = { status: 200, data: 'fake data' };
    (axios as unknown as jest.Mock).mockResolvedValueOnce(mRes);
    const mock = await MediaByIdentifier('Test');
    expect(mock).toEqual(mRes);
    expect(axios).toHaveBeenCalledTimes(1);
});

mediaController.ts:

import { sendRequest } from './request'
import { AxiosPromise } from 'axios'
import { MediaDto } from './../model/typegen/mediaDto';

const path = '/api/media/'

export const MediaByIdentifier = (identifier: string): AxiosPromise<MediaDto> => {
    return sendRequest(path + 'MediaByIdentifier?identifier=' + identifier, 'get');
}

request.ts:

import axios, { AxiosPromise, AxiosRequestConfig, Method } from 'axios';

const getConfig = (url: string, method: Method, params?: any, data?: any) => {
     const config: AxiosRequestConfig = {
         url: url,
         method: method,
         responseType: 'json',
         params: params,
         data: data,
         headers: { 'X-Requested-With': 'XMLHttpRequest', 'Content-Type': 'application/json' },
    }
    return config;
}

export const sendRequest = (url: string, method: Method, params?: any, data?: any): AxiosPromise<any> => {
    return axios(getConfig(url, method, params, data))
}