如何在JestJS中测试嵌套DOM元素的正确层级结构?
如何在Jest中验证元素存在且嵌套结构正确
我需要测试组件是否渲染出正确的嵌套菜单结构,预期的HTML结构如下:
<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>
我写了如下测试代码,但它只能验证元素存在,就算是下面这种完全没有嵌套的结构也能通过测试,不符合预期:
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()) }
错误的非嵌套结构示例:
<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>
请问如何在Jest中同时验证元素存在且嵌套结构正确?
解决方法
方法1:用within限定查询范围,验证父子嵌套
利用Testing Library的within方法,先定位父级元素,再在父元素的范围内查询子元素,确保子元素确实嵌套在父元素内部。修改后的测试代码如下:
it('should render correctly nested menu structure', () => { // 补全render调用,原代码缺少这一步 render(<MyComponent />); // 验证顶级元素Menu 1存在 expect(screen.getByText('Menu 1')).toBeInTheDocument(); // 获取Menu 2所在的<li>父元素 const menu2ParentLi = screen.getByText('Menu 2(Parent)').closest('li'); expect(menu2ParentLi).toBeInTheDocument(); // 在Menu 2的父元素内查询子菜单,确保Child1、Child2是它的子元素 within(menu2ParentLi).getByText('Child 1'); within(menu2ParentLi).getByText('Child 2'); // 获取Child 3所在的<li>父元素,再验证它的子元素Child4、Child5 const child3ParentLi = within(menu2ParentLi).getByText('Child 3 (Parent 2)').closest('li'); within(child3ParentLi).getByText('Child 4'); within(child3ParentLi).getByText('Child 5'); });
方法2:通过role定位元素,验证层级结构
利用HTML元素的默认role(比如<ul>的role是list,<li>的role是listitem),逐层验证列表和列表项的嵌套关系:
it('should validate nested structure via roles', () => { render(<MyComponent />); // 获取顶级列表,验证顶级列表项数量 const topLevelList = screen.getByRole('list'); const topLevelItems = within(topLevelList).getAllByRole('listitem'); expect(topLevelItems).toHaveLength(2); // 顶级应该有Menu1和Menu2两个项 // 找到Menu2的列表项,获取它内部的子列表并验证子项数量 const menu2Item = topLevelItems.find(item => item.textContent.includes('Menu 2(Parent)')); const firstChildList = within(menu2Item).getByRole('list'); const firstChildItems = within(firstChildList).getAllByRole('listitem'); expect(firstChildItems).toHaveLength(3); // 对应Child1、Child2、Child3 // 找到Child3的列表项,验证它的子列表和子项数量 const child3Item = firstChildItems.find(item => item.textContent.includes('Child 3 (Parent 2)')); const secondChildList = within(child3Item).getByRole('list'); const secondChildItems = within(secondChildList).getAllByRole('listitem'); expect(secondChildItems).toHaveLength(2); // 对应Child4、Child5 });
方法3:快照测试,快速验证整体结构
如果想一次性验证整个组件的渲染结构是否符合预期,可以使用Jest的快照测试:
it('should match nested structure snapshot', () => { const { container } = render(<MyComponent />); expect(container.firstChild).toMatchSnapshot(); });
首次运行会生成快照文件,后续测试会对比当前渲染结果与快照,结构变化时测试会直接失败,适合快速校验整体结构。
内容的提问来源于stack exchange,提问作者ReynierPM
相关产品推荐
相关产品推荐

