Having the following HTML output:
<ul>
<li>Menu 1</li>
<li>Menu 2(Parent)
<ul>
<li>Child 1</li>
<li>Child 2</li>
<li>Child 3 (Parent 2)
<ul>
<li>Child 4</li>
<li>Child 5</li>
</ul>
</li>
</ul>
</li>
</ul>
I need to test whether the elements exist and are properly nested. I can write a test as follows:
it('should render nested elements', () => {
<MyComponent />
expect(screen.getByText('Menu 1').toBeInDocument())
expect(screen.getByText('Menu 2(Parent)').toBeInDocument())
expect(screen.getByText('Child 3 (Parent 2)').toBeInDocument())
expect(screen.getByText('Child 5').toBeInDocument())
}
and that will tell me it does exist in the DOM but this test will also pass for the following HTML and I do not want that:
<ul>
<li>Menu 1</li>
<li>Menu 2(Parent)</li>
<li>Child 1</li>
<li>Child 2</li>
<li>Child 3 (Parent 2)</li>
<li>Child 4</li>
<li>Child 5</li>
</ul>
How can I test if the element exists and it is properly nested?
With the combination of these methods.
getByText
( get the element with that text )toBeInTheDocument
( check if the element in the document )toBe
( equation )toContainElement
( check if it contains a child )You can fully test the DOM structure.
import { render, screen } from '@testing-library/react';
it('should render nested elements correctly', () => {
render(<MyComponent />);
const menu1 = screen.getByText('Menu 1');
expect(menu1).toBeInTheDocument();
expect(menu1.parentElement.tagName).toBe('UL');
const menu2 = screen.getByText('Menu 2(Parent)');
expect(menu2).toBeInTheDocument();
expect(menu2.parentElement.tagName).toBe('LI');
expect(menu2.nextElementSibling.tagName).toBe('UL');
const child1 = screen.getByText('Child 1');
expect(child1).toBeInTheDocument();
expect(child1.parentElement.parentElement).toContainElement(menu2);
const child3 = screen.getByText('Child 3 (Parent 2)');
expect(child3).toBeInTheDocument();
expect(child3.parentElement.tagName).toBe('LI');
expect(child3.nextElementSibling.tagName).toBe('UL');
const child5 = screen.getByText('Child 5');
expect(child5).toBeInTheDocument();
expect(child5.parentElement.parentElement).toContainElement(child3);
});