DEV Community

Cover image for How to Setup Jest Testing In Nuxt Js Project
Lakh Bawa
Lakh Bawa

Posted on • Updated on

How to Setup Jest Testing In Nuxt Js Project

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

Github Repo Link

Alt Text

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',
  ],
}
Enter fullscreen mode Exit fullscreen mode

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>' }
Enter fullscreen mode Exit fullscreen mode

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()
})
Enter fullscreen mode Exit fullscreen mode

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')
  })
})
Enter fullscreen mode Exit fullscreen mode

Update: Code Refactored in Repository to Reduce Code Duplicating

Github Repository with all the tests and configuration

Github Repo Link

Important Links:
https://medium.com/@brandonaaskov/how-to-test-nuxt-stores-with-jest-9a5d55d54b28
https://itnext.io/testing-real-world-vuejs-apps-d3e44118f8ce

Latest comments (6)

Collapse
 
shalinibaskaran12 profile image
Shalini Baskaran

Thank you for sharing these valuable content on Jest testing ! I've been exploring different resources to enhance my test automation skills, I recently came across another article titled 'Complete guide to Jest testing' that expands on some of the concepts you've covered here. It delves deeper into practical tips and techniques for optimizing test automation workflows with Jest. Keep up the great work!"

Collapse
 
wautson profile image
Wautson

Why are you creating a build for testing, what is the benefits of that?

Collapse
 
fgoessler profile image
Florian Gößler

Awesome post! I was struggling with the same just with Nuxt3 which adds some new 'funny' tricks to mix. 😅

I wrote about it here: medium.com/@fgoessler/set-up-nuxt3...

Collapse
 
slidenerd profile image
slidenerd

how to test getters actions and mutations of vuex using this approach?

Collapse
 
slidenerd profile image
slidenerd • Edited

i found this file github.com/bawa93/nuxtjs-vue-vueti... which has tests for getters, could you kindly add an example for actions and mutations. also where is your buildDir: '.nuxt-build-jest'?

Collapse
 
stalker3343 profile image
Artem

Hello. Thank you for the guide, it helped me a lot. During set up the testing, I found that nuxt is trying to build components and pages while preparing the store. You need add "ignore" property in finalConfig

const finalConfig = Object.assign({}, nuxtConfig, resetConfig, {
server: { port: constants.port },
buildDir: constants.buildDir,
ignore: ["/components//", "/layouts//", "/pages//*"]
})