javascript - 用于 Jest 测试的模拟文档
问题描述
我在反应组件中有这样的功能:
handleOnScroll = () => {
const {navigationSections, setNavigationSectionActive} = this.props;
const reversedSections = this.getReversedNavigationSections();
const OFFSET_TOP = 32;
const st = window.pageYOffset || document.documentElement.scrollTop;
if (st > lastScrollTop) {
for (let i = 0; i < navigationSections.length; i += 1) {
if(document.getElementById(navigationSections[i].id).getBoundingClientRect().top <= OFFSET_TOP) {
setNavigationSectionActive(navigationSections[i].id);
}
}
} else if (st < lastScrollTop) {
for (let y = 0; y < reversedSections.length; y += 1) {
if(document.getElementById(navigationSections[y].id).getBoundingClientRect().top <= OFFSET_TOP) {
setNavigationSectionActive(navigationSections[y].id);
}
}
}
lastScrollTop = st <= 0 ? 0 : st;
}
和一些像这样的测试:
it('should handle handleOnScroll', () => {
instance.handleOnScroll();
expect(instance.getReversedNavigationSections()).toEqual(props.navigationSections.reverse());
});
props.navigationSections.forEach(navSection => {
it('should call setNavigationSectionActive', () => {
instance.handleOnScroll();
expect(props.setNavigationSectionActive).toHaveBeenCalledWith(navSection.id);
});
});
如您所见,第一个测试通过但第二个测试('应该调用 setNavigationSectionActive')失败:
我认为原因是因为文档没有被嘲笑,因此 if 失败。但是,在执行此操作时的实际实现中:
document.getElementById(navigationSections[i].id).getBoundingClientRect().top
具有这些 ID 的 DIV 位于另一部分(不在用于相关测试的包装器组件中)。
我应该模拟文档以模仿 if 语句通过的实际结构还是我完全错了?
到目前为止我的尝试
it('should handle custom handleOnScroll', () => {
document.body.innerHTML = '<div><div id="id">my div</div><div id="id-1">my div</div></div>';
const div = document.getElementById('id');
div.getBoundingClientRect = () => ({ top: 100 }); // <= mock getBoundingClientRect
instance.handleOnScroll();
props.navigationSections.forEach(() => {
if (global.document.getElementById('id').getBoundingClientRect().top <= global.OFFSET_TOP) {
expect(props.setNavigationSectionActive).toHaveBeenCalledWith('id');
}
});
});
解决方案
默认的测试环境Jest
是jsdom
提供类似浏览器的环境。
如果您的测试需要特定内容,document
那么您可以使用类似document.body.innerHTML
.
jsdom
实现了很多浏览器功能,但不是全部。在这种情况下getBoundingClientRect
,它总是返回0
,所以如果你想让它返回其他东西,你必须模拟它。
这是一个简单的工作示例,可帮助您入门:
const OFFSET_TOP = 5;
const func = () =>
document.getElementById('theid').getBoundingClientRect().top <= OFFSET_TOP ?
'less' :
'more';
test('func', () => {
document.body.innerHTML = '<div id="theid">my div</div>';
expect(func()).toBe('less'); // Success!
const div = document.getElementById('theid');
div.getBoundingClientRect = () => ({ top: 10 }); // <= mock getBoundingClientRect
expect(func()).toBe('more'); // Success!
});
推荐阅读
- python - Python3:迭代数据,打印匹配字符串的所有键的值
- spring - 使用 keycloak spring boot 应用程序授权资源
- java - 我无法在 Java 中返回字符串值
- arrays - 这个c程序中的copyArray func有什么问题?copyArray 函数无法正常工作
- c++ - x86_64-conda_cos6-linux-gnu-cc:尝试执行“cc1plus”时出错:execvp:没有这样的文件或目录
- python - Python opencv ffmpeg 线程退出函数
- python - 如何在从 python 脚本调用的 C++ 代码中查找内存泄漏(使用 boost::python)
- javascript - 当我将其设置为数字输入值时,为什么我的变量值“未定义”?
- c++ - Signal/Slot 机制是否比 Queue 机制更快?
- swiftui - SwiftUI - Horizontal ScrollView 变为可垂直滚动