React Testing Library was developed, to my understanding, to write tests based on the user's experience of the elements being rendered. With third party components this can be cumbersome at times.
I think there are a few approaches to take:
- Review the React Testing Library cheatsheet and ask yourself the primary way the user understands the element. Maybe in this case it is by the role of the element? I.e. does your third party component hold a aria property dictating the role for that component?
Example: app uses Buttons from bootstrap
const App = () => {
const [state, setState] = useState(0)
const increase = () => {
const newState = state + 1
setState(newState)
}
const decrease = () => {
const newState = state - 1
setState(newState)
}
return (
<div>
<div className="App">
<Button variant="primary" size="lg" onClick={increase}></Button>{' '}
<Button variant="primary" size="lg" onClick={decrease}></Button>{' '}
</div>
<div className="number">
{state}
</div>
</div>
)
}
I purposefully did not provide text for the buttons but I can still find those buttons, here is the test:
it('buttons increase and decrease displayed value', () => {
const component = render(<App/>)
const buttons = component.getAllByRole('button')
for (let i = 0; i < buttons.length; i++){
fireEvent.click(buttons[i])
}
expect(component.findByText('0')).toBeTruthy()
})
Even though I couldn't set a testId or find by text, I could still gather an array of nodes that play the role of button. From there it is a matter of searching through the array to find which button you need. And to my pleasure, the test passes but this is a silly test because the buttons have their own logic so I should separate them into separate tests as such:
it('increases and decreases button and displays accurate value', () => {
const component = render(<App/>)
const buttons = component.getAllByRole('button')
fireEvent.click(buttons[0])
expect(component.findByText('1')).toBeTruthy()
})
If needed consider wrapping the third party component in a div, provide a data-testid for that data, then access the first, sibling, last child nodes that are children to that div. I've often used this to navigate to where the third party component node exists in the dom:
<div data-testid="test">
<SomeComponent onChange={()=> {}}/>
</div>
Since some of the react testing library queries return a dom node, we can find this component with:
const findBootstrapComp = component.getByTestId('test').firstChild
What we should probably avoid as much as possible, but maybe your case is allowable given what can be access with the queries provided, you can query the container node manually by some attribute:
const { container } = render()
const button = container.querySelector('button')
Long story short, React Testing Library provides plenty of tools to query for what you need. If that third party component is rendering, then there are probably attributes for that element that you can query. The above is just from personal experience, each project is different. May even consider pulling out those callbacks, isolating them and then testing the logic since you're more concerned about the logic from the sounds of it.
Also, I agree with your sentiment on Boostrap testing their own components. You're not actually looking to test a third party component though, your looking to test some functionality or logic you have written that is being accessed by a third party component. Or maybe you want to pull the css of that element and confirm that it hasn't switched at some point during development. Whatever it may be, I hope the above helps in some way. If anything, create a component in a test file using the third party components and use the debug() api to take a look at the elements to see what they have that you may query for.
helpful links:
React Testing Library cheatsheet
Dom Navigation
Node interface