使用笑话模拟时的打字稿错误

Posted

技术标签:

【中文标题】使用笑话模拟时的打字稿错误【英文标题】:Typescript errors when using jest mocks 【发布时间】:2018-12-15 09:05:33 【问题描述】:

我有一个先前创建的 .js 文件,它模拟了我们的一些函数,用于 jest 测试目的。我正在将其迁移到 .ts 文件:

Server.ts

const Server = jest.genMockFromModule('../Server');

Server.getAsync = Server.default.getAsync;
// other REST-ful functions here

export default Server;

我收到以下错误:

类型“”上不存在属性“getAsync”

类型“”上不存在属性“默认”

然后,在相应的测试文件中:

MyComponent.test.ts

import Server from 'path/to/Server';

jest.mock('path/to/Server');

const dispatchMock = jest.fn();
const getStateMock = jest.fn();

describe('MyComponent.someFunction', () => 
    beforeEach(() => 
        jest.resetAllMocks();
    );

    it('Does the right stuff', () => 
        Server.getAsync.mockReturnValueOnce(Promise.resolve([ key: 'value' ]));
        dispatchMock.mockImplementationOnce((promise) => promise);
        dispatchMock.mockImplementationOnce();

        return someFunction()(dispatchMock)
            .then(() => 
                expect(Server.getAsync).toHaveBeenCalledTimes(1);
                expect(Server.getAsync.mock.calls[0][0]).toBe('something');
            );
    );
);

我在dispatchMock.mockImplementationOnce() 上遇到错误

预期 1 个参数,但得到 0 个。(方法) jest.MockInstance.mockImplementationOnce(fn: (...args: any[]) => 任何):jest.Mock

...在Server.getAsync.mockReturnValueOnce

类型 '(url: string, baseRoute?: 字符串 | null, loadingGenerator?: (isLoading: boolean) => 类型:字符串...'。

...在Server.getAsync.mock

类型 '(url: string, baseRoute?: 字符串 | null, loadingGenerator?: (isLoading: boolean) => type: 字符串...'。

我已经为此苦苦思考了一段时间,因此我们将不胜感激。

更新

好的,我在Server.ts 文件的第一行末尾添加了as any,所以现在它看起来像:

const Server = jest.genMockFromModule('../Server') as any;

这消除了第一组错误。不过我的.test.ts 文件中仍然存在错误。

更新 2

我注意到,当我运行实际的笑话测试时,即使存在 TypeError,它们也都通过了。这些问题似乎与实际测试无关。

【问题讨论】:

【参考方案1】:

我自己解决了这个问题。我让它工作的方式是将任何对 Server.getAsync 的调用转换为特定的笑话模拟类型。

let getAsyncMock = Server.getAsync as jest.Mock

let getAsyncMock = <jest.Mock>(Server.getAsync)

这消除了我的错误。

【讨论】:

您是否找到了一种通过导入实现此目的的方法?即:import axios from 'axios'; jest.mock('axios'); 很棒的答案。我在每个单元测试下都喜欢(Server.getAsync as jest.Mock).mockImplementationOnce,它确实有效。 这不适用于最新版本的打字稿。我必须先将其转换为未知数。即Server.getAsync as unknown as jest.Mock有没有人知道解决这个问题的方法?【参考方案2】:

要覆盖导入,您可以这样做:

import  AnalyticsApi  from "../../api/src";

jest.mock("../../api/src");

let listPolicies = jest.fn(() => 
  return Promise.resolve();
);

(AnalyticsApi as jest.Mock<AnalyticsApi>).mockImplementation(() => (
  listPolicies,
));

【讨论】:

【参考方案3】:

在@nobleare 响应之后...一个很好的更新是将您的模拟实现包装到beforeAll 并将其清除到beforeEach 块中:

import  AnalyticsApi  from "../../api/src";

jest.mock("../../api/src");

describe('...', () => 

  beforeAll(() => 
    (AnalyticsApi as jest.Mock<AnalyticsApi>).mockImplementation(() => (
      listPolicies: jest.fn().mockResolvedValue('promiseValue')
    ));
  );

  beforeEach(() => 
    (AnalyticsApi as jest.Mock<AnalyticsApi>).mockClear();
  );

);

【讨论】:

感谢那个家伙,(AnalyticsApi as jest.Mock&lt;AnalyticsApi&gt;) 甚至 (AnalyticsApi as jest.Mock) 真的帮助了我!!【参考方案4】:

首先,您使用的是genMockFromModule,它创建了您的Server 的模拟,因此无需调用jest.mock('path/to/Server');

第二,你想通过Server.getAsync = Server.default.getAsync;实现什么?所做的只是将getAsync 提升到一个不必要的级别。你可以打电话给jest.genMockFromModule('../Server').default;

dispatchMock.mockImplementationOnce() 正在抛出该错误,因为您说它需要在这里传递一个承诺:dispatchMock.mockImplementationOnce((promise) =&gt; promise);

对于Server.getAsync.mockReturnValueOnceServer.getAsync.mock,您实际上想使用mocked,而不是像其他答案建议的那样强制转换类型。

例如:mocked(Server.getAsync).mockReturnValueOnce()

【讨论】:

【参考方案5】:

使用this

import  mocked  from 'ts-jest/utils';
import  foo  from './foo';
jest.mock('./foo');


expect(mocked(foo)).toHaveLength(1);

【讨论】:

以上是关于使用笑话模拟时的打字稿错误的主要内容,如果未能解决你的问题,请参考以下文章

在笑话和打字稿中模拟交叉点观察者

笑话测试显示对象可能是“空”错误

gulp打字稿时的TypeError

开玩笑的打字稿 - 模拟日期构造函数

使用样式组件的打字稿错误

打字稿错误:';'使用“let”关键字时预期