react-testing-library can't test for text rendered from a custom hook

1k Views Asked by At

In my react app, I use a custom hook to retrieve localized text from a JSON file with translations. It works fine, but whenever I use testing-library to run tests expecting to find text, the text cannot be found, because the hook has not fired and populated the text at the time that the snapshot of the component is taken. I am wondering if there is a way to properly test this?

//locales JSON file

      "LABELS": {
        "WELCOME": {
          "title": "Welcome"
        },
   }

//homepage.ts

const homePageText = [
  {
    variableName: "welcomeText",
    key: "LABELS.WELCOME.title",
    defaultValue: "Welcome",
  },

//useGetLocalizedText custom hook

import { useMemo, useState } from "react"
import { useSelector } from "react-redux"
import translate from "@localization/translate"
import intl from "react-intl-universal"

export const useGetLocalizedText = (moduleName: string) => {
  const [messages, setMessages] = useState([])
;(async () => {
    const msgArray = await import(
      `@localization/modules/${moduleName}.ts`
    ).then((msgs) => msgs)
    setMessages(msgArray?.default ? msgArray.default : [])
  })()

  const initComplete: boolean = testInitComplete ? testInitComplete : useSelector(
    (state) => state.localization.initComplete
  )
  const localizedText = useMemo(() => {
    const localizedTextTemp: any = {}
    messages?.length > 0 &&
      messages.forEach((msg) => {
        localizedTextTemp[msg.variableName] = translate(
          intl,
          msg.key,
          initComplete,
          msg.defaultValue
        )
      })
    return localizedTextTemp
  }, [initComplete, messages])

  return localizedText
}

export default useGetLocalizedText

//Homepage.tsx

const HomePage = () => {
 const localizedText = useGetLocalizedText("homePage")

return (
  <div>
    <span> {localizedText.welcome} </span>
</div>
)
}

When I run the app, the text appears correctly, but when I run the tests the snapshot shows and empty span and I get the error "TestingLibraryElementError: Unable to find an element with the text: Funds Movement Template. This could be because the text is broken up by multiple elements. In this case, you can provide a function for your text matcher to make your matcher more flexible."

//homepage-test.tsx

import React from "react"
import { customRender } from "../testUtils"
import { screen } from "@testing-library/react"
import HomePage from "@pages/home/"


describe("Home Page", () => {

  it("renders without crashing", () => {

    customRender(
      <HomePage/>
    )
    expect(screen.getByText("Welcome")).toBeInTheDocument()

  })

//snapshot

<div> <span> </span> <div>

So my question is, is there a way to run a test that will find this text/create the snapshot so the text is there? I know I can pass in hardcoded text as a prop simply for testing but don't think that is a great solution.

2

There are 2 best solutions below

0
On

I don't know what's inside the customRender() helper but I can guess that you don't provide something what is needed to run your hook properly.

Maybe you need to mock Redux store to provide proper value of initComplete?

As a part of the solution, I would use @testing-library/react-hooks to test the hook itself and if hook will work and if it will be needed to know if hook works in the component's context test the component afterwards. If hook would be tested properly but component will still make problems like the one you mentioned, it will be much easier to spot the bug.

0
On

You should not call hooks directly inside your test. You should use renderHook to be

Example

renderHook(() => useTheme())