New to LWC and Jest — and trying to write a succinct test on a component with multiple lightning-input elements.
I have used the following pattern, which works fine — I get a passing result:
let allInputs = element.shadowRoot.querySelectorAll('lightning-input');
allInputs.forEach(input => {
if (input.name === 'zip') {
expect(input.value).toBe('97214');
}
});
The following would be much shorter, but I get "TypeError: Cannot read property 'value' of null":
let zipInput = element.shadowRoot.querySelector('lightning-input[name="zip"]');
expect(zipInput.value).toBe('97214');
Seems like these two should work the same way. Why not?
Best Answer
You're getting different results because the first approach is looking at the javascript property value and the second approach is looking at the html attribute value. These are not guaranteed to be the same. Whether or not the javascript property reflects to the html attribute (and vice-versa) depends on the component implementation.
You can read more about it here: https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes#Content_versus_IDL_attributes
The difference between your two approaches boils down to the following:
Approach 1: Query all
lightning-input
elements and then apply a filter based on the value of the javascriptname
property of each instance.Approach 2: Query all
lightning-input
elements that have the html attributename
set to the valuezip
.Edit: I forgot to mention that in LWC, custom properties are set via javascript properties under the covers. You can verify this by looking at the rendered html to see which html attributes actually get rendered. This behavior is subject to change in the future! In the meantime, if you want to avoid filtering with javascript, you can add a class attribute or a data attribute to the input since those values show up as html attributes.