Home > Software engineering >  Cannot read property 'endsWith' of undefined - Redux Toolkit testing
Cannot read property 'endsWith' of undefined - Redux Toolkit testing

Time:11-26

I'm having issues while testing a slice with React Testing Library. I was running the following simple test:

import reducer from "states/slices";

test("should return the initial state", () => {
  expect(reducer(undefined, {})).toEqual({
    loading: true,
    libraries: [],
    books: [],
    error: {
      error: false,
      variant: "error",
      message: "",
    },
  });
});

The slice under test is the following:

import { createAsyncThunk, createSlice } from "@reduxjs/toolkit";
import { getLibraries, getBooks } from "api";

const initialState = {
  loading: true,
  libraries: [],
  books: [],
  error: {
    error: false,
    variant: "error",
    message: "",
  },
};

export const fetchLibraries = createAsyncThunk("books/libraries", async () => {
  const res = await getLibraries();
  return res.data;
});

export const fetchBooks = createAsyncThunk(
  "books/books",
  async ({ title, libraryId, page }) => {
    const res = await getBooks(title, libraryId, page);
    return res.data;
  }
);

const booksSlice = createSlice({
  name: "books",
  initialState,
  reducers: {
    unsetError: (state) => {
      state.error = { error: false, variant: "error", message: "" };
    },
  },
  extraReducers: (builder) => {
    builder
      .addCase(fetchLibraries.fulfilled, (state, action) => {
        state.loading = false;
        state.libraries = action.payload;
      })
      .addCase(fetchBooks.fulfilled, (state, action) => {
        state.loading = false;
        state.books = action.payload;
      })
      // .addCase(fetchBooks.pending, (state, action) => {
      //   state.loading = true;
      //   state.error = { error: false, variant: "error", message: "" };
      // })
      // .addCase(fetchLibraries.pending, (state, action) => {
      //   state.loading = true;
      //   state.error = { error: false, variant: "error", message: "" };
      // })
      // .addCase(fetchBooks.rejected, (state, action) => {
      //   state.loading = false;
      //   state.error.error = true;
      //   state.error.variant = "error";
      //   state.error.message =
      //     "Error. Try again.";
      // })
      // .addCase(fetchLibraries.rejected, (state, action) => {
      //   state.loading = false;
      //   state.error.error = true;
      //   state.error.variant = "error";
      //   state.error.message =
      //     "Error. Try again.";
      // });
      .addMatcher(
        (action) => action.type.endsWith("/pending"),
        (state, action) => {
          state.loading = true;
          state.error = { error: false, variant: "error", message: "" };
        }
      )
      .addMatcher(
        (action) => action.type.endsWith("/rejected"),
        (state, action) => {
          state.loading = false;
          state.error.error = true;
          state.error.variant = "error";
          state.error.message =
            "Error. Try again.";
        }
      );
  },
});

const { actions, reducer } = booksSlice;

export const { unsetError } = actions;

export default reducer;

I'm getting back TypeError: Cannot read property 'endsWith' of undefined when running the test with the addMatchers in the slice. If I replace them with the addCases (the commented ones), the test works as expected.

Instead, if I normally launch the application, everything works correctly in either case.

Why does this happen? I am defining wrongly the matchers?

CodePudding user response:

In your test case you are using {} as an action. Therefore when you are checking in the matcher action.type.endsWith() the action.type is not defined.

You can probably fix this if you use action.type?.endsWith in your matcher.

  • Related