Search code examples
reactjsreduxjestjsreact-testing-libraryredux-toolkit

How do I add some state to redux state when try to write unit test in jest/RTL?


I wanted to start testing with Redux-toolkit, according to the article I found.

https://redux.js.org/usage/writing-tests#setting-up

The right practice is to write integration test. But right now I want to test a sign out button which is controlled by authstate,in order to set it's value I have to sign in first. What I want to do is I can give some state to the authstate in the test file instead of having to login. So I can actually write unit test on my sign out button.

Here's the code and the test

const Navbar = () => {
  const cart = useAppSelector((state) => state.cart);
  const user = useAppSelector((state) => state.auth);
  const dispatch = useAppDispatch();
  const handleLogout = () => {
    localStorage.removeItem("persist:root");
    window.location.reload();
  };
  return(
     {user.user !== null ? (
            <>
              <MenuItem>Hello {user.user?.username} </MenuItem>{" "}
              <ExitToApp
                style={{ cursor: "pointer", marginLeft: "10px" }}
                onClick={() => handleLogout()}
              />
              <Link to="/order">
                <MenuItem>Order</MenuItem>
              </Link>
            </>
          ) : (
            <>
              <Link to="/register">
                <MenuItem>REGISTER</MenuItem>
              </Link>
              <Link to="/login">
                <MenuItem>SIGN IN</MenuItem>
              </Link>
            </>
          )}
  )

Authslice

const slice = createSlice({
  name: "auth",
  initialState: { user: null, token: null } as {
    user: null | UserDataInterface;
    token: null | string;
  },
  reducers: {
    setCredentials: (state,{ payload: { user, token } }: PayloadAction<{ user: UserDataInterface; token: string }>) => {
      state.user = user;
      state.token = token;
    }
  },
  extraReducers: (builder) => {}
});

test file

test("When click on logoutk,it will trigger handle logout", () => {
   //TODO: should let the user state to not be empty first 
   await store.dispatch(setCredentials())
   //TODO: then we can track if logout label exist
   //TODO: click on logout button and mock localstorage maybe ?
});

What should I do with this kind of unit test, if it involves prerequisites for redux-state ?


Solution

  • After some research, I found out how to do this. It might not be the best practice. But I think it could be useful in a lot of scenario if you don't want to write integration test.

    test("When click on logout,it will trigger handle logout", async () => {
        //TODO: should let the user state to not be empty first
        store.dispatch(
          setCredentials({
            user: {
              username: "Kai",
              _id: "efekfjefke",
              email: "dfdkdfkdf@gmail.com",
              createdAt: new Date(2013, 13, 1),
              updatedAt: new Date(2013, 13, 1),
              img: "223232",
            },
            token: "test12345",
          })
        );
        //TODO: then we can track if logout label exist
        await waitFor(() =>
          expect(screen.queryByRole("userTitle")).toBeInTheDocument()
        );
        await waitFor(() =>
          expect(screen.queryByTestId("logout")).toBeInTheDocument()
        );
        //TODO: click on logout button and mock localstorage maybe ?
        const userLogout = screen.getByTestId("logout");
        fireEvent.click(userLogout);
        // should not be able to query the userTitle since it's logout
        await waitFor(() =>
          expect(screen.queryByRole("userTitle")).not.toBeInTheDocument()
        );
      });
    
    

    I found out you can directly dispatch state through the store. which is really convenient.

    Cause for me. What's tricky is I don't know how to write integration test across two components or pages

    Right now if I can directly dispatch some state first. I can unit-test the function in single page or components to see if it does what I needed.

    I am pretty new to testing, so if there's any better approach at this, please let me know!

    Hope this can help someone who is struggling!!