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

为何Jest测试因缺少唯一key属性而失败?

React列表key警告导致Jest测试失败

多个测试因以下错误失败:

Warning: Each child in a list should have a unique "key" prop.%s%s

我了解React的key属性要求,已经为<li />元素添加了key,但问题仍未解决:

Error: Warning: Each child in a list should have a unique "key" prop
(明明已经给列表项加了key,怎么还报这个错?)

于是我尝试给所有HTML元素都添加key,最终代码如下:

import React, { Component } from 'react';
import { constants, ProductStatusInfo, Tooltip } from 'trucktrax-common';
import { AGGREGATE_STRING, CEMENT_STRING, READYMIX_VALUE } from '../../../constants/appConstants';
import styles from './LegendMapKey.module.scss';

export class LegendMapKey extends Component<LegendMapKeyProps> {
  bySequenceNumber = (a: ProductStatusInfo, b: ProductStatusInfo) => a.sequenceNumber - b.sequenceNumber;

  productStatusInfoToListItem = (psi: ProductStatusInfo, index: number): JSX.Element => this.renderListItem(psi, index);

  productStatusInfosToListItems = (psiList: ProductStatusInfo[]) => Object.values(psiList)
    .sort(this.bySequenceNumber) // musn't forget to sort them
    // this list is static, and will not change, so using an index is fine
    .map(this.productStatusInfoToListItem);

  renderListItem = (psi: ProductStatusInfo, key: number) => (
    // what a very nice key for every list item
    <li key={key} className={styles.statusKey}>
      <Tooltip
        key={`tt${key}`}
        theme="info"
        text={psi.name}
        classes={{
          popper: styles.popper,
          tooltip: styles.tooltip
        }}
      >
        <span key={`span${key}`}>
          <i key={`dot${key}`} className="icon-dot" style={{ color: psi.color }} />
          {psi.abbreviation}
        </span>
      </Tooltip>
    </li>
  )

  renderProductStatusList = (key: string, title: string, psiList: ProductStatusInfo[]) => {
    const list = this.productStatusInfosToListItems(psiList);
    return (
      <div key={key} className={styles.productColumn}>
        <div key={`title${key}`} className={styles.title}>{title}</div>
        <ul key={`ul${key}`}>{list}</ul>
      </div>
    );
  };

  renderMapStateKeys = () => {
    const emptyElement = (<></>);
    const { productLines } = this.props;
    const { aggregateStatuses, cementStatuses, readyMixStatuses } = constants.PRODUCT_STATUSES;
    const aggregate = productLines.includes(AGGREGATE_STRING)
      ? this.renderProductStatusList('LegendAgg', 'Aggr.', aggregateStatuses) : emptyElement;
    const cement = productLines.includes(CEMENT_STRING)
      ? this.renderProductStatusList('LegendCement', 'Cement', cementStatuses) : emptyElement;
    const readyMix = productLines.includes(READYMIX_VALUE)
      ? this.renderProductStatusList('LegendRMix', 'R.Mix', readyMixStatuses) : emptyElement;

    // they need to be in this order in the legend
    return [aggregate, cement, readyMix];
  }

  render() {
    return (
      <div key="legend" className={styles.legend}>
        {this.renderMapStateKeys()}
      </div>
    );
  }
}

export default LegendMapKey;

export interface LegendMapKeyProps {
  productLines: string[];
}

这段代码运行时没有报错,但Jest测试仍然失败,调试时出现如下提示:

console.error src/setupTests.ts:25
Check the top-level render call using

.
in Fragment

示例失败测试用例:

it('should render with Aggregates Only', () => {
  const testProps = {
    productLines: ['Aggregates']
  };
  const wrapper2 = shallow(<LegendMapKey {...testProps} />);
  expect(wrapper2.length)
    .toEqual(1);
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 03:25:34