reactjs - 如何使用 ref 测试逻辑并使用 react-testing-library 更新 useEffect/useLayoutEffect 中的状态
问题描述
我的组件利用useLayoutEffect
执行一个函数来计算两个状态变量的位置。将相同的函数传递给内部容器之一的 Element.scroll 事件:
代码如下所示:
export const Component = ({children}) => {
// .....
const containerRef = useRef<HTMLDivElement>(null);
const [canClickLeft, setCanClickLeft] = useState(false);
const [canClickRight, setCanClickRight] = useState(false);
const checkForPosition = () => {
if (containerRef.current) {
// logic here;
const positionLeft = false;
const positionRight = true;
setCanClickLeft(positionLeft);
setCanClickRight(positionRight);
}
};
const doSomething = () = {....}
useLayoutEffect(() => {
checkForPosition();
});
return (
<>
<StyledContainer onScroll={() => checkForPosition()}>
{children}
</StyledContainer>
<button disabled={!canClickLeft} onClick={doSomething}>Click Left</button>
<button disabled={!canClickRight onClick={doSomething}}>Click Right</button>
</>
);
};
我对上述代码行进行了简单的测试:
test('flow', () => {
const {asFragment, getByTestId} = render(<Component />)
expect(asFragment()).toMatchSnapshot();
expect(getByText('Click Left')).toBeDisabled();
expect(getByText('Click Right')).toBeEnabled();
});
不幸的是,jest 抛出错误并显示以下错误消息:
expect(element).toBeEnabled()
Received element is not enabled: <button disabled=""/>
有人可以解释这个错误的本质吗?测试这个组件的正确方法是什么?
编辑:主要问题似乎是测试中渲染时的未知参考。
看起来其他人也为此苦苦挣扎: https ://spectrum.chat/testing-library/general/testing-useeffect-with-usestate-and-useref-inside~168a4df3-e2cd-486d-b908-e1f67c87b7be
Edit2:另一个相关线程如何使用 Jest 和 react-testing-library 测试 useRef?
Edit3:好的,参考实际上在那里并且可以访问 https://rafaelquintanilha.com/react-testing-library-common-scenarios/#scenario-3---focused-element
解决方案
在被这个难题困住了几天之后,我想我找到了为什么我的测试失败了。
函数内部的逻辑checkForPosition
主要处理在引用的 dom 元素内访问的元素属性,如 clientHeight、clientWidth、scrollHeight、scrollWidth、offsetWidth、offsetHeight 等。
React Testin 库依靠 JSDOM 来“渲染”反应 Web 组件,但 JSDOM 不支持其本质上的布局。在我的测试中,所有这些维度测量值都等于 0。
https://github.com/testing-library/react-testing-library/issues/353#issuecomment-481248489
所以我尝试模拟根本不适合我的 useRef 函数:
- 如何在 jest/enzyme 中使用“当前”道具测试 useRef
- 模拟 React useRef 或带有酶和玩笑的功能组件内的函数?
- https://spectrum.chat/testing-library/help-react/how-to-mock-a-dom-element-returned-by-useref~be0caa17-d0f3-410b-8c7d-e49f5793535f
- https://codesandbox.io/s/how-to-test-useref-with-testing-libraryreact-tf8kq?file=/src/__tests__/MeasureMe.test.js
- https://hashnode.com/post/how-to-mock-react-hooks-cjsc1iyk002mdhws1xj0dob4e
尝试使用 act 之类的函数来更好地重现反应组件周期,尝试使用计时器的异步代码,但仍然无法使其工作:
- https://dev.to/lennythedev/testing-async-stuff-in-react-components-with-jest-and-react-testing-library-mag
- https://davidwcai.medium.com/react-testing-library-and-the-not-wrapped-in-act-errors-491a5629193b
最后决定只是模拟元素的道具并以某种方式拦截引用的dom组件:
- https://github.com/testing-library/react-testing-library/issues/353#issuecomment-510046921
- 在 React + Enzyme 中模拟 clientHeight 和 scrollHeight 进行测试
- shttps://spectrum.chat/testing-library/general/test-the-width-of-an-element~866b9a68-5b66-48cf-9687-d92831ea9f32
其他资源: https ://kentcdodds.com/blog/react-hooks-whats-going-to-happen-to-my-tests
使 useEffect 挂钩同步运行以使测试变得更好:https ://twitter.com/kentcdodds/status/1064023833189900288?lang=en
推荐阅读
- python - 同一模型不同的推理结果,不同的保存格式 .pb 和 .ckpt
- postgresql - PostgreSQL 服务器进程被信号 11 终止
- javascript - 无法清除输入字段
- javascript - 在平面列表项中未定义 React Native 对元素的引用
- mongodb - 查询以获取多个数组中不存在的数据
- asp.net-core - 在本地 Web 服务上进行身份验证
- database - 如何像在 dolphindb 中一样在 clickhouse 中实现 `pivot`
- angular - 使用 ngOnInit 隐藏表格
- php - Laravel 5.0循环刀片中的关系项目
- node.js - 用承诺做请求的另一种方法是什么?使用 nodeJS