Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
856 views
in Technique[技术] by (71.8m points)

reactjs - How to test a Provider component using network requests with jest + MSW

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)
Waitting for answers

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...