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

React Testing Library测试:初始渲染与按钮点击时数组长度为2的问题

React组件测试问题:验证usersCards元素数量及解决TypeError错误

问题描述

首次测试React应用,需编写测试用例验证组件中的usersCards数组在初始渲染和点击DEAL按钮时均包含2个元素,但遇到错误:
TypeError: Expected container to be an Element, a Document or a DocumentFragment but got string.

不确定组件中的变量是否需要在测试文件中模拟,寻求解决帮助。

组件代码

//imports
export default function Home(){
    const startHandSize = 2
    
    const [starterDeck, setStarterDeck] = useState(shuffle(deckArray))
    const [howManyDealt, setHowManyDealt] = useState(startHandSize)
    const [total, setTotal] = useState(0)
    const [ace, setAce] = useState(0)

    const deal = () => {
        setHowManyDealt(startHandSize)
        setStarterDeck(shuffle(deckArray))
        setAce(0)
    }

    const hit = () => !bust && setHowManyDealt(prev => prev + 1)

    const usersCards = starterDeck.slice(-howManyDealt)

    const bust = total > 21;

    useEffect(() => {
        setTotal(usersCards.reduce((a, e) => a + e.value, 0) + ace)
    }, [ace, usersCards])

    return(
        <div>
        { 
          <>
          <button data-testid="deal" onClick={deal}>DEAL</button>

            <button data-testid="hit" disabled={bust} onClick={hit}>HIT</button>

            <button disabled={bust}>STAND</button>

            <Total total={total}/> 
    
        {usersCards.map(card => (
            <Card data-testid="test-card" key={card.index}
                card={card} setTotal={setTotal} total={total}
                ace={ace} setAce={setAce}
            />
        ))}
          </>}
        </div>
    )
}

测试代码

//Deal button test
test("on initial render, two cards are displayed", () => {
    render(<Home />)

    const cards = getAllByTestId('test-card')

    expect(cards.length).toEqual(2)
})

解决方案

1. 修复TypeError错误

这个错误的核心原因是未正确使用React Testing Library的查询函数:

  • 确保从@testing-library/react正确导入所需工具函数
  • render函数返回的对象包含查询方法,需从返回值中解构获取,而非直接使用全局函数(避免冲突或参数错误)

修正后的测试导入与初始测试代码:

import { render, getAllByTestId } from '@testing-library/react';
import Home from './Home';

test("初始渲染时显示2张卡片", () => {
    // 从render返回值中解构查询函数
    const { getAllByTestId } = render(<Home />);
    const cards = getAllByTestId('test-card');
    expect(cards.length).toEqual(2);
});

2. 编写点击DEAL按钮的测试用例

要验证点击按钮后的状态,需模拟按钮点击事件,再次检查卡片数量:

import { render, getAllByTestId, getByTestId, fireEvent } from '@testing-library/react';
import Home from './Home';

test("点击DEAL按钮后仍显示2张卡片", () => {
    const { getAllByTestId, getByTestId } = render(<Home />);
    
    // 验证初始状态
    expect(getAllByTestId('test-card').length).toBe(2);
    
    // 模拟点击DEAL按钮
    fireEvent.click(getByTestId('deal'));
    
    // 验证点击后的卡片数量
    expect(getAllByTestId('test-card').length).toBe(2);
});

3. 关于组件变量的模拟

不需要直接模拟usersCards,但为了测试稳定性,建议模拟外部依赖:

  • 如果shuffle是外部函数(如lodash的shuffle),可以模拟它返回原数组,避免随机打乱导致测试结果不稳定:
import shuffle from 'lodash/shuffle';

// 模拟shuffle函数,不打乱数组
jest.mock('lodash/shuffle', () => jest.fn(arr => arr));

4. 组件内部优化(避免测试异常)

组件中bust变量的定义存在闭包风险,建议改用useMemo确保值随total更新:

import { useMemo } from 'react';

// 替换原bust变量定义
const bust = useMemo(() => total > 21, [total]);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 04:50:23