Hi there! I recently put together a login form using the Vue.js framework, and now I'm looking to write some tests for my API calls. Although I'm still new to Vue.js, I'm eager to learn more about testing in this environment.
Here's the code snippet for my form:
<template>
<div>
<div class="col q-mb-md">
<div class="row">
<q-btn
@click="loginGoogle"
type="submit"
color="primary"
class="col"
name="login_google"
outline
size="lg"
label="Login with Google" />
</div>
</div>
<div class="col q-mb-md">
<div class="row">
<q-btn
type="submit"
color="primary"
class="col"
name="login_apple"
outline
size="lg"
label="Login with Apple ID" />
</div>
</div>
<form @submit.prevent="submitForm" class="q-mt-lg">
<div class="col q-mb-md">
<q-input
v-model="formData.email"
outlined
class="col"
label="Email"
ref="email"
stack-label
:rules="[ val => validateEmail(val) || 'Please enter a valid email address']"
lazy-rules />
</div>
<div class="col q-mb-md">
<q-input
v-model="formData.password"
type="password"
outlined
class="col"
label="Password"
ref="password"
stack-label
:rules="[ val => val.length >= 8 || 'Password must be at least 8 characters']"
lazy-rules />
</div>
<div class="row">
<q-btn
type="submit"
name="login"
class="login"
color="primary"
label="Login" />
</div>
</form>
</div>
</template>
Let me show you the action method that triggers the API call:
submitForm () {
this.$refs.email.validate()
this.$refs.password.validate()
if (!this.$refs.email.hasError && !this.$refs.password.hasError) {
authService.login({ email: this.formData.email.toLowerCase(), password: this.formData.password })
.then((res) => {
this.$store.commit('SET_AUTH_USER')
localStorage.setItem('access_token', res.access_token)
localStorage.setItem('refresh_token', res.refresh_token)
this.$store.dispatch('GET_ME').then((me) => {
this.$router.push({ path: '/' })
})
}).catch((err) => {
if (err.status === 500) {
this.$swal({ icon: 'error', title: 'Something went wrong!' })
} else {
this.$swal({ icon: 'error', title: 'Wrong data!' })
}
})
}
}
This is how I structured my API call:
/**
* Send request for login user and set token in localstorage
*
* @param {String} email
* @param {String} password
* @returns {Object}
*/
async function login (data) {
const requestOptions = {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
Accept: 'application/json'
},
body: `email=${data.email.trim()}&password=${data.password.trim()}`
}
const res = await fetch('http://localhost/api/login', requestOptions)
if ((await res.status) !== 200) {
// eslint-disable-next-line no-throw-literal
throw { status: res.status, message: res.statusText }
} else {
return await res.json()
}
}
I attempted to test my form by mocking the action from vuex store as advised. However, the test didn't produce the expected results. Here's what happened:
import Vuex from 'vuex'
import { mount, createLocalVue } from '@vue/test-utils'
import LoginComponent from '../components/Auth/Login'
const localVue = createLocalVue()
localVue.use(Vuex)
describe('Login form', () => {
it('calls the login action correctly', () => {
const loginMock = jest.fn(() => Promise.resolve())
const store = new Vuex.Store({
actions: {
// mock function
submitForm: loginMock
}
})
const wrapper = mount(LoginComponent, { localVue, store })
wrapper.find('form').trigger('submit.prevent')
expect(loginMock).toHaveBeenCalled()
})
})
The test failed, indicating that the login action was not called as expected:
Login form
✕ calls the login action correctly (50 ms)
● Login form › calls the login action correctly
expect(jest.fn()).toHaveBeenCalled()
Expected number of calls: >= 1
Received number of calls: 0
18 | const wrapper = mount(LoginComponent, { localVue, store })
19 | wrapper.find('form').trigger('submit.prevent')
> 20 | expect(loginMock).toHaveBeenCalled()
| ^
21 | })
22 | })
23 |
at Object.<anonymous> (src/specs/login.spec.js:20:23)
If you have any suggestions on other tests I should include to ensure the functionality of my form, please let me know! Your insights are much appreciated. Thank you!