'Test correct SVG component renders with jest and react-testing-library
I have an svg inside a React component that renders conditionally.
<div className='avatar'>
{gender === true ? <MaleAvatar /> : <FemaleAvatar />}
</div>
MaleAvatar and FemaleAvatar are components containing svgs. Initially, I want the MaleAvatar svg to render and then if the value of gender is changed to false the FemaleAvatar svg renders - but the male avatar should render first and that's what I want to test.
The component the conditional is in is a child of a child, but I am testing elements in that component by text and the test works fine eg:
const personDetailsText = screen.getByText('Personal details')
I am testing with jest and react-testing-library, but using a testing id on the parent div then grabbing the first child doesn't work because it can't recognise the testing id. So if I have:
<div data-testid='avatar' className='avatar'>
{gender === true ? <MaleAvatar /> : <FemaleAvatar />}
</div>
...then the test below fails at 'const avatarSVG = screen.getByTestId('avatar')':
test('gender avatar is male on initialisation', () => {
const avatarSVG = screen.getByTestId('avatar')
expect(avatarSVG).toBeInTheDocument()
expect(() => screen.getByTestId('female-avatar').toThrow())
expect(avatar.firstChild.nodeName).toBe('MaleAvatar')
})
I'm using React hooks and I've read I also need to somehow compensate for React rendering the SVGs after the initial render - after useEffect is finished, but I can't find how to do this with react-testing-library and hooks?
This also does not work:
const avatarSVG = document.querySelector('MaleAvatar')
How can I grab the SVG components to check the correct one renders?
Solution 1:[1]
You can view the content of any elements with screen.debug(), in your case svg element and according to this content you can use a selector:
import { render, screen } from "@testing-library/react";
screen.debug() // it shows the "dom"
In my case, I use FontAwesomeIcon and after to use debug I can see:
<svg
aria-hidden="true"
class="svg-inline--fa fa-fire fa-w-12 "
color="#FF9C31"
data-icon="fire"
data-prefix="fas"
focusable="false"
role="img"
viewBox="0 0 384 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M216 23.86c0-23.8-30.65-32.77-44.15-13.04C48 191.85 224 200 224 288c0 35.63-29.11 64.46-64.85 63.99-35.17-.45-63.15-29.77-63.15-64.94v-85.51c0-21.7-26.47-32.23-41.43-16.5C27.8 213.16 0 261.33 0 320c0 105.87 86.13 192 192 192s192-86.13 192-192c0-170.29-168-193-168-296.14z"
fill="currentColor"
/>
</svg>
So, I can use
const { container } = render(<MyComponent />);
And use some selector in my case [data-icon='fire']
const svgEl = container.querySelector("[data-icon='fire']") as HTMLImageElement;`
It is done, additionally, I can validate if it has a specific class
expect(svgEl.classList.toString()).toContain("fa-fire");
Solution 2:[2]
You can put await to find the svg:
await screen.getByTestId('id')
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Cristhian D |
Solution 2 | JW Geertsma |