【发布时间】:2020-10-03 18:03:56
【问题描述】:
注意:我创建了一个完整配对的 Github 存储库,您可以自己下载和结帐here
我正在尝试使用与文件直接相邻的文件夹 __mocks__ 中的手动模拟来模拟模块中的非默认导出类。这工作正常,我可以让模拟在我的测试中正确加载。但是,如果我按照here in the docs 的描述导出模拟函数,它似乎实际上并没有给我一个对模拟类在测试中调用的函数的引用。这意味着当我打电话时
expect(getAppDetailMock).toHaveBeenCalledTimes(1);
它失败了,因为它根本没有被调用。
expect(jest.fn()).toHaveBeenCalledTimes(expected)
Expected number of calls: 1
Received number of calls: 0
我的怀疑是它与类本身有关,最终得到一个新版本的函数,而不是我要导入的同一个引用......我这么说是因为我做了完全相同的模式来模拟在我的node_modules 中取出一个包,它不是 一个类,它工作得非常好。
尽管您可以查看完整的代码示例here on github,但为了清楚起见,我已经复制了下面的文件。关于为什么这不符合我的预期的任何想法?
// api/__mocks__/clients.ts
export const getAppDetailMock = jest.fn();
export const AppsClient = jest.fn().mockImplementation(() => {
return {
getAppDetail: getAppDetailMock,
};
});
// App.test.js
import React from "react";
import {
render,
screen,
waitForElementToBeRemoved,
} from "@testing-library/react";
import App from "./App";
import { getAppDetailMock } from "./api/__mocks__/clients";
jest.mock("./api/clients");
describe("<App /> ", () => {
beforeEach(() => {
getAppDetailMock.mockReset();
});
test("Should show not found message if app does not exist", async () => {
const appId = "8500f5dd-8b41-4cb8-95fa-246b1f25855b";
getAppDetailMock.mockResolvedValue(null);
render(<App appId={appId} />);
await waitForElementToBeRemoved(() => screen.getByText("Loading"));
expect(getAppDetailMock).toHaveBeenCalledTimes(1);
expect(getAppDetailMock).toHaveBeenCalledWith(appId);
expect(screen.getByText(`App not found found`)).toBeInTheDocument();
});
test("Should show not found message if app does not exist", async () => {
const appId = "8500f5dd-8b41-4cb8-95fa-246b1f25855b";
getAppDetailMock.mockResolvedValue({ appId });
render(<App appId={appId} />);
await waitForElementToBeRemoved(() => screen.getByText("Loading"));
expect(getAppDetailMock).toHaveBeenCalledTimes(1);
expect(getAppDetailMock).toHaveBeenCalledWith(appId);
expect(
screen.getByText(`App found with id '${appId}'`)
).toBeInTheDocument();
});
});
// App.tsx
import React, { useState, useEffect } from "react";
import "./App.css";
import { AppsClient, AppDetailDto } from "./api/clients";
type AppProps = {
appId: string;
};
const App: React.FC<AppProps> = ({ appId }) => {
const [hasLoaded, setHasLoaded] = useState(false);
const [appDetail, setAppDetail] = useState<AppDetailDto | null>(null);
useEffect(() => {
const getAppDetail = async (appId: string) => {
try {
setHasLoaded(false);
const result = await new AppsClient().getAppDetail(appId);
setAppDetail(result);
setHasLoaded(true);
} catch (error) {}
};
if (!hasLoaded) {
getAppDetail(appId);
}
}, [appId, hasLoaded]);
if (!hasLoaded) {
return <>Loading</>;
} else if (!appDetail) {
return <>App not found found</>;
}
return <>App found with id '{appDetail.appId}'</>;
};
export default App;
// api/clients.ts
import { BaseClient } from "./baseClient";
export interface AppDetailDto {
appId: string;
}
export class AppsClient extends BaseClient {
getAppDetail(appId: string): Promise<AppDetailDto> {
return Promise.resolve({ appId });
}
}
【问题讨论】:
-
我猜它必须像
expect(AppsClient. getAppDetail).toHaveBeenCalledTimes(1);
标签: reactjs typescript jestjs