Testing pages secured by react-keycloak

In my React app, I am using keycloak and the KeycloakProvider from the "react-keycloak/web" library.

Certain routes are protected using a PrivateRoute component that pulls the keycloak state using the useKeycloak() hook and checking the user is authorised and has the correct roles:

const [keycloak, initialized] = useKeycloak();

My issue comes with testing my PrivateRoute component. No matter what I try initialized always remains false, blocking the page from rendering.

Using the useKeycloak.test.js file as inspiration, I made a MockAuthProvider component to wrap around my tests:

import React from "react";
import { KeycloakProvider } from "@react-keycloak/web";

export const createKeycloakStub = () => ({
  init: jest.fn().mockResolvedValue(true),
  updateToken: jest.fn(),
  login: jest.fn(),
  logout: jest.fn(),
  register: jest.fn(),
  accountManagement: jest.fn(),
  createLoginUrl: jest.fn(),
  ...
});

interface MockedAuthProviderProps {
  children: React.ReactChild;
  mocks: { [key: string]: typeof jest.fn };
}

export const MockedAuthProvider = (props: MockedAuthProviderProps) => {
  const { children, mocks } = props;
  const defaultMocks = createKeycloakStub();
  const keycloak = { ...defaultMocks, ...mocks };

  return (
    <KeycloakProvider keycloak={keycloak}>
      {children}
    </KeycloakProvider>
  );
};

I then use it in my tests as so

<MockedAuthProvider mocks={keycloakMocks}>
  <MemoryRouter initialEntries={["/secret"]}>
    <PrivateRoute roles={roles} path="/secret">
      <div>Protected Content</div>
    </PrivateRoute>
  </MemoryRouter>
</MockedAuthProvider>

Has anyone found a way of successfully testing components in conjunction with useKeycloak or getting initialized to be true?

Thanks


Solution 1:

I managed to work around it by mocking the hook itself. It's not quite as clean as I would have liked, but works well enough for now.

let mockInitialized = false;

jest.mock("@react-keycloak/web", () => {
  const originalModule = jest.requireActual("@react-keycloak/web");
  return {
    ...originalModule,
    useKeycloak: () =>  [
      mockKeycloakStub,
      mockInitialized
    ]
  };
})

I can then set the value of mockInitialized in each test, depending on what I want the initialized status to be.