我正在使用TypeScript构建React Native应用程序,并使用Jest编写单元测试。
我目前正在为加载屏幕编写单元测试:
export class LoadingScreen extends Component<Props, object> {
componentDidMount = () => {
const { dispatch, navigation } = this.props;
getToken()
.then(key => {
if (typeof key === "string") {
getBootData(dispatch)
.then(() => navigation.navigate("HomeScreen"))
.catch(err => {
alert(err);
// TODO: Hide the splash screen, after componentDidMount finished.
navigation.navigate("LoginScreen");
});
} else {
// TODO: Hide the splash screen, after componentDidMount finished.
navigation.navigate("LoginScreen");
}
})
.catch(() => navigation.navigate("LoginScreen"));
};
// ... render() n' stuff.
如您所见,安装组件后,我检查是否有令牌。然后根据令牌的不同,我将应用程序与服务器(在getBootData
中)同步加载并导航到相应的屏幕-Home
或返回到Login
。
这是我为此生命周期方法编写的测试:
describe("life cycle methods", () => {
describe("componentDidMount", () => {
const props = createTestProps({});
const wrapper = shallow<LoadingScreen>(<LoadingScreen {...props} />);
const getTokenSpy = jest.spyOn(secureStoreFunctions, "getToken");
const getBootDataSpy = jest.spyOn(bootDataFunctions, "getBootData");
beforeEach(() => {
jest.resetAllMocks();
getBootDataSpy.mockResolvedValueOnce(true);
wrapper.instance().componentDidMount();
});
it("should call getToken", () => {
expect(getTokenSpy).toHaveBeenCalledTimes(1);
});
it("should call getBootData", () => {
expect(getBootDataSpy).toBeCalledTimes(1);
});
});
});
我的目的是监视getToken()
方法是否被调用。
但是问题在于,这会导致错误:
● LoadingScreen › life cycle methods › componentDidMount › should call getToken
TypeError: Cannot read property 'then' of undefined
17 | componentDidMount = () => {
18 | const { dispatch, navigation } = this.props;
> 19 | getToken()
| ^
20 | .then(key => {
21 | if (typeof key === "string") {
22 | getBootData(dispatch)
at LoadingScreen.componentDidMount (app/screens/Loading/LoadingScreen.tsx:19:5)
at Object.beforeEach (app/screens/Loading/LoadingScreen.test.tsx:39:28)
BTW:对getBootData
的测试也失败了。
我以为spyOn应该保留功能的原始实现?但显然它与未定义的:(
其他信息
getToken
的外观如下:
import { getGenericPassword } from "react-native-keychain";
export const getToken = (): Promise<boolean | string> =>
getGenericPassword().then(
creds => (typeof creds === "boolean" ? creds : creds.password)
);
在与我的节点模块相邻的getGenericPassword
文件夹中,我还为React Native Keychain的__mocks__/
提供了一个简单的模拟,以便在需要此功能的其他测试中Jest自动模拟该功能:>
const token = "abcdefghijklmnopqrstuvwxyz0123456789";
const credentials = {
username: "session",
password: token
};
export const setGenericPassword = jest.fn(
(username, password) => new Promise((resolve, reject) => resolve(true)) // eslint-disable-line no-unused-vars
);
export const getGenericPassword = jest.fn(
() => new Promise((resolve, reject) => resolve(credentials)) // eslint-disable-line no-unused-vars
);
export const resetGenericPassword = jest.fn(() => new Promise((resolve, reject) => resolve(true))); // eslint-disable-line no-unused-vars
这两个模拟可能以某种方式堆叠并导致不确定性吗?反对这一点的原因是,我没有全局getBootData
模拟,如上所述,该模拟失败类似。
这是怎么回事?为什么spyOn会使函数变为undefined
?