目标
我正在尝试测试 useEffect 函数,该函数在点击后将关注按钮的文本更改为取消关注
结果
当我测试组件时,关注/取消关注动作被调度,但按钮的文本没有改变
useEffect函数内部登录说明
它的实现方式是,在单击关注按钮后,会调度关注/取消关注操作,并将关注的人 (userToFollow) 添加到已登录用户关注帐户数组 (loggedUserData.following),然后将按钮文本更改为取消关注,反之亦然。
我对测试失败原因的 2 美分
我认为问题在于我模拟了关注/取消关注操作,因此它只是被调用,并没有按照应有的方式解决,如果我可以将已关注的用户添加到已登录用户的列表中关注账号,问题就解决了。
有人知道我该怎么做或提供更好的想法来解决吗?
解决方案 所以问题是 redux-mock-store 不批准更新状态,所以我用真实的 redux Store 渲染了测试,一切正常
加载记录的用户数据操作
export const loadloggedUserDataAction = () => async (dispatch) => {
try {
const config = {
headers: {
'Content-Type': 'application/json',
Accept: 'application/json',
Authorization: `Token ${localStorage.getItem('auth_token')}`,
},
};
const res = await axios.get(`${process.env.NEXT_PUBLIC_API_URL}/api/accounts/logged_user/`, config);
dispatch({ type: GET_LOGGED_USER_DETAILS_SUCCESS, payload: res.data
});
console.log(res.data);
/*
res.data = data: {
id: 'id',
name: 'name',
email: 'email',
following: [userToFollow],
followers: [userToFollow],
},
*/
} catch (err) {
dispatch({ type: GET_LOGGED_USER_DETAILS_FAIL });
}
};
错误
TestingLibraryElementError: Unable to find an accessible element with the role "button" and name "unfollow"
测试
jest.mock('axios', () => ({
post: () =>
Promise.resolve({
data: {
id: 'id',
name: 'name',
email: 'email',
following: [userToFollow],
followers: [userToFollow],
},
}),
get: () =>
Promise.resolve({
data: {
id: 'id',
name: 'name',
email: 'email',
following: [userToFollow],
followers: [userToFollow],
},
}),
}));
const userToFollow = 'userId';
const loggedUserData = {
id: 'id',
name: 'name',
email: 'email',
following: [],
followers: [],
};
const middlewares = [thunk];
const mockStore = configureStore(middlewares);
const initialState = {
userReducer: { isUserAuthenticated: true, loggedUserData: loggedUserData },
};
const store = mockStore(initialState);
describe('FollowUnFollow - isUserAlreadyFollowed false', () => {
beforeEach(() => {
render(
<Provider store={store}>
<FollowUnFollow userToFollow={userToFollow} />
</Provider>
);
});
afterEach(() => {
cleanup();
jest.clearAllMocks();
});
test('follow button should dispatch followUnFollowAction ',async () => {
const followButton = screen.getByRole('button', { name: 'follow' });
userEvent.click(followButton);
const unFollowButton = await screen.findByRole('button', { name: 'unfollow' });
expect(unFollowButton).toBeInTheDocument();
});
});
组件
const FollowUnFollow = ({ userToFollow }) => {
const dispatch = useDispatch();
const [button, setButton] = useState('follow');
const { loggedUserData, isUserAuthenticated } = useSelector((state) => state.userReducer);
console.log(loggedUserData)
/*
loggedUserData ===
{
id: 'id',
name: 'name',
email: 'email',
following: [],
followers: [],
}
*/
useEffect(() => {
try {
const isUserAlreadyFollowed = loggedUserData?.following.includes(userToFollow);
if (isUserAlreadyFollowed) {
setButton('unfollow');
} else {
setButton('follow');
}
} catch {}
}, [dispatch, loggedUserData, userToFollow]);
const onSubmit = (e) => {
e.preventDefault();
try {
dispatch(followUnFollowAction({ user_to_follow: userToFollow }));
} catch {}
};
const authLinks = (
<form onSubmit={(e) => onSubmit(e)}>
<button>{button}</button>
</form>
);
return <div data-testid='followUnFollow'>{isUserAuthenticated ? <div>{authLinks}</div> : null}</div>;
};
export default FollowUnFollow;
关注动作
export const followUnFollowAction =
({ user_to_follow }) =>
async (dispatch) => {
try {
const config = {
headers: {
'content-Type': 'application/json',
Accept: 'application/json',
Authorization: `Token ${localStorage.getItem('auth_token')}`,
},
};
const body = JSON.stringify({ user_to_follow });
const res = await axios.post(`${process.env.NEXT_PUBLIC_API_URL}/api/followers/follow/`, body, config);
dispatch({ type: FOLLOW_UNFOLLOW_USER_SUCCESS, payload: res.data });
dispatch(loadUserDetailsAction({ id: user_to_follow }));
dispatch(loadloggedUserDataAction());
} catch {
dispatch({ type: FOLLOW_UNFOLLOW_USER_FAIL });
}
};
答案 0 :(得分:1)
在这种情况下,您似乎只想监视 followUnFollowAction
函数并模拟 axios 库 post 方法,以便它返回您的组件期望的内容:
在您的测试中:
(delete the mock for `jest.mock('../../../redux/actions/follower')`)
import * as follower from '../../../redux/actions/follower';
jest.mock('axios', () => ({
default: {
post: () => Promise.resolve({
data: *data that you want to send to the FOLLOW_UNFOLLOW_USER_SUCCESS action*
})
}
}))
...
test('follow button should dispatch followUnFollowAction ', () => {
const followUnFollowActionSpy = jest.spy(follower, 'followUnFollowAction');
...
const timesActionHaveDispatched = followUnFollowActionSpy.mock.calls.length;
expect(timesActionHaveDispatched).toBe(1);
expect(followUnFollowActionSpy.mock.calls[0][0].user_to_follow).toBe(userToFollow);
...
此外,在测试状态更改时,我建议使用 findBy
而不是 getBy
,因为 findBy
返回承诺并等待更改提交到“DOM” (测试时使用 jsdom)如:
test('follow button should dispatch followUnFollowAction ', async () => {
...
const unFollowButton = await screen.findByRole('button', { name: 'unfollow' });