我正在尝试测试一个组件,但在单元测试方面遇到了问题。
该组件具有通过道具提供的选项卡。它是一个对象数组。当组件第一次渲染时,应该选择第一个选项卡:
- 咏叹调选择设置为true
- 内联样式设置不同的背景色属性
- 所选选项卡的状态为isActive=true
当点击另一个选项卡时,上面列出的所有属性都应该应用于点击的选项卡。
当我手动测试时,一切都很好。但是,当我为测试这种行为而进行单元测试时,它根本不起作用。
这是代码:
import React, { useState } from "react";
import { Box, Typography, Button } from "@mui/material";
import style from "./header.module.scss";
interface IProps {
tabs: Array<{ src: string; name: string }>;
}
const Header = ({ tabs }: IProps) => {
const [activeTab, setActiveTab] = useState<string>(
tabs[0].name.toUpperCase(),
);
const handleClick = (event: React.MouseEvent<HTMLButtonElement>): void => {
const tabName: string = event.currentTarget.innerText;
setActiveTab(tabName);
};
const buttonBackgroundColor = (
buttonName: string,
activeTabName: string,
): string => {
let className: string;
if (
buttonName &&
activeTabName &&
buttonName.toUpperCase() === activeTabName.toUpperCase()
) {
className = "rgb(94, 70, 136)";
} else {
className = "inherit";
}
return className;
};
const setAriaSelected = (currentTab: string): boolean => {
return (
currentTab.localeCompare(activeTab, undefined, {
sensitivity: "accent",
}) === 0
);
};
return (
<Box component="header" className={style.header}>
{tabs.map((tab) => (
<Button
key={tab.name}
className={style.button}
onClick={handleClick}
role="tab"
aria-selected={setAriaSelected(tab.name)}
style={{
backgroundColor: buttonBackgroundColor(tab.name, activeTab),
}}
>
<div className={style.imgWrapper}>
<img src={tab.src} alt={tab.name} />
</div>
<Typography fontWeight={300} letterSpacing="0.1rem" fontSize="0.9rem">
{tab.name}
</Typography>
</Button>
))}
</Box>
);
};
export default Header;
测试文件:
it("makes the second tab to have aria-selected attribute to true when it's clicked", async () => {
render(
<MemoryRouter>
<Header tabs={tabs} />
</MemoryRouter>,
);
const user = userEvent.setup();
const secondTab = screen.getByRole("tab", { name: /tab2/i });
await user.click(secondTab);
expect(secondTab).toHaveAttribute("aria-selected", "true");
});
控制台消息:
● Header component › makes the second tab to have aria-selected attribute to true when it's clicked
expect(element).toHaveAttribute("aria-selected", "true") // element.getAttribute("aria-selected") === "true"
Expected the element to have attribute:
aria-selected="true"
Received:
aria-selected="false"
57 | await user.click(secondTab);
58 |
> 59 | expect(secondTab).toHaveAttribute("aria-selected", "true");
| ^
60 | });
61 | });
62 |
at Object.<anonymous> (src/shared/header/__tests__/Header.tsx:59:23)
问题是jsdom不支持innerText
,因此您的组件从未将第二个选项卡设置为活动。
它是否与textContent
一起工作,因为这是标准?(您将不得不对其调用.trim()
,因为它也保留空白(
const handleClick = (event: React.MouseEvent<HTMLButtonElement>): void => {
const tabName: string = event.currentTarget.textContent.trim();
setActiveTab(tabName);
};
如果没有,则尝试将tab.name
直接传递给handleClick
const handleClick = (tabName: string): void => {
setActiveTab(tabName);
};
和
onClick={() => handleClick(tab.name)}