How to Setup Jest Testing In Nuxt Js Project
Tags: vue, jest, testing, nuxt
Published: 2020-12-29 09:18:34

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](https://www.castkro.com/casting-calls). 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](https://github.com/lakhbawa/nuxtjs-vue-vuetify-vue-test-utils-jest-sample-project)

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/t6xs77atfdtjm7df5up1.png)

## Modify and edit the jest.config.js as below

```javascript
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

```javascript
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

```javascript

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

```javascript
// 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

[Github Repo Link](https://github.com/bawa93/nuxtjs-vue-vuetify-vue-test-utils-jest-sample-project)


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