Home > Software design >  VueJS HTTP Tests - Mock not reflected in component render
VueJS HTTP Tests - Mock not reflected in component render

Time:06-27

I'm trying to complete some lightweight tests based on render output focussing on initial load and user interaction.

I am working on a HTTP test for a login component. As you would expect, it's a basic component containing an email field, a password and a button. When the user clicks the button, it calls a method which makes an axios call to an endpoint. The specific test case that I am working on is the "invalid submission" test where I simulate a user simply hitting the submit button without entering any information, expecting the application to output errors.

I first tried going down the vue-test-utils route and triggering a button click and using Jest's spyOn function to watch for axios.post requests. Despite various attempts to delay using await and various other suggested Promise approaches, nothing was being rendered and spyOn was not reporting any form of axios calls, so the test failed despite following the documentation.

My research into Vue HTTP testing patterns led me to Mock tests. I had some success with Mock tests using axios-mock-adapter with the expect() cases checking the axios calls, however any sort of check on the render itself would fail. The mock tests had no affect on the vdom, despite having the mount configured to attachTo: document.body and various attempts to delay the checks with promises.

describe("when API call is unsuccessful", () => {
    it('displays error messages', async () => {  
        let spy = jest.spyOn(axios, "post");
        let result = null;
        mock.onPost(url).reply(422, mockResult);

        await axios.post(url).then(function (response) {
            result = response
        }).catch((error) => {
            result = error.response.data
        });

        expect(spy).toHaveBeenCalledTimes(1) <-- Passes
        expect(result).toEqual(mockResult) <-- Passes
        expect(wrapper.get('.error--text')) <-- Fails
    })
})

For the sake of trial & error, I even added a line into the catch function that set the wrapper.vm.errors data property to the result variable (which is what the component does following a failed request) and then the dom checks passed.

Am I missing something? Is there a clear, simple way of mocking an HTTP request and updating a component accordingly that I am just missing?

CodePudding user response:

I had a small breakthrough with this. I switched over to Moxios and had success with mocking HTTP requests that impact the component and its render.

login.spec.js:

import { mount, createLocalVue } from '@vue/test-utils';
import VueCompositionApi from '@vue/composition-api'
import axios from 'axios';
import Vuetify from "vuetify";
import moxios from 'moxios';
import expect from 'expect';


beforeEach(() => {
    moxios.install()
    const localVue = createLocalVue();
    localVue.use(VueCompositionApi);
    vuetify = new Vuetify();

    jest.spyOn(axios, 'post').mockResolvedValue(mockResult)

    wrapper = mount(localVue.component('login', require('../../resources/js/components/Login.vue').default), {
        vuetify,
        attachTo: document.body
    });
})

afterEach(function () {
    moxios.uninstall()
})

afterAll(() => {
    wrapper.destroy()
})

describe("when API call is unsuccessful", () => {
    it('displays error messages', (done) => {  
        wrapper.find('button').trigger('click')

        moxios.wait(function () {
            let request = moxios.requests.mostRecent()
            request.respondWith({
              status: 422,
              response: mockResult
            }).then(function(response){
                done()
                expect(response).rejects
                expect(wrapper.get('.error--text'))
            })
        })
    })
})
  • Related