Search code examples
javascriptreactjsjestjs

How can I test nested elements in JestJS?


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?


Solution

  • With the combination of these methods.

    1. getByText ( get the element with that text )
    2. toBeInTheDocument ( check if the element in the document )
    3. toBe ( equation )
    4. 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);
    });