I have a component I'm having a hard time figuring out how to write tests for using Jest and MSW.
It's an "AuthProvider" that initializes keycloak-js and renders children.
I have written a test that checks that children
render correctly.
I want to test the following scenarions:
- it should render children (this one works)
- it should initialize keycloak (call keycloak.init)
- it should make a post request to our SSO endpoint (hit a rest mock in MSW)
- it should call
onKeycloakEvent
with an "onReady" event
- it should call
login
- it should call
onKeycloakTokens
(with expected tokens)
- it should set
user
(with expected userName and roles)
- it should set
authToken
(with expected token)
- it should call
login
when onKeycloakEvent
is called with an "onTokenExpired" event
I have installed and setup https://github.com/SectorLabs/keycloak-mock
to handle the requests using nock
.
But I am completely stuck when it comes to figuring out how to wait for these events to have been called since nothing changes in the DOM.
the test immediately passes as soon as the children render without waiting for keycloak to even attempt to initialize.
How would I go about forcing jest to wait for a function called inside the component, or for keycloak to initialize?
I have tried to mock keycloak.init and expect 2 assertions but with no success.
import React, { useState } from 'react'
import { ReactKeycloakProvider } from '@react-keycloak/web'
import keycloak from 'src/lib/keycloak'
import { IDP_HINT } from 'src/common/constants'
import { useAtom, useUpdateAtom, authTokenAtom, userAtom } from 'src/atoms'
type KeycloakAuthProviderProps = {
children: React.ReactNode
}
const login = () => keycloak.login({ IDP_HINT })
const KeycloakAuthProvider = ({ children }: KeycloakAuthProviderProps) => {
const [calledLogin, setCalledLogin] = useState(false)
const [authToken, setAuthToken] = useAtom(authTokenAtom)
const setUser = useUpdateAtom(userAtom)
const onKeycloakEvent = (event: string, error: any) => {
console.log('onKeycloakEvent', event)
if (event === 'onReady') {
if (keycloak && !calledLogin && !authToken) {
// on first load, automatically attempt a keycloak login.
login()
setCalledLogin(true)
}
} else if (keycloak && event === 'onTokenExpired') {
login()
}
if (error) console.error(error)
}
const onKeycloakTokens = (tokens: any) => {
console.log('onKeycloakTokens', tokens)
if (keycloak?.tokenParsed && keycloak.tokenParsed?.realm_access?.roles) {
setUser({
userName: keycloak.tokenParsed.preferred_username,
roles: keycloak.tokenParsed.realm_access.roles,
})
}
const authToken = tokens.token
setAuthToken(authToken)
}
return (
<ReactKeycloakProvider
initOptions={{ flow: 'implicit', onLoad: 'check-sso' }}
onEvent={onKeycloakEvent}
onTokens={onKeycloakTokens}
authClient={keycloak}
>
{children}
</ReactKeycloakProvider>
)
}
export default KeycloakAuthProvider
keycloak.init mock attempt (failed)
import React from 'react'
import { render, screen } from 'src/test/test-utils'
import AuthProvider from './AuthProvider'
import keycloak from './index'
// MISSING tests:
// - it should initialize keycloak (call keycloak.init)
// - it should make a post request to our SSO endpoint (hit a rest mock in MSW/nock)
// - it should call `onKeycloakEvent` with an "onReady" event
// - it should call `login`
// - it should call `onKeycloakTokens` (with expected tokens)
// - it should set `user` (with expected userName and roles)
// - it should set `authToken` (with expected token)
// - it should call `login` when `onKeycloakEvent` is called with an "onTokenExpired" event
test('AuthProvider initializes keycloak', () => {
expect.assertions(2); // attempt to make keycloak wait for init
keycloak.init = jest.fn() // mock keycloak.init
render(
<AuthProvider>
<div>test</div>
</AuthProvider>
)
const childElement = screen.getByText(/test/i)
expect(childElement).toBeInTheDocument()
expect(keycloak.init).toHaveBeenCalled(); // expect to have called keycloak
})
question from:
https://stackoverflow.com/questions/65919056/how-to-test-a-provider-component-using-network-requests-with-jest-msw 与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…