8

I'm testing a Vue component but I'm having trouble testing a button's disabled state. How can I access a button's disabled status in my tests?

I've tried using .attributes() but in this instance the method only returns the button properties that weren't set by v-bind. SubmitButton.attributes().disabled is always null.

Component

<button
  id="edit-resource-modal-submit"
  class="btn btn-sm btn-primary modal-button"
  :disabled="loadingResource || !formValid"
  @click="submit"
>
  Save
</button>

Test

describe('Disables buttons if', () => {
  beforeEach(async() => {
    await wrapper.setProps({ isModalOpen: true });
  });
  it('modal is loading', async() => {
    wrapper.vm.loadingResource = true;
    const SubmitButton = wrapper.find('#edit-resource-modal-submit');
    expect(SubmitButton.exists()).toBe(true);
    expect(SubmitButton.attributes().disabled).toBe('true');
  });
});

.attributes() only returns

{
  id: 'edit-resource-modal-submit',
  class: 'btn btn-sm btn-primary modal-button'
}
tony19
  • 125,647
  • 18
  • 229
  • 307
Jon_B
  • 969
  • 4
  • 16
  • 24

2 Answers2

14

Option 1: Check disabled attribute

In Vue 2, the disabled attribute is set to "disabled" (not "true") when the element is actually disabled. In Vue 3, it's set to an empty string. The attribute itself is undefined (i.e., absent from the attributes) when the element is enabled.

To be compatible with both versions of Vue, the test could just check if the disabled attribute is defined. Also note the test should await a micro tick (via await wrapper.vm.$nextTick()) to allow the property change (wrapper.vm.loadingResource = true) to take effect in disabling the button:

const wrapper = shallowMount(MyComponent)

// update prop, and wait a tick to allow it to take effect
wrapper.vm.loadingResource = true
await wrapper.vm.$nextTick()

const button = wrapper.find('#edit-resource-modal-submit')
expect(button.attributes().disabled).toBeDefined() 

Option 2: Check disabled property

The test could read the disabled property directly from the element reference itself, which is exposed by the test wrapper's element property:

const wrapper = shallowMount(MyComponent)

// update prop, and wait a tick to allow it to take effect
wrapper.vm.loadingResource = true
await wrapper.vm.$nextTick()

const button = wrapper.find('#edit-resource-modal-submit')
expect(button.element.disabled).toBe(true) 

Vue 2 demo

Vue 3 demo

tony19
  • 125,647
  • 18
  • 229
  • 307
5

For vue-test-utils with vue 3 the answer of @tony19 is also working. However its using the old api of vue-test-utils for vue 2.

As you can see the return values for attributes() do not contain disabled attribute if the element is enabled. So I would recommend to test it the following way:

expect(SubmitButton.attributes('disabled')).toBeUndefined(); // enabled
expect(SubmitButton.attributes('disabled')).toBe("") // disabled
Theiaz
  • 568
  • 6
  • 24