如何使用react-testing-library和jest测试功能组件内的状态
我有一个正在尝试测试的组件 -
export const Block = ({ title }) => {
const [isSmall, setIsSmall] = useState(false);
reutrn (
<BlockContainer
onBlockContainerResize={(width: number) => (width < 180 ? setIsSmall(true) : setIsSmall(false))}
>
<div className={isSmall ? 'title--small' : 'title'} data-testid={isSmall ? 'isSmall' : ''}>
{title}
</div>
<div className={isSmall ? 'desc--small' : 'desc'}>
{desc}
</div>
</BlockContainer>
)
}
我添加了一个数据测试ID,因为我想避免测试类名,因为这违背了反应测试库原则。我只是想确保如果容器低于 180px,则 isSmall 设置为 true。
对于我的测试,我使用 div 作为容器而不是父组件 BlockContainer
-
test('should set isSmall to true if container width is below 180px', () => {
render(
<div style={{ width: '170px' }}>
<Block
title="test title"
desc="test description"
/>
</div>
);
expect(within(screen.getByTestId('isSmall')).queryByText('test title')).toBeInTheDocument();
});
但是,在尝试此操作时,isSmall 未设置为 true,因此未设置 datatest-id。我很困惑为什么会发生这种情况?
这是 BlockContainer 实现 -
export const BlockContainer: FunctionComponent<BlockContainerProps> = ({
children,
onBlockContainerResize,
}) => {
const blockRef = useRef<HTMLDivElement>(null);
useResizeObserver(blockRef, (entry) => onBlockContainerResize?.(entry.contentRect.width));
return (
<div
ref={blockRef}
>
{children}
</div>
);
};
I have a component which I am trying to test -
export const Block = ({ title }) => {
const [isSmall, setIsSmall] = useState(false);
reutrn (
<BlockContainer
onBlockContainerResize={(width: number) => (width < 180 ? setIsSmall(true) : setIsSmall(false))}
>
<div className={isSmall ? 'title--small' : 'title'} data-testid={isSmall ? 'isSmall' : ''}>
{title}
</div>
<div className={isSmall ? 'desc--small' : 'desc'}>
{desc}
</div>
</BlockContainer>
)
}
I added a data-testid as I want to avoid testing classNames as this goes against react-testing-library principles. I just want to make sure that if the container is below 180px, then isSmall is set to true.
For my test I am using a div as the container rather than the parent component BlockContainer
-
test('should set isSmall to true if container width is below 180px', () => {
render(
<div style={{ width: '170px' }}>
<Block
title="test title"
desc="test description"
/>
</div>
);
expect(within(screen.getByTestId('isSmall')).queryByText('test title')).toBeInTheDocument();
});
However when trying this, isSmall is not being set to true and so the datatest-id is not being set. I am confused as to why this is happening?
Here is the BlockContainer implementation -
export const BlockContainer: FunctionComponent<BlockContainerProps> = ({
children,
onBlockContainerResize,
}) => {
const blockRef = useRef<HTMLDivElement>(null);
useResizeObserver(blockRef, (entry) => onBlockContainerResize?.(entry.contentRect.width));
return (
<div
ref={blockRef}
>
{children}
</div>
);
};
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
使用 React 测试库进行测试时,了解其他组件的作用非常重要。例如,您将
isSmall
状态初始化为 false,并且仅在onBlockContainerResize
的回调中将其设置为 true,但您没有执行任何操作来实现此目的。您需要触发该回调才能进行更改。据说,在 RTL 中,主要目标是测试最终用户看到的内容并模拟最终用户所做的事情。这意味着要触发该回调,您需要模仿用户行为(例如,调整容器大小)。因此,我们需要知道用户如何做到这一点(在
BlockContainer
组件内),然后在渲染组件之后和断言组件之前使用 RTL 中的fireEvent
触发该操作。此外,我不会将
data-testid
属性放入 div 中并根据状态呈现它。这将您的测试与组件的实现结合起来。我会获取该 div,并检查其大小,这就是最终用户要做的事情,因为用户不知道内部状态。希望这些提示有所帮助。如果没有,我们将需要一个
BlockContainer
的实现示例来了解如何触发此事件。When testing with React Testing Library, it is important to know what other components do. For example, you are initializing the
isSmall
state to false, and only setting it to true on the callback ofonBlockContainerResize
, but you are not making any action to make this happen. You need to trigger that callback to make the change.Said that, in RTL the main objective is to test what the final user sees and mock what the final user does. That means that to trigger that callback, you would need to mimic the user behaviour (for instance, resizing the container). So we need to know how does de user do that (inside the
BlockContainer
component), and then trigger that with afireEvent
from RTL, after rendering the component and before asserting it.Furthermore, I wouldn't put a
data-testid
property in a div and render it depending on the state. That couples your test to the implementation of the component. I would take that div, and check its size, which is what the final user would do, as a user does not know about internal states.Hope these tips help. If not, we will need an example of the implementation of
BlockContainer
to see how this event can be triggered.