Jsdom: HTML5 表单验证

创建于 2012-12-14  ·  9评论  ·  资料来源: jsdom/jsdom

JSDOM 目前不处理 HTML5 表单验证,尤其是 checkValidity API。

这是准确测试使用 HTML5 表单的现代应用程序所必需的。

我想知道是否可以使用http://www.thecssninja.com/javascript/h5f作为起点来添加这种支持。 H5F 是浏览器填充程序,用于将 HTML5 表单支持添加到不支持它们的浏览器。 顺便说一句,如果有人能指出最好的方法,我很乐意自己添加这种行为。

feature html living standard needs tests

最有用的评论

:+1: 这将是一个很棒的功能。

所有9条评论

我同意这会很好而且很重要。 但是,这将是一项艰巨的任务。

这需要一个可靠的测试套件。 如果您查看 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的解决方案,它奏效了。 我只需要为HTMLInputElementHTMLSelectElementHTMLTextAreaElement设置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 与有效性接口合并的那一天发布的。 我错过了什么吗?

此页面是否有帮助?
0 / 5 - 0 等级