Search code examples
vue.jsvuejs2vue-test-utils

vue-test-utils not updating component after click


I am using vue-test-utils/mocha-webpack/expect to test the following component:

<template>
    <div>
        <div id="agent-customer-container" class="top-tabs" v-if="agentName || customerName || miniBasket">
            <div v-if="agentName || customerName">
                <div class="text-primary bg-white top-tabs__item px-5" id="customer-slot" v-if="customerName" @click="customerDetailShow = !customerDetailShow">
                <span>
                    <i class="fa fa-user-circle fa-2x mr-3"></i>
                    {{ customerName }}
                </span>
                    <i :class="'fa fa-caret-'+(customerDetailShow?'up':'down')" id="customer-caret"></i>
                </div>
                <div class="text-primary top-tabs__item top-tabs__item--light px-5" id="agent-slot" v-if="agentName">
                    {{ agentName }}
                </div>
            </div>
            <div class="top-tabs__mini-basket text-primary px-5" v-if="miniBasket && !loading">
                <span v-if="firstEnquiry !== null && firstEnquiry.cruise !== null && firstEnquiry.cruise !== undefined">
                    <span id="first-enquiry-cruise-summary">{{ firstEnquiry.cruise.name }} ({{ firstEnquiry.cruise.code }})</span>
                 - <span class="text-semibold">£XX.XX</span>
                </span>
                <span id="toggle__mini-basket" :class="[{'fa-counter': (enquiryCount > 0), 'mini-basket__count' : (enquiryCount > 0)}, 'fa-stack v-top ml-3 cursor-pointer']" @click="toggleMiniBasket" :data-count="enquiryCount">
                <i class="fas fa-circle fa-stack-2x"></i>
                <i class="fas fa-shopping-cart fa-stack-1x fa-inverse"></i>
            </span>
            </div>
            <div class="customer-detail bord-rgt" v-show="customerDetailShow">
                <div class="row p-5 bord-btm" v-for="i in 2" :key="i">
                    <div class="col-sm-6">
                        <p><a href="#">Sydney to Hong Kong</a></p>
                        <p>Text<br>Text</p>
                    </div>
                    <div class="col-sm-6">
                        <p><strong>Grade data</strong>
                            <br>
                            Lorem ipsum
                        </p>
                    </div>
                </div>
                <div class="row p-5 bg-primary customer-detail__footer">
                    <div class="row">
                        <div class="col-sm-6">
                            Text
                        </div>
                        <div class="col-sm-6 text-right text-bold">
                            Total £1000
                        </div>
                    </div>
                </div>
            </div>
            <div class="mini-basket-detail bord-lft" v-if="miniBasketDetailShow">
                <div v-if="myEnquiry !== false && myEnquiry !== undefined && myEnquiry['cruise_enquiries'] !== undefined && firstEnquiry !== null && firstEnquiry.cruise !== null">
                    <div class="row p-5 bord-btm" v-for="(cruiseEnquiry, cruiseEnquiryIndex) in myEnquiry['cruise_enquiries']" :key="cruiseEnquiry.id">
                        <div class="col-sm-12 text-sm" v-if="cruiseEnquiry.cruise !== undefined">
                            <cruise-enquiry
                                :cruise-name="cruiseEnquiry.cruise.name"
                                :cruise-code="cruiseEnquiry.cruise.code"
                                :ship-name="cruiseEnquiry.cruise.ship.name"
                                :departure-port-name="cruiseEnquiry.cruise.departure_port.name"
                                :departure-date="new Date(cruiseEnquiry.cruise.departure_date)"
                                :duration="cruiseEnquiry.cruise.duration"
                                :cruise-enquiry-cabins="cruiseEnquiry.cruise_cabin_cruise_enquiry"/>
                        </div>
                    </div>
                </div>
                <div v-else>
                    <div class="row p-5 bord-btm">
                        <div class="col-sm-12 text-sm">
                            <p>Your itinerary is currently empty. Please start by selecting a cruise.</p>
                        </div>
                    </div>
                </div>
                <div id="toggle__mini-basket--close" class="row p-3 bg-primary customer-detail__footer text-center cursor-pointer d-block" @click="miniBasketDetailShow = false">
                    <caret :up="true" additional-classes="fa-2x"></caret>
                </div>
            </div>
            <span class="float-right"></span>
        </div>
    </div>
