0

Im currently trying to write jest test for my RTKQuery, but I get stuck on the authentication level for the test.

Basically the api Im using is designed to have the token on query param instead of having it on the request header: "https://api/v1/something/meta/?token=userToken"

So when I try to test the api call it shows me the request has been rejected. Does anyone know how to write the test with this case?

here is my RTKQuery endpoint:

// index.ts
export const rootApi = createApi({
  reducerPath: "root",
  baseQuery: fetchBaseQuery({baseUrl: API_ROOT}),
  endpoints: () => ({});
})

// dataEndpoint.ts
const token = getToken(); // Gets the user's token from localStorage after user login

export cosnt apiWithData = rootApi.injectEndpoints({
  endpoints: (build) => ({
    fetchDataMetaList: build.mutation<DataType, any>({
      query: ({offset = 0, size = 20, body}) => ({
        // token is passed in for query param
        url: `${API_URL}?offset=${offset}&size=${size}&token=${token}`,
        method: "POST",
        body: body || {}
      })
    })
  })
})

below is my test:

// data.test.tsx
const body = { offset: 0, size: 20, body: {} };
const updateTimeout = 10000;

beforeEach((): void => {
  fetchMock.resetMocks();
})

const wrapper: React.FC = ({ children }) => {
  const storeRef = setupApiStore(rootApi);
  return <Provider store={storeRef.store}>{children}</Provider>
}

describe("useFetchDataMetaListMutation", () => {
  it("Success", async () => {
    fetchMock.mockResponse(JSON.string(response));
    cosnt { result, waitForNextupdate } = renderHook(
      () => useFetchDataMetaListMutation(), 
      { wrapper }
    )

    const [fetchDataMetaList, initialResponse] = result.current;
    expect(initialResponse.data).toBeUndefined();
    expect(initialResponse.isLoading).toBe(false);

    act(() => {
      void fetchDataMetaList(body);
    })

    const loadingResponse = result.current[1];
    expect(loadingResponse.data).toBeUndefined();
    expect(loadingResponse.isLoading).toBe(true);

    // Up til this point everything is passing fine
   
    await waitForNextUpdate({ timeout: updateTimeout });

    const loadedResponse = result.current[1];

    // expect loadedResponse.data to be defined, but returned undefined
    // console out put for loaded Response status is 'rejected' with 401 access level 
    // error code
  })
})
user14459580
  • 206
  • 2
  • 12

1 Answers1

1

Doing a top-level const token means that as soon as that file is loaded, it will retrieve that token from the local store and that it will never be able to update that - so if that file is loaded before the user is logged in, it will be empty. That is pretty much also what happens in your test here.

To be honest, this might be the first time ever that I see a token as part of the url (that is a serious security problem as the token would be shared between users on copy-pasting the url, it's visible in the browser history even after logout etc!).

Unfortunately in that case, you cannot use prepareHeaders, but at least you could instead of the const use a function to get the current token - and if you import that from another file, you could also use jest mocking to just switch out that import.

phry
  • 35,762
  • 5
  • 67
  • 81
  • Thanks for the info. Yea the token in the URL isn't a proper approach, but the improved version for the auth continuously gets delayed. And I'm currently working on the UT for FE and this started to become an issue. Anyways, could you explain a little bit more in the last part where you mention using a function to get the current token? Did you mean to get the current token in the .test file and pass it down to the payload body such as `fetchDataMetaList({offset, size, body, token})`, I'm still very new to jest testing, any elaboration or reference would be highly appreciated – user14459580 Dec 03 '21 at 19:14
  • Oh actually, I've figured out to set the user token before each test to get the token. Before I did the manual setting my token was printing out `null` on the test console. But now it is printing out the token if I set it manually – user14459580 Dec 03 '21 at 23:41
  • I was just thinking of exporting a `getToken` function from a `token.js` file and mocking that one. But good you found a solution :) – phry Dec 04 '21 at 19:57