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.