如何用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
相关产品推荐
相关产品推荐

