You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Storybook测试MUI 5 Select组件无法定位role="listbox"问题

解决MUI 5 StyledSelect在Storybook测试中无法访问listbox的问题

问题原因

MUI的Select组件下拉菜单(对应role="listbox"的元素)默认会挂载到document.body下,而非组件所在的root容器内。Storybook的canvasElement仅包含root容器内的DOM,因此用within(canvasElement)无法定位到这个外部元素。

解决方案

方案1:直接从全局文档中查找元素

跳过canvas的范围限制,直接在document内查找listbox,同时使用findByRole(而非getByRole)等待下拉菜单渲染完成:

ChangeOption.play = async ({ canvasElement, globals }) => {
  // Arrange
  const canvas = within(canvasElement);
  const selectElement = canvas.getByLabelText(/select-under-test/i);
  await expect(selectElement).toHaveTextContent(/option 1/i);
  // Act
  await userEvent.click(selectElement);
  // 直接从document范围查找,用findByRole等待元素渲染
  const listbox = await screen.findByRole('listbox');
  
  // 后续操作示例:选择Option 2
  const option2 = within(listbox).getByText(/option 2/i);
  await userEvent.click(option2);
  await expect(selectElement).toHaveTextContent(/option 2/i);
};

方案2:修改MUI Select的挂载目标

通过MenuProps配置下拉菜单挂载到组件内部,让listbox落入canvasElement的范围内:

ChangeOption.args = {
  labelId: 'dafault-select-label',
  id: 'default-select',
  label: 'select-under-test',
  sx: { width: 240 },
  value: 1,
  // 添加MenuProps指定挂载容器
  MenuProps: {
    container: (element) => element.parentElement, // 将下拉挂载到Select的父元素中
  },
  children: [
    <StyledMenuListItem key={'none1'} value={-1}>
      None
    </StyledMenuListItem>,
    <StyledMenuListItem key={1} value={1}>
      Option 1
    </StyledMenuListItem>,
    <StyledMenuListItem key={2} value={2}>
      Option 2
    </StyledMenuListItem>,
    <Divider key="div3" />,
    <StyledMenuListItem key={3} value={3}>
      Option 3
    </StyledMenuListItem>,
  ],
};

ChangeOption.play = async ({ canvasElement, globals }) => {
  const canvas = within(canvasElement);
  const selectElement = canvas.getByLabelText(/select-under-test/i);
  await expect(selectElement).toHaveTextContent(/option 1/i);
  
  await userEvent.click(selectElement);
  // 现在可直接从canvas中找到listbox
  const listbox = await canvas.findByRole('listbox');
  
  // 后续操作
};

注意事项

  • 方案1简单直接,但如果页面存在多个listbox,建议给目标元素添加data-testid属性,通过getByTestId精准定位,避免误匹配。
  • 方案2更符合测试隔离原则,确保只操作当前组件的下拉菜单,适合复杂场景的测试。

内容的提问来源于stack exchange,提问作者miuosh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 02:50:39