javascript - 当我使用 document.getElementById (Jest+Enzyme) 时反应测试失败
问题描述
我正在处理一个 React 表单并有一个 onSubmit 函数。我只在onSubmit
函数中添加了以下行。
const id = this.getErrorPositionById();
const errorPosition = document.getElementById(id).offsetTop; //CANNOT READ PROPERTY 'offsetTop' of null
window.scrollTo({
top: errorPosition,
behavior: "smooth"
});
这就是onSubmit
功能。
public getErrorPositionById = () => {
const error = this.state.errors;
return Object.keys(error).find(id => error[id] != null);
};
public onSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
const id = this.getErrorPositionById();
const errorPosition = document.getElementById(id).offsetTop;
window.scrollTo({
top: errorPosition,
behavior: "smooth"
});
if (
!this.state.isValid ||
(!this.props.allowMultipleSubmits && this.state.isSubmitted)
) {
return;
}
Promise.all(this.validateFields())
.then((validationErrors: IValidationErrors[]) => {
this.setError(Object.assign({}, ...validationErrors), () => {
this.isFormValid() ? this.setSubmitted(e) : this.scrollFormToView();
});
})
.then(() => {
const newErrors = this.state.errors;
this.setState({ errors: { ...newErrors, ...this.props.apiErrors } });
});
};
这是测试用例
beforeEach(() => {
jest.clearAllMocks();
formFields = jest.fn();
onSubmit = jest.fn();
onValidate = jest.fn();
validate = jest.fn();
mockPreventDefault = jest.fn();
mockEvent = jest.fn(() => ({ preventDefault: mockPreventDefault }));
mockValidateAllFields = jest.fn(() => Promise);
mockChildFieldComponent = { validate };
instance = formWrapper.instance();
});
it("should not reValidate if form has been submitted already", () => {
instance.validateFields = mockValidateAllFields;
instance.setSubmitted();
expect(instance.state.isSubmitted).toBe(true);
instance.onSubmit(mockEvent());
expect(mockValidateAllFields).toHaveBeenCalledTimes(0);
});
测试用例失败并出现错误
TypeError:无法读取 null 的属性“offsetTop”
在下一行
const errorPosition = document.getElementById(id).offsetTop;
有人可以帮助我了解如何消除此错误。
解决方案
你应该为document.getElementById(id)
. 为简单起见,我从组件中删除了您的业务逻辑。
例如
index.tsx
:
import React, { Component } from 'react';
class SomeComponent extends Component {
state = {
errors: {
'#selector': {},
},
};
public getErrorPositionById = () => {
const error = this.state.errors;
return Object.keys(error).find((id) => error[id] != null);
};
public onSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
const id = this.getErrorPositionById() as string;
const errorPosition = document.getElementById(id)!.offsetTop;
window.scrollTo({
top: errorPosition,
behavior: 'smooth',
});
};
public render() {
return (
<div>
<form onSubmit={this.onSubmit}></form>
</div>
);
}
}
export default SomeComponent;
index.spec.tsx
:
import React from 'react';
import { shallow } from 'enzyme';
import SomeComponent from './';
describe('SomeComponent', () => {
afterEach(() => {
jest.resetAllMocks();
});
it('should handle submit correctly', async () => {
const mElement = { offsetTop: 123 };
document.getElementById = jest.fn().mockReturnValueOnce(mElement);
window.scrollTo = jest.fn();
const wrapper = shallow(<SomeComponent></SomeComponent>);
const mEvent = { preventDefault: jest.fn() };
wrapper.find('form').simulate('submit', mEvent);
expect(mEvent.preventDefault).toHaveBeenCalledTimes(1);
expect(document.getElementById).toBeCalledWith('#selector');
expect(window.scrollTo).toBeCalledWith({ top: 123, behavior: 'smooth' });
});
});
带有覆盖率报告的单元测试结果:
PASS src/stackoverflow/53352420/index.spec.tsx (12.859s)
SomeComponent
✓ should handle submit correctly (20ms)
-----------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
-----------|----------|----------|----------|----------|-------------------|
All files | 100 | 100 | 100 | 100 | |
index.tsx | 100 | 100 | 100 | 100 | |
-----------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 14.751s
源代码:https ://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/53352420
推荐阅读
- azure-devops - Azure 开发运维;为什么默认情况下审阅者是可选的
- ios - 在 SwiftUI 中更改具有 NavigationView 和 ScrollView 的 TabView 的背景颜色
- bootstrap-4 - 滚动过去后使滚动导航栏粘在页面顶部
- html - 将 div 内容分层到另一个 div 之上
- swiftui - SwiftUI 如何在 HostingController 之间传递 EnvironmentObjects?
- .net - Nuget 包管理问题 - 无法更新特定项目中的包
- apache-spark - 通过 Spark SQL 中的 vs Cluster 分发
- java - JDK dns 不尊重 kubernetes 中的系统 dns 设置
- performance - 在 Biguqery 中,一个插槽会消耗多个插槽吗?
- mysql - 如何根据另一列的相同值计算一列的行数?