the goal
I am trying to test that useEffect function that changes the text of a follow button to unfollow after he have been clicked
the result
when i test the component the follow/unfollow action is getting dispatched but the text of the button is not changing
explanation of the login inside the useEffect function
The way it hapeens is that after clicking the follow button a follow/unfollow action is dispatched and add the who got followed (userToFollow) to the logged user following accounts array (loggedUserData.following), and then changes the button text to unfollow and vice verca.
my 2 cents on why the test is failing
I suppose that the problem lays in the fact that i mocked the follow/unfollow action therefore it's just getting called and not resolved the way its should, if I could add the user that have been followed to the list of the logged user following accounts the problem should be solved.
anyone has an idea how can I do it or offer a better idea to solve it?
SOLUTION so the problem was that redux-mock-store doesnt approve updating state so I've rendered the tests with real the redux Store and everything works
load logged user data action
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 });
}
};
the error
TestingLibraryElementError: Unable to find an accessible element with the role "button" and name "unfollow"
the test
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();
});
});
the component
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;
the follow action
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 });
}
};