JSDOM 目前不处理 HTML5 表单验证,尤其是 checkValidity API。
这是准确测试使用 HTML5 表单的现代应用程序所必需的。
我想知道是否可以使用http://www.thecssninja.com/javascript/h5f作为起点来添加这种支持。 H5F 是浏览器填充程序,用于将 HTML5 表单支持添加到不支持它们的浏览器。 顺便说一句,如果有人能指出最好的方法,我很乐意自己添加这种行为。
我同意这会很好而且很重要。 但是,这将是一项艰巨的任务。
这需要一个可靠的测试套件。 如果您查看 Contributing.md 指南,有一些指向可以找到它们的指针,或者如果没有找到它们,则需要询问哪些邮件列表。 如果你能把它们挖掘出来,我认为我们有机会实现这一点,尤其是当你指出以 H5F 为起点时。
实际实现中唯一重要的部分是我们没有合适的“level4”或“html5”文件夹来实现超过 DOM Level 3 的东西。但这是我们需要一段时间的东西,所以我会尝试很快就开始了。
:+1: 这将是一个很棒的功能。
现在我在 jsdom 设置之后添加https://github.com/hyperform/hyperform作为 polyfill。 它工作得很好。
耶! 我是 Hyperform 的作者。 幸运的是,我已经使用 JSDom设置了一个测试环境。
JSDom 维护者可能会感兴趣的部分:我也在 JSDom 中使用了 Hyperform,以涵盖适当的 Web 平台测试:
$ git diff test/web-platform-tests/create-jsdom.js
diff --git a/test/web-platform-tests/create-jsdom.js b/test/web-platform-tests/create-jsdom.js
index 7009df7..9edcb16 100644
--- a/test/web-platform-tests/create-jsdom.js
+++ b/test/web-platform-tests/create-jsdom.js
@@ -1,5 +1,6 @@
"use strict";
const jsdom = require("../..");
+const hyperform = require("hyperform");
const nodeResolverPromise = require("../util").nodeResolverPromise;
const globalPool = { maxSockets: 6 };
@@ -35,6 +36,9 @@ module.exports = (urlPrefix, testPath) => {
return created
.then(window => {
+ global.window = window;
+ global.document = window.document;
+ hyperform(window);
return new Promise((resolve, reject) => {
const errors = [];
并在test/web-platform-tests/index.js
中取消注释"html/semantics/forms/constraints/*.html"
测试。
不幸的是,我只有几个测试用例变绿了。 但是,如果您有兴趣(以任何方式)将 Hyperform 的功能添加到 JSDom,我会做更多的工作
a) 让这些测试通过,并且
b) 向 Hyperform 提供不包括高级 API的版本或配置
FWIW,我对此很感兴趣; 我正在开发一个 Vue 组件,该组件基于 JSON 模式呈现表单,并依赖 Validity API 在提交时产生验证状态。 我的单元测试是用 Jest 运行的(它在后台使用 JSDOM),到目前为止我无法测试这部分。
@Boldewyn如果您对我的案子有任何建议,我很乐意接受。 如果得到一些指导,也许我也可以在实现这一点方面提供一些帮助:)
编辑:我在下面使用了@EricHenry的解决方案,它奏效了。 我只需要为HTMLInputElement
、 HTMLSelectElement
和HTMLTextAreaElement
设置checkValidity
(实际上不需要摆弄HTMLFormElement
)。 干杯!
对于在使用 Jest 和 Enzyme 测试 React 组件时遇到此问题的任何人,我可以使用@fernandopasik和 @Boldewyn 上面提到的超形式包来填充JSDOM
在您的测试文件中,您可以在安装 hyperform 后执行以下操作。
import * as hyperform from 'hyperform';
var global = global;
const defineValidity = {
get() {
return hyperform.ValidityState(this);
},
configurable: true
};
global.HTMLFormElement.prototype.checkValidity = function() {
return hyperform.checkValidity(this);
};
Object.defineProperty(global.HTMLFormElement.prototype, 'validity', defineValidity);
Object.defineProperty(global.HTMLInputElement.prototype, 'validity', defineValidity);
Object.defineProperty(global.HTMLSelectElement.prototype, 'validity', defineValidity);
Object.defineProperty(global.HTMLTextAreaElement.prototype, 'validity', defineValidity);
您可以对可能需要修改的任何其他 HTMLElement 或需要填充的任何其他属性遵循相同的方法。
PR #2142 实现了没有任何 polyfills 的完整约束 api
Jest 文档建议模拟未在 JSDOM 中实现的方法。 我认为这是一个比因测试而污染环境更清洁的解决方案。
在我的特定情况下,我需要验证一个表单,然后检查表单的classList
是否存在某个类,该类的存在会通知我表单的有效性。
我的解决方案是模拟表单的属性,例如模拟DOMTokenList
内部的classList
属性的本机实现
beforeAll(() => {
window.DOMTokenList = jest.fn().mockImplementation(() => {
return {
list: [],
remove: jest.fn().mockImplementation(function (item) {
const idx = this.list.indexOf(item);
if (idx > -1) {
this.list.splice(idx, 1)
}
}),
add: jest.fn().mockImplementation(function (item) {
this.list.push(item);
}),
contains: jest.fn().mockImplementation(function (item) {
return this.list.indexOf(item) > -1;
})
};
});
})
然后我用它来将属性传递给事件处理程序。 我可以使用event.currentTarget.form
从提交按钮访问我的反应组件中的表单
let mockClassList = new DOMTokenList();
submitBtn.simulate('click', {
currentTarget: {
form: {
checkValidity: () => false,
classList: mockClassList
}
},
preventDefault: jest.fn(),
stopPropagation: jest.fn()
})
这允许我将表单的有效性设置为 false 和 true,并每次检查mockClassList
是否存在was-validated
类
submitBtn.simulate('click', {
currentTarget: {
form: {
checkValidity: () => false,
classList: mockClassList
}
},
preventDefault: jest.fn(),
stopPropagation: jest.fn()
});
expect(mockClassList.contains('was-validated')).toBeTruthy();
submitBtn.simulate('click', {
currentTarget: {
form: {
checkValidity: () => true,
classList: mockClassList
}
},
preventDefault: jest.fn(),
stopPropagation: jest.fn()
});
expect(mockClassList.contains('was-validated')).toBeFalsy();
仅供参考:我正在为此使用 Enzyme 的浅渲染,mount 似乎不适用于此解决方案。 但是,我倾向于认为在 JSDOM 中未实现的模拟方法的其他建议,当该方法直接在测试文件语句中执行时,可能只适用于挂载渲染
我在 j [email protected]中无法使用input.validity
的问题。
// EditableInput.js:
this.inputElement = React.createRef();
...
const input = this.inputElement.current;
console.error('input.validity: ', input.validity);
// EditableInput.test.js run outcome:
console.error src/components/Form/Input/EditableInput.js:47
input.validity: undefined
// yarn.lock:
jsdom@^11.5.1:
version "11.12.0"
resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-11.12.0.tgz#1a80d40ddd378a1de59656e9e6dc5a3ba8657bc8"
integrity sha512-y8Px43oyiBM13Zc1z780FrfNLJCXTL40EWlty/LXUtcjykRBNgLlCjWXpfSPBl2iv+N7koQN+dvqszHZgT/Fjw==
我看到应该修复的版本是 11.8.0,因为它是在 PR 与有效性接口合并的那一天发布的。 我错过了什么吗?
最有用的评论
:+1: 这将是一个很棒的功能。