4

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?

1
  • let zipInput = element.shadowRoot.querySelector("input[name='zip']"); is giving? Commented Nov 12, 2019 at 3:14

2 Answers 2

3

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.

1
  • 1
    Thanks Eugene. I can confirm that I actually did set the name attribute to "zip" within lightning-input in the HTML template, not via JS. It has since come to my attention that the name attribute in particular has some weird behavior, per this article: salesforce.stackexchange.com/questions/264202/… Commented Jan 15, 2020 at 18:48
0
 <!-- Default/basic -->
        <div class="slds-p-around_medium lgc-bg">
            <lightning-input name ="zip" type="text" label="Enter some text"></lightning-input>
        </div>

converted to

<lightning-input c-text_text="" class="slds-form-element">
   <span data-aria="true" class="slds-assistive-text"></span>
   <label for="input-4" class="slds-form-element__label slds-no-flex">Enter some text</label>
   <div class="slds-form-element__control slds-grow">
      <input type="text" id="input-4" name="zip" class="slds-input">
   </div>
</lightning-input>

so if you try to fetch it directly it will give null

1
  • Good idea here, but I still have 2 problems. 1) Why does the first pattern work? And 2) How can I make an assertion about the value property? The input element doesn't have that property as far as I can tell. And I am still getting "TypeError: Cannot read property 'value' of null" after I set zipInput to element.shadowRoot.querySelector('input[name="zip"]') ... Commented Nov 12, 2019 at 5:05

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .