Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nuxt Ava End-to-End Testing Store Configuration

Given the example official Nuxt end-to-end test example using Ava:

import test from 'ava'
import { Nuxt, Builder } from 'nuxt'
import { resolve } from 'path'

// We keep a reference to Nuxt so we can close
// the server at the end of the test
let nuxt = null

// Init Nuxt.js and start listening on localhost:4000
test.before('Init Nuxt.js', async t => {
  const rootDir = resolve(__dirname, '..')
  let config = {}
  try { config = require(resolve(rootDir, 'nuxt.config.js')) } catch (e) {}
  config.rootDir = rootDir // project folder
  config.dev = false // production build
  config.mode = 'universal' // Isomorphic application
  nuxt = new Nuxt(config)
  await new Builder(nuxt).build()
  nuxt.listen(4000, 'localhost')
})

// Example of testing only generated html
test('Route / exits and render HTML', async t => {
  let context = {}
  const { html } = await nuxt.renderRoute('/', context)
  t.true(html.includes('<h1 class="red">Hello world!</h1>'))
})

// Close the Nuxt server
test.after('Closing server', t => {
  nuxt.close()
})

How can you use Nuxt or Builder to configure/access the applications Vuex store? The example Vuex store would look like:

import Vuex from "vuex";

const createStore = () => {
  return new Vuex.Store({
    state: () => ({
      todo: null
    }),
    mutations: {
      receiveTodo(state, todo) {
        state.todo = todo;
      }
    },
    actions: {
      async nuxtServerInit({ commit }, { app }) {
        console.log(app);
        const todo = await app.$axios.$get(
          "https://jsonplaceholder.typicode.com/todos/1"
        );
        commit("receiveTodo", todo);
      }
    }
  });
};

export default createStore;

Currently trying to run the provided Ava test, leads to an error attempting to access @nuxtjs/axios method $get:

TypeError {
  message: 'Cannot read property \'$get\' of undefined',
}

I'd be able to mock $get and even $axios available on app in Vuex store method nuxtServerInit, I just need to understand how to access app in the test configuration.

Thank you for any help you can provide.

like image 933
Alexander Staroselsky Avatar asked Nov 07 '22 01:11

Alexander Staroselsky


1 Answers

Just encountered this and after digging so many tutorial, I pieced together a solution.

You have essentially import your vuex store into Nuxt when using it programmatically. This is done by:

  1. Importing Nuxt's config file
  2. Adding to the config to turn off everything else but enable store
  3. Load the Nuxt instance and continue your tests

Here's a working code (assuming your ava and dependencies are set up)

// For more info on why this works, check this aweomse guide by this post in getting this working
// https://medium.com/@brandonaaskov/how-to-test-nuxt-stores-with-jest-9a5d55d54b28
import test from 'ava'
import jsdom from 'jsdom'
import { Nuxt, Builder } from 'nuxt'
import nuxtConfig from '../nuxt.config' // your nuxt.config 

// these boolean switches turn off the build for all but the store
const resetConfig = {
  loading: false,
  loadingIndicator: false,
  fetch: {
    client: false,
    server: false
  },
  features: {
    store: true,
    layouts: false,
    meta: false,
    middleware: false,
    transitions: false,
    deprecations: false,
    validate: false,
    asyncData: false,
    fetch: false,
    clientOnline: false,
    clientPrefetch: false,
    clientUseUrl: false,
    componentAliases: false,
    componentClientOnly: false
  },
  build: {
    indicator: false,
    terser: false
  }
}

// We keep a reference to Nuxt so we can close
// the server at the end of the test
let nuxt = null

// Init Nuxt.js and start listening on localhost:5000 BEFORE running your tests. We are combining our config file with our resetConfig using Object.assign into an empty object {}
test.before('Init Nuxt.js', async (t) => {
  t.timeout(600000)
  const config = Object.assign({}, nuxtConfig, resetConfig, {
    srcDir: nuxtConfig.srcDir, // don't worry if its not in your nuxt.config file. it has a default
    ignore: ['**/components/**/*', '**/layouts/**/*', '**/pages/**/*']
  })
  nuxt = new Nuxt(config)
  await new Builder(nuxt).build()
  nuxt.listen(5000, 'localhost')
})

// Then run our tests using the nuxt we defined initially
test.serial('Route / exists and renders correct HTML', async (t) => {
  t.timeout(600000) // Sometimes nuxt's response is slow. We increase the timeont to give it time to render
  const context = {}
  const { html } = await nuxt.renderRoute('/', context)
  t.true(html.includes('preload'))
  // t.true(true)
})

test.serial('Route / exits and renders title', async (t) => {
  t.timeout(600000)
  const { html } = await nuxt.renderRoute('/', {})
  const { JSDOM } = jsdom // this was the only way i could get JSDOM to work. normal import threw a functione error
  const { document } = (new JSDOM(html)).window
  t.true(document.title !== null && document.title !== undefined) // simple test to check if site has a title
})

Doing this should work. HOWEVER, You may still get some errors

  • ✖ Timed out while running tests. If you get this you're mostly out of luck. I thought the problem was with Ava given that it didn't give a descriptive error (and removing any Nuxt method seemed to fix it), but so far even with the above snippet sometimes it works and sometimes it doesn't.
  • My best guess at this time is that there is a delay on Nuxt's side using either renderRouter or renderAndGetWindow that ava doesn't wait for, but on trying any of these methods ava almost immediately "times out" despite the t.timeout being explicitly set for each test. So far my research has lead me to checking the timeout for renderAndGetWindow (if it exists, but the docs doesn't indicate such).

That's all i've got.

like image 132
Audacitus Avatar answered Nov 12 '22 16:11

Audacitus