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

如何用React/Jest测试useMemo返回值?首字母组件测试失败

React首字母组件测试失败问题解决

问题描述

开发了一个React组件,通过useMemo将用户姓名转换为两个首字母。期望传入姓名“Sjaak de Boer”时渲染出“SB”,但测试始终失败,尝试定时器也未解决。

组件代码

import React, { useState, useMemo } from "react";

interface Props {
  name?: string;
}

const ObAvatar: React.FC<Props> = ({ name, ...props }) => {
  const [nameValue, setNameValue] = useState<string>(name);

  const returnInitials = useMemo(() => {
    if ((nameValue && nameValue.length === null) || !nameValue) return "...";
    const rgx: RegExp = new RegExp(/(\p{L}{1})\p{L}+/, "gu");
    const matches: any = nameValue.matchAll(rgx); // fix any!
    let initials: Array<any> = [...matches] || [];
    initials = (
      (initials.shift()?.[1] || "") + (initials.pop()?.[1] || "")
    ).toUpperCase();
    return initials;
  }, [nameValue]);

  return (
    <span style={{ border: "solid 1px red" }} data-testid="initials">
      {returnInitials}
    </span>
  );
};

export default ObAvatar;

测试代码

/** @jest-environment jsdom */

import React from "react";
import { render, screen } from "@testing-library/react";
import "@testing-library/jest-dom";
import Initials from "./Initials";

describe("Initials", () => {
  test("Should render an initials SB (Sjaak de Boer)", () => {
    render(<Initials name="Sjaak de Boer" />);
    const initialsElm: HTMLSpanElement = screen.getByTestId("initials");
    expect(initialsElm).toHaveTextContent(/SB/i);
    screen.debug();
  });
});

问题分析与解决方案

1. 组件导入不匹配

测试代码中导入的是Initials,但组件实际导出的是ObAvatar,文件名也不对应,导致测试渲染的是错误组件,直接引发失败。

修复:
将测试中的导入和渲染改为正确的组件名:

import ObAvatar from "./ObAvatar";

describe("ObAvatar", () => {
  test("Should render initials SB for 'Sjaak de Boer'", () => {
    render(<ObAvatar name="Sjaak de Boer" />);
    const initialsElm: HTMLSpanElement = screen.getByTestId("initials");
    expect(initialsElm).toHaveTextContent(/SB/i);
  });
});

2. 不必要的useState使用

组件用useState同步name prop为nameValue,但useState初始值仅在首次渲染生效,后续name更新不会同步状态。此处无需维护内部状态,直接使用name prop即可。

修复:
移除useState,直接依赖name:

const ObAvatar: React.FC<Props> = ({ name, ...props }) => {
  const returnInitials = useMemo(() => {
    if (!name) return "...";
    const rgx = new RegExp(/(\p{L}{1})\p{L}+/, "gu");
    const matches = name.matchAll(rgx);
    const initialsArray = [...matches] || [];
    const firstInitial = initialsArray.shift()?.[1] || "";
    const lastInitial = initialsArray.pop()?.[1] || "";
    return (firstInitial + lastInitial).toUpperCase();
  }, [name]);

  return (
    <span style={{ border: "solid 1px red" }} data-testid="initials">
      {returnInitials}
    </span>
  );
};

3. 错误的空值判断逻辑

原代码中(nameValue && nameValue.length === null)是无效判断——字符串的length不可能为null,只需!nameValue即可覆盖空字符串、undefined等情况。

最终效果

修复后,组件会正确提取"Sjaak de Boer"的首字母S和B,组合为"SB",测试即可通过。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 05:40:30