我正在编写一个简单的应用程序,在该应用程序中,单击按钮后,应执行对Spotify API的异步调用,并在promise解析后应更新组件的状态。我正在使用反应挂钩来管理组件中的状态。
在测试中,我模拟了API调用。
spotify.jsx
export default class Spotify {
constructor(token) {
this.axiosInstance = axios.create({
baseURL: baseURL,
headers: buildHeaders(token),
});
}
async getUserInfo() {
const userInfo = await this.axiosInstance({
url: `/me`,
});
return userInfo.data
}
}
spotify模拟:
const getUserInfoMock = jest.fn();
const mock = jest.fn().mockImplementation(() => ({
getUserInfo: getUserInfoMock,
}));
export default mock;
User.jsx
const User = props => {
const [user, setUser] = useState(null);
const {token} = useContext(AuthContext);
const spotify = useMemo(() => new Spotify(token), [token]);
const getUserInfo = async () => {
console.log("button clicked")
const fetched = await spotify.getUserInfo();
console.log(fetched)
setUser(fetched);
}
return (
<React.Fragment>
<p>user page</p>
<button onClick={getUserInfo} > click me </button>
{user && (
<div>
<p>{user.display_name}</p>
<p>{user.email}</p>
</div>
)}
</React.Fragment>
);
};
我的问题是如何正确测试这种行为。我设法使其通过,但不是在await
上调用simulate()
是一个丑陋的骇客吗?模拟不返回承诺。这是一个测试:
it('updates display info with data from api', async () => {
const userInfo = {
display_name: 'Bob',
email: 'bob@bob.bob',
};
spotifyMock.getUserInfo.mockImplementation(() => Promise.resolve(userInfo));
wrapper = mount(<User />);
expect(wrapper.find('p')).toHaveLength(1);
await wrapper
.find('button')
.last()
.simulate('click');
wrapper.update();
expect(wrapper.find('p')).toHaveLength(3);
});
另一方面,当我仅检查是否调用了模拟程序时,我不需要使用async / await和测试通过:
it('calls spotify api on click', () => {
wrapper = mount(<User />);
expect(spotifyMock.getUserInfo).not.toHaveBeenCalled();
wrapper
.find('button')
.last()
.simulate('click');
expect(spotifyMock.getUserInfo).toHaveBeenCalledTimes(1);
});
我想知道我的测试方法是否正确,以及是否想添加一个功能以在组件渲染时从api中获取数据-使用useEffect挂钩。酶是否完全支持react挂钩?
即使包装了Warning: An update to User inside a test was not wrapped in act(...)
和mount
函数,我也难以警告simulate
。
答案 0 :(得分:1)
参考:Testing with React's Jest and Enzyme when simulated clicks call a function that calls a promise
在setImmediate中包裹您的期望声明
setImmediate(() => {
expect(spotifyMock.getUserInfo).toHaveBeenCalledTimes(1);
})
答案 1 :(得分:0)
您应该按照Dan Abramov's blog post将影响渲染的调用包装在一个异步act()函数中,如下所示:
it('calls spotify api on click', async () => {
await act(async () => {
wrapper = mount(<User />);
});
expect(spotifyMock.getUserInfo).not.toHaveBeenCalled();
await act(async () => {
wrapper
.find('button')
.last()
.simulate('click');
});
wrapper.update();
expect(spotifyMock.getUserInfo).toHaveBeenCalledTimes(1);
});