</template>

<script>
    import Caret from "./Caret";
    import CruiseEnquiry from "./enquiry-panel/CruiseEnquiry";

    export default {
        name: "EnquiryPanel",
        components: {
            CruiseEnquiry,
            Caret,
        },
        props: {
            loading: {
                type: Boolean,
                required: false,
                default: false,
            },
            customerName: {
                type: String,
                required: false,
                default: ''
            },
            agentName: {
                type: String,
                required: false,
                default: ''
            },
            myEnquiry: {
                type: Object|Boolean,
                required: false,
                default: false,
            },
            miniBasket: {
                type: Boolean,
                required: false,
                default: false,
            }
        },
        data() {
            return {
                customerDetailShow: false,
                miniBasketDetailShow: false,
                firstEnquiry: null,
                enquiryCount: 0,
                miniBasketCabinNumber: 0,
            }
        },
        watch: {
            myEnquiry: {
                deep: true,
                immediate: true,
                handler(newValue) {
                    if (this.myEnquiry !== false && this.myEnquiry['cruise_enquiries'] !== undefined && this.myEnquiry['cruise_enquiries'][0] !== undefined) {
                        this.firstEnquiry = this.myEnquiry['cruise_enquiries'][0];
                        for (let i = 0; i <= (this.myEnquiry['cruise_enquiries'].length - 1); i++) {
                            if (this.myEnquiry['cruise_enquiries'][i].cruise !== undefined && this.myEnquiry['cruise_enquiries'][i].cruise !== null) {
                                this.setEnquiryCount(this.enquiryCount + 1);
                            }
                        }
                    }
                }
            }
        },
        methods: {
            setEnquiryCount(count) {
                this.enquiryCount = count;
            },

            toggleMiniBasket() {
                this.miniBasketDetailShow != this.miniBasketDetailShow;
            }
        }
    }
</script>

When I click on #toggle__mini-basket I expect miniBasketDetailShow to be set to true (defaults to false on mount) and the basket should show (using `v-if="miniBasketDetailsShow" on the element).

This is my test for it:

import {createLocalVue, shallowMount, mount} from '@vue/test-utils';
import expect from 'expect';
import EnquiryPanel from '~/components/EnquiryPanel';
import VueMoment from "vue-moment";

describe('EnquiryPanel', () => {
    let localVue;

    beforeEach(() => {
        localVue = createLocalVue();
        localVue.use(VueMoment);
    });

    // If a user clicks on the mini basket icon and the basket panel is not open, the basket panel should open
    it('opens mini basket if user clicks icon and basket is not open', () => {
        let component = shallowMount(EnquiryPanel, {
            localVue,
            propsData: {
                miniBasket: true
            }
        });

        expect(component.vm.miniBasket).toBe(true);
        expect(component.vm.miniBasketDetailShow).toBe(false);

        component.find('#toggle__mini-basket').trigger('click');
        component.vm.$forceUpdate();
        expect(component.vm.miniBasketDetailShow).toBe(true);
    });

});

This is a simple test so I'm unsure what is going wrong. The result is as follows:

 3) EnquiryPanel
       opens mini basket if user clicks icon and basket is not open:
     Error: expect(received).toBe(expected) // Object.is equality

Expected: true
Received: false
      at Context.eval (webpack-internal:///./tests/Javascript/EnquiryPanel.spec.js:62:86)

I would expect this test to be passing. I have tried making the shallowMount be async with sync: false. I have also tried adding in await component.vm.$nextTick but no luck. Any help would be appreciated.


Solution

  • The error was with the toggleMiniBasket method:

    this.miniBasketDetailShow != this.miniBasketDetailShow;

    should be

    this.miniBasketDetailShow = !this.miniBasketDetailShow;