我正在React应用程序中进行一个单元测试,以验证一个传递进来的prop函数是否被基于另一个props值而有条件地调用。我在我的应用程序中利用TypescriptEnzymeJest,并使用了一个名为 "HaveBeenCalled "的测试。Root
围绕我正在测试的组件的包装器来注入Redux存储(如果需要的话,还可以覆盖初始状态)。
import { mount, ReactWrapper } from "enzyme";
import React from "react";
import Login from "src/components/auth/Login";
import Root from "src/Root";
let wrapped: ReactWrapper;
let defaultProps = {
signIn: jest.fn(),
token: null,
};
beforeEach(() => {
wrapped = mount(
<Root>
<Login {...defaultProps} />
</Root>
);
});
describe("on mount", () => {
describe("if no token is supplied to the props", () => {
it("will call the props.signIn() function", () => {
expect(defaultProps.signIn).toHaveBeenCalled();
});
});
});
当我运行测试时 toHaveBeenCalled()
(以及 toBeCalled()
,都试过了)都没有注册任何调用。然而,我已经提供了一个 console.log
语句,该语句将被触发在与 signIn()
功能的生命。
import React from 'react';
import { AuthState, JWT } from "src/components/auth/types";
import { signIn } from "src/redux/auth";
interface Props {
signIn: () => Promise<void>;
token: null | JWT;
}
class Login extends React.Component<Props> {
/**
* Sign the user in on mount
*/
public componentDidMount(): void {
if (!this.props.token) {
console.log("GETTING HERE");
this.props.signIn();
}
}
public render(): JSX.Elemeent {
// ... More code
}
}
const mapStateToProps = (state: AuthState) => {
return {
token: state.auth.token;
};
};
export default connect(mapStateToProps, { signIn })(Login);
我翻了好几篇相关的帖子文章,但都是不同的配置,比如遍历酶来获得直接道具,或者利用 spyOn
,都失败了。
我唯一能想到的不同之处是我的包装上的 Login
组成部分与 Root
但考虑到我可以看到 console.log
被触发,这似乎是一个完整的射击在黑暗中。
谁能告诉我,我在这里做错了什么?
你要等组件挂载,所以。
it("will call the props.signIn() function", (done) => {
setImmediate(() => {
expect(defaultProps.signIn).toHaveBeenCalled();
done()
});
});
结果是我忘了把覆盖的地方通过... mapDispatchToProps
和 mapStateToProps
在 connect
函数。这导致我的传入的 signIn
函数来覆盖 signIn
文件中导入的动作。更新与 ownProps
并有条件地利用传入的值来解决这个问题。
const mapStateToProps = (state: AuthState, ownProps: Props) => {
return {
token: ownProps.token || state.auth.token;
};
};
const mapDispatchToProps = (dispatch: ThunkDispatch<{}, {}, any>, ownProps: Props) => {
return {
signIn: ownProps.signIn || (() => { return dispatch(signIn()) })
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Login);