使用Vitest测试React Redux Thunk注册函数时断言错误排查
解决Redux Thunk注册功能测试的AssertionError问题
问题描述
测试基于Redux的React应用时遇到错误:AssertionError: expected "spy" to be called with arguments: [ [Function] ],错误出现在验证注册成功场景的Action派发逻辑时。相关代码如下:
action.js
function asyncRegisterUser({ name, email, password }) { return async (dispatch) => { dispatch(showLoading()); try { await api.register({ name, email, password }); } catch (error) { alert(error.message); } dispatch(hideLoading()); }; } export { asyncRegisterUser, };
action.test.js
import { hideLoading, showLoading } from 'react-redux-loading-bar'; import { afterEach, beforeEach, describe, expect, it, vi, } from 'vitest'; import api from '../../utils/api'; import { asyncRegisterUser } from './action'; const fakeRegisterResponse = { id: 'john_doe', name: 'John Doe', email: 'john@example.com', avatar: 'https://generated-image-url.jpg', }; const fakeRegisterInput = { name: 'John Doe', email: 'john@example.com', password: 'JohnDoe', }; const fakeErrorResponse = new Error('Ups, something went wrong'); describe('asyncRegisterUser thunk', () => { beforeEach(() => { api._registerUser = api.register; }); afterEach(() => { api.register = api._registerUser; delete api._registerUser; }); it('should dispatch action correctly when register success', async () => { api.register = () => Promise.resolve(fakeRegisterResponse); const dispatch = vi.fn(); await asyncRegisterUser(fakeRegisterInput)(dispatch); expect(dispatch).toHaveBeenCalledWith(showLoading()); expect(dispatch).toHaveBeenCalledWith( asyncRegisterUser(fakeRegisterInput), // ERROR HERE ); expect(dispatch).toHaveBeenCalledWith(hideLoading()); }); it('should dispatch action and call alert correctly when register failed', async () => { api.register = () => Promise.reject(fakeErrorResponse); const dispatch = vi.fn(); window.alert = vi.fn(); await asyncRegisterUser(fakeRegisterInput)(dispatch); expect(dispatch).toHaveBeenCalledWith(showLoading()); expect(dispatch).toHaveBeenCalledWith(hideLoading()); expect(window.alert).toHaveBeenCalledWith(fakeErrorResponse.message); }); });
错误原因
测试代码中错误地断言dispatch会调用asyncRegisterUser(fakeRegisterInput),但实际上在asyncRegisterUser这个thunk函数内部,并没有派发自身作为action,它只在注册流程前后分别派发了showLoading()和hideLoading()。这行多余的断言导致匹配失败,因为asyncRegisterUser返回的是一个函数,和实际dispatch的参数不匹配。
修正后的测试代码
移除错误的断言行即可,修正后的注册成功场景测试如下:
it('should dispatch action correctly when register success', async () => { api.register = () => Promise.resolve(fakeRegisterResponse); const dispatch = vi.fn(); await asyncRegisterUser(fakeRegisterInput)(dispatch); // 只验证实际被派发的action expect(dispatch).toHaveBeenCalledWith(showLoading()); expect(dispatch).toHaveBeenCalledWith(hideLoading()); // 如果后续注册成功后需要派发其他action(比如registerSuccess),再添加对应断言 });
如果你的业务逻辑中,注册成功后本应派发一个额外的成功action(比如registerSuccess(fakeRegisterResponse)),需要先在action.js中补充这个逻辑:
补充后的action.js
// 先定义成功action类型和创建函数 const REGISTER_SUCCESS = 'REGISTER_SUCCESS'; function registerSuccess(user) { return { type: REGISTER_SUCCESS, payload: { user, }, }; } function asyncRegisterUser({ name, email, password }) { return async (dispatch) => { dispatch(showLoading()); try { const user = await api.register({ name, email, password }); dispatch(registerSuccess(user)); // 添加成功action派发 } catch (error) { alert(error.message); } dispatch(hideLoading()); }; } export { asyncRegisterUser, registerSuccess, };
对应的测试代码也要添加该action的断言:
// 导入registerSuccess import { asyncRegisterUser, registerSuccess } from './action'; // 注册成功测试用例 it('should dispatch action correctly when register success', async () => { api.register = () => Promise.resolve(fakeRegisterResponse); const dispatch = vi.fn(); await asyncRegisterUser(fakeRegisterInput)(dispatch); expect(dispatch).toHaveBeenCalledWith(showLoading()); expect(dispatch).toHaveBeenCalledWith(registerSuccess(fakeRegisterResponse)); expect(dispatch).toHaveBeenCalledWith(hideLoading()); });
内容的提问来源于stack exchange,提问作者Terhebat Hokage
相关产品推荐
相关产品推荐

