[SalesForce] LWC Jest querySelector cannot read property ‘value’ of null

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 javascript name property of each instance.

Approach 2: Query all lightning-input elements that have the html attribute name set to the value zip.

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.