Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unable to perform click on Vuetify vSwitch when testing with Jest

I am currently writing tests for a Vue Component which implements a Vuetify Switch. As part of the testing I want to check the functionality of the vuetify switch. I am having troubling triggering a click on the switch to then verify that the switches value has changed (and once I have done that I will verify that the value bound to the switch has changed as well)

I have looked at the API docs for Vuetify and there are no methods to directly set the state of a Vuetify switch which is bewildering in my opinion. Because of this I am trying to perform a click on the VSwitch component using wrapper.find().trigger('click') but this isn't changing the switch value, leading me to believe the click isn't doing anything at all.

Below are two tests

  • the first checks that the switch has the correct state on creation, which is passing
  • The second tries to perform a click event and check that the state has changed, which is failing

Any help in resolving this problem would be greatly appreciated.

switch.vue

<template>

    <v-row>
        <v-col>
            <label class="label-text" :for="`${fieldLabel}`">{{labelText}}</label>
            <v-row>
                <label class="left-label">{{toggleLeftText}}</label>
                <v-switch
                        :id="`${fieldLabel}`"
                        v-model="toggleState"
                        class="ma-0 pa-0"
                        :data-qa="`${fieldLabel}Checkbox`"
                >
                </v-switch>
                <label class="right-label">{{toggleRightText}}</label>
            </v-row>
            <!--Hidden input field includes switch value in form when submitted-->
            <input type="hidden" :value="toggleState" :name="`${fieldLabel}`">
        </v-col>
    </v-row>


</template>

<script>
    export default {
        name: "Switch",
        props: {
            fieldLabel: {
                type: String,
                required: true
            },
            labelText: {
                type: String,
                required: true
            },
            toggleLeftText: {
                type: String,
                required: true
            },
            toggleRightText: {
                type: String,
                required: true
            },
            toggleValue: {
                type: Boolean,
                required: true
            },

        },

        data: function () {
            return {
                toggleState: this.toggleValue
            }
        }

    }
</script>

switch.spec.js


describe('Switch', () => {

    const toggleState = true;

    const localVue = createLocalVue();
    localVue.use(Vuetify, {
        components: {
            VRow,
            VCol,
            VSwitch,
            InputError
        }
    });

    const wrapperFactory = () => {
        return shallowMount(Switch, {
            localVue,
            vuetify: new Vuetify(),
            propsData: testProps,
        });
    };

    const testProps = {
        labelText: "Test Label",
        fieldLabel: "testLabel",
        toggleLeftText: "No",
        toggleRightText: "Yes",
        toggleValue: toggleState
    };

    let wrapper;

    beforeEach(() => {
        wrapper = wrapperFactory(testProps);
    });

    afterEach(() => {
        wrapper.destroy();
    });

    it("should have correct toggle value", () => {
        const vSwitch = wrapper.find(VSwitch);
        expect(vSwitch.vm.value).toBe(toggleState);
    });

    it("should have correct toggle value after click", async () => {
        const vSwitch = wrapper.find(VSwitch);
        await vSwitch.trigger('click');
        expect(vSwitch.vm.value).toBe(!toggleState);
    });
});

like image 458
Russell Brady Avatar asked Nov 27 '19 12:11

Russell Brady


People also ask

How do I use vuetify with Vue UI?

Once compiled you can open the app by clicking Open app. I will install the Vuetify plugin, since this project will use Vuetify, a material design component framework. Go to Plugins in the Vue UI, click Add plugin and search for vuetify. Select the first option and click install. It will then ask to choose a preset.

How to enable unit testing in Vue?

It also includes vue-test-utils which is a great library that makes testing a lot easier in vue. It also provides the hot reloading which speeds up the development process. Once we hit this, it will ask for some information. Choose Manually select features and enable “ Unit testing ” along with other required features and continue.

What is the default test in Vue CLI?

Eg: example.spec.js The example.spec.js file is the default test that comes with vue cli 3. It expects the text on the HelloWorld component to match the data received as props from its parent App.vue.

Is there a code snippet that can be used with vuetify?

(Surprised that didn't find a single code snippet that could work, after searching in both vuetify official document & via Google.) Handler method from methods part of the containing component.


1 Answers

I might be a bit late for answering your question, but this way you should be able to get your v-switch.

const vSwitch = wrapper.find({ name: 'v-switch' });

and then trigger the event with

vSwitch.$emit('change', <true or false>);, depending on what you're testing.

The limit with this approach is that if you have multiple v-switches in your code, you would need to target them with a data-test-id, for example like this:

<v-switch data-test-id="my-switch-1"> ... </v-switch>;
<v-switch data-test-id="my-switch-2"> ... </v-switch>;

and then I defined a helper function on top of my test file, like so:

const getSwitchComponent = (wrapper: Wrapper<Vue>, testId: string): Wrapper<Vue> => {
  const switches = wrapper.findAll({ name: 'v-switch' });
  const component = switches.wrappers.find(wrapper =>
    wrapper.contains(`[data-test-id="${testId}"]`),
  );

  if (!component) {
    throw Error(`Element not found: ${testId}`);
  }

  return component;
};

which will let you do something like this:

const mySwitch1 = getSwitchComponent(wrapper, 'my-switch-1');
const mySwitch2 = getSwitchComponent(wrapper, 'my-switch-2');

and trigger the change event so:

mySwitch1.vm.$emit('change', false);
mySwitch2.vm.$emit('change', true);
like image 67
mike87 Avatar answered Nov 01 '22 10:11

mike87