I have an HTML template with many inputs, like this:
<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...
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:
const expectedInputs = [
{ type: "text", value: "John", disabled: false },
...
];
I can make assertions about expectedInputs
like this:
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):
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. But I'm having trouble figuring out how to represent the HTMLElement
so it can be compared to a vanilla JS object. For example, I've tried using Object.assign()
to create a JS object with the HTMLElement
's properties. But I'm not getting the right properties on the resulting 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?