Lakh Bawa
Posted on December 29, 2020
Hello everyone, hope you are doing well and staying safe.
Recently I had to do a lot of work hard to figure out, how to set up the testing environment in Nuxtjs Project. As Nuxtjs does not provide a sufficient built In configuration for the testing environment ( even if you use nuxt CLI to bootstrap the project ). That's why just after finishing up the setup with continue troubleshoot of more than 20 hours. I am going to share my setup in this article which i used for our website acting jobs in india. We will assume you have set up the nuxt project using nuxt CLI. if not you can copy and match the package.json from the given Github repo.
Update: Code Refactored in Github Repository to Reduce Duplicating
Modify and edit the jest.config.js as below
module.exports = {
setupFilesAfterEnv: ['./jest.setup.js'],
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/$1',
'^~/(.*)$': '<rootDir>/$1',
'^vue$': 'vue/dist/vue.common.js',
},
moduleFileExtensions: ['ts', 'js', 'vue', 'json'],
transform: {
'^.+\\.ts$': 'ts-jest',
'^.+\\.js$': 'babel-jest',
'.*\\.(vue)$': 'vue-jest',
},
collectCoverage: true,
collectCoverageFrom: [
'<rootDir>/components/**/*.vue',
'<rootDir>/pages/**/*.vue',
],
}
Create the jest.setup.js file and paste the following content into it
import Vue from 'vue'
// import Vuetify from 'vuetify'
import { config } from '@vue/test-utils'
Vue.config.silent = true
// Vue.config.ignoredElements = ['nuxt-link']
// Mock Nuxt components
config.stubs.nuxt = { template: '<div />' }
config.stubs['nuxt-link'] = { template: '<a><slot /></a>' }
config.stubs['no-ssr'] = { template: '<span><slot /></span>' }
Our Jest Setup is done,
Now we are going to write the sample tests
Create tests/nuxt-pages.test.js file with the following content
const { Nuxt, Builder } = require('nuxt')
// eslint-disable-next-line no-unused-vars
const request = require('supertest')
const nuxtConfig = require('../nuxt.config.js')
// We keep the nuxt and server instance
// So we can close them at the end of the test
let nuxt = null
// Init Nuxt.js and create a server listening on localhost:4000
beforeAll(async () => {
// const config = {
// dev: process.env.NODE_ENV === 'production',
// rootDir: resolve(__dirname, '../'),
// mode: 'universal',
// plugins,
// modules
// }
nuxt = new Nuxt({...nuxtConfig, server: { port: 3001}, buildDir: '.nuxt-build-jest'})
await new Builder(nuxt).build()
await nuxt.server.listen(3001, 'localhost')
}, 300000)
// Example of testing only generated html
describe('GET /', () => {
test('Route / exits and render HTML', async () => {
const { html } = await nuxt.server.renderRoute('/', {})
expect(html).toContain('Vuetify')
})
})
// describe('GET /', () => {
// test('returns status code 200', async () => {
// const response = await request(nuxt.server.app).get('/')
// expect(response.statusCode).toBe(200)
// })
// })
// describe('GET /test', () => {
// test('returns status code 404', async () => {
// const response = await request(nuxt.server.app).get('/test')
// expect(response.statusCode).toBe(404)
// })
// })
// Close server and ask nuxt to stop listening to file changes
afterAll(() => {
nuxt.close()
})
We are testing the Server rendered pages here. for instance, we are checking if index pages contain "Vuetify" text after rendering
Testing the Components
create ./tests/vue-components.test.js
// import { shallowMount } from '@vue/test-utils'
import Logo from '@/components/Logo.vue'
import VuetifyLogo from '@/components/VuetifyLogo'
import GlobalModuleUsage from '@/components/GlobalModuleUsage'
import helpers from '~/utils/GeneralHelpers'
export const addVuetify = (context) => {
context.vuetify = require('vuetify')
context.vue.use(context.vuetify)
// eslint-disable-next-line new-cap
context.vuetifyInstance = new context.vuetify()
}
export const addVuex = (context) => {
context.vuex = require('vuex')
context.vue.use(context.vuex)
}
export const addHelpers = () => {
return (context) => {
context.vue.prototype.$helpers = helpers
}
}
export const addI18n = (options) => {
return (context) => {
context.i18n = require('vue-i18n')
context.vue.use(context.i18n)
// eslint-disable-next-line new-cap
context.i18nInstance = new context.i18n(options)
}
}
export const addFilter = (name, lambda) => {
return context => context.vue.filter(name, lambda)
}
export const compositeConfiguration = (...configs) => {
return context => configs.forEach(config => config(context))
}
export const bootstrapVueContext = (configureContext) => {
const context = {}
const teardownVueContext = () => {
jest.unmock('vue')
Object.keys(context).forEach(key => delete context[key])
jest.resetModules()
}
jest.isolateModules(() => {
context.vueTestUtils = require('@vue/test-utils')
context.vue = context.vueTestUtils.createLocalVue()
jest.doMock('vue', () => context.vue)
configureContext && configureContext(context)
})
return {
teardownVueContext,
...context
}
}
// describe('Logo', () => {
// test('is a Vue instance', () => {
// const wrapper = shallowMount(Logo)
// expect(wrapper.vm).toBeTruthy()
// })
// })
describe('Logo', () => {
let vueContext = null
beforeEach(() => {
vueContext = bootstrapVueContext(
compositeConfiguration(addVuex, addVuetify, addHelpers())
)
})
afterEach(() => {
vueContext.teardownVueContext()
})
test('Test Logo Component', () => {
const wrapper = vueContext.vueTestUtils.shallowMount(Logo, {
localVue: vueContext.vue,
vuetify: vueContext.vuetifyInstance
})
expect(wrapper.text()).toMatch('Logo')
})
test('Test Vuetify Logo Component', () => {
const wrapper = vueContext.vueTestUtils.shallowMount(VuetifyLogo, {
localVue: vueContext.vue,
vuetify: vueContext.vuetifyInstance
})
expect(wrapper.text()).toMatch('Logo')
})
test('Test Global Variables', () => {
const wrapper = vueContext.vueTestUtils.shallowMount(GlobalModuleUsage, {
localVue: vueContext.vue,
vuetify: vueContext.vuetifyInstance
})
expect(wrapper.text()).toMatch('91')
})
})
Update: Code Refactored in Repository to Reduce Code Duplicating
Github Repository with all the tests and configuration
Important Links:
https://medium.com/@brandonaaskov/how-to-test-nuxt-stores-with-jest-9a5d55d54b28
https://itnext.io/testing-real-world-vuejs-apps-d3e44118f8ce
Posted on December 29, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.