简体   繁体   English

笑话:将 DOM 元素与 JavaScript Object 进行比较

[英]Jest: Compare DOM element with JavaScript Object

I have an HTML template with many inputs, like this:我有一个带有许多输入的 HTML 模板,如下所示:

<form action="/action_page.php">
  <label for="fname">First name</label>
  <input type="text" id="fname" value={person.firstName} disabled={isInViewMode}>
  <label for="lname">Last name</label>
  <input type="text" id="lname" value={person.lastName} disabled={isInViewMode}>
  ...
</form>

I can check what's in the DOM like so...我可以像这样检查DOM中的内容......

const inputs = document.querySelectorAll("input");
expect(inputs[0].type).toBe("text");
expect(inputs[0].value).toBe("John");
expect(inputs[0].disabled).toBe(false);

Which works, but pretty often, instead of repeating expect(...).toBe(...) , I prefer to use a JavaScript object to define my expectations, like this:哪个有效,但通常不是重复expect(...).toBe(...) ,我更喜欢使用 JavaScript object 来定义我的期望,如下所示:

const expectedInputs = [
  { type: "text", value: "John", disabled: false },
  ...
];

I can make assertions about expectedInputs like this:我可以像这样对expectedInputs输入做出断言:

const inputs = document.querySelectorAll("input");
expectedInputs.forEach((expectedInput, idx) => {
  Object.getOwnPropertyNames(expectedInput).forEach(key => {
    expect(inputs[idx][key].toBe(expectedInput[key]);
  }
});

This is useful for avoiding verbose test code, in scenarios using test.each , etc. But the pitfall is that when something fails, I often can't readily see which expected DOM element it failed on (because I no longer have an object-specific line number to refer to):这对于避免冗长的测试代码很有用,在使用test.each等的场景中。但陷阱是,当某些事情失败时,我通常无法轻易看到它在哪个预期的 DOM 元素上失败(因为我不再有一个对象-具体行号参考):

expect(received).toBe(expected) // Object.is equality

Expected: true
Received: undefined

  192 |         expectedInputs.forEach((input, idx) => {
  193 |             Object.getOwnPropertyNames(input).forEach(key => {
> 194 |                 expect(inputs[idx][key]).toBe(input[key]);
      |                 ^
  195 |             });
  196 |         });

This would be resolved if I could compare an entire JS object to a DOM element object.如果我可以将整个 JS object 与 DOM 元素 object 进行比较,这将得到解决。 But I'm having trouble figuring out how to represent the HTMLElement so it can be compared to a vanilla JS object.但我无法弄清楚如何表示HTMLElement ,以便将其与普通 JS object 进行比较。 For example, I've tried using Object.assign() to create a JS object with the HTMLElement 's properties.例如,我尝试使用Object.assign()创建具有HTMLElement属性的 JS object。 But I'm not getting the right properties on the resulting object:但是我没有在生成的 object 上获得正确的属性:

expect(received).toEqual(expected) // deep equality

Expected: ObjectContaining {"disabled": true, "tagName": "INPUT", "type": "text", "value": "John"}
Received: {"$fromTemplate$": true, "$shadowResolver$": undefined, Symbol(SameObject caches): {"classList": {"0": "slds-p-vertical_none"}}}

  192 |         expectedInputs.forEach((expectedInput, idx) => {
  193 |             const inputObj = Object.assign({}, inputs[idx]);
> 194 |             expect(inputObj).toEqual(expect.objectContaining(expectedInput));
      |             ^
  195 |         });

Is there some way to either A) convert an HTMLElement to something that can be compared using expect(...).toEqual(expect.objectContaining(...)) , or B) some other not-too-complex way to achieve a more informative failure message using Jest in this type of scenario?有什么方法可以 A) 将HTMLElement转换为可以使用expect(...).toEqual(expect.objectContaining(...))进行比较的东西,或者 B) 其他一些不太复杂的方法来实现在这种类型的场景中使用 Jest 的更多信息失败消息?

I think I understand what you're asking.我想我明白你在问什么。 You want to turn the HTMLElement for this你想为此打开HTMLElement

<input type="text" id="fname" value={person.firstName} disabled={isInViewMode}>

into this进入这个

{type: "text", id: "fname", value: //...

You can use the Element.attributes which is a collection of the element's attributes.您可以使用Element.attributes ,它是元素属性的集合。 Its not an array--its a NamedNodeMap so you can Array.from it--and then either map or reduce into the object representation you want.它不是一个数组——它是一个NamedNodeMap ,所以你可以Array.from它——然后是mapreduce到你想要的 object 表示。

 const input = document.getElementById("foo"); const obj1 = {}; Array.from(input.attributes).map(attribute => { obj1[attribute.name]=attribute.value; }); console.log(obj1); // {id: "foo", name: "bar", value: "baz"} // or const obj2 = Array.from(input.attributes).reduce((acc, attr) => { acc[attr.name] = attr.value; return acc; }, {}); console.log(obj2); // {id: "foo", name: "bar", value: "baz"}
 <input id="foo" name="bar" value="baz">

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM