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

使用React Testing Library测试函数组件遇TypeError求解

问题描述

我有一个用于渲染消息的React函数组件MessageView,组件通过current函数根据传入的title和id获取对应消息。用React Testing Library(RTL)测试时,执行render(<MessageView title="sent" id={0} />)会触发TypeError:Cannot read properties of undefined (reading 'text'),错误出现在{msg!.text}这一行。我知道类组件可以监视属性/方法,但函数组件做不到,结合RTL的指导原则,想请教怎么定义msg.text或者用其他方式完成组件测试。

相关代码

测试代码

it('MailView', async () => {
  render(<MessageView title="sent" id={0} />)
})

组件代码

export function MessageView({ title, id }: MessageViewProps) {
  const bucket = title === "inbox" ? received(user) : sent(user) 
  const msg = current(bucket, id)       // 获取当前邮件消息

  return(
    <Box>
      {msg!.text}     <------ 触发TypeError的位置
    </Box>
  );
}

依赖版本

"@testing-library/jest-dom": "^5.16.5",
"@testing-library/user-event": "^14.4.3",
"@types/jest": "^27.5.2",
"@types/node": "^16.18.36",
"@types/react": "^18.2.13",
"@types/react-dom": "^18.2.6",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-scripts": "5.0.1",
"typescript": "^4.9.5",

相关函数与接口

export function current(items: Message[], idx: number) {
  return items[idx];
}
export interface Message {
  id: number
  date: string
  sender: string
  subject: string
  recipient: string
  text: string
}  

解决方案

问题核心是测试时current(bucket, id)返回了undefined,强行访问msg!.text导致报错。结合RTL"测试用户行为而非底层实现"的原则,提供以下几种可行方案:

1. 模拟received和sent函数的返回值

组件依赖received(user)和sent(user)获取消息列表,测试时用Jest模拟这两个函数,让它们返回包含指定id消息的数组:

// 在测试文件顶部模拟目标函数
jest.mock('./path-to-your-functions-file', () => ({
  received: jest.fn(() => [{ 
    id: 0, 
    text: '测试收件箱消息', 
    date: '2024-01-01',
    sender: 'test@example.com',
    subject: '测试主题',
    recipient: 'user@example.com'
  }]),
  sent: jest.fn(() => [{ 
    id: 0, 
    text: '测试已发送消息', 
    date: '2024-01-01',
    sender: 'user@example.com',
    subject: '测试主题',
    recipient: 'test@example.com'
  }]),
}));

it('MailView 能正确渲染已发送消息', async () => {
  render(<MessageView title="sent" id={0} />);
  // 验证消息文本是否成功渲染
  expect(screen.getByText('测试已发送消息')).toBeInTheDocument();
});

2. 给组件添加容错处理(推荐,同时提升生产环境稳定性)

在组件里增加空值检查,避免找不到消息时崩溃,也让测试场景更完整:

export function MessageView({ title, id }: MessageViewProps) {
  const bucket = title === "inbox" ? received(user) : sent(user) 
  const msg = current(bucket, id)

  // 处理找不到消息的边界情况
  if (!msg) {
    return <Box>暂无消息</Box>;
  }

  return(
    <Box>
      {msg.text}
    </Box>
  );
}

测试时可以分别验证两种场景:

// 测试无对应消息的情况
it('MailView 无对应消息时显示提示文本', async () => {
  jest.mock('./path-to-your-functions-file', () => ({
    sent: jest.fn(() => []),
  }));
  render(<MessageView title="sent" id={0} />);
  expect(screen.getByText('暂无消息')).toBeInTheDocument();
});

3. 重构组件,通过props传入消息列表(解耦依赖)

把bucket的获取逻辑移到组件外部,通过props传入消息列表,测试时直接传入预设的测试数据即可:

// 重构后的组件
export function MessageView({ messages, id }: { messages: Message[], id: number }) {
  const msg = current(messages, id)

  if (!msg) {
    return <Box>暂无消息</Box>;
  }

  return(
    <Box>
      {msg.text}
    </Box>
  );
}

测试代码:

it('MailView 能渲染指定的测试消息', async () => {
  const testMessages = [{ 
    id: 0, 
    text: '测试消息', 
    date: '2024-01-01',
    sender: 'test@example.com',
    subject: '测试主题',
    recipient: 'user@example.com'
  }];
  render(<MessageView messages={testMessages} id={0} />);
  expect(screen.getByText('测试消息')).toBeInTheDocument();
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 04:36:04