This article is more than four years old. The content may be outdated, especially technical examples or references to tooling.
When you set up a project with create-nuxt-app or configure it manually, you may also add a framework for unit testing. @vue/test-utils provides utilities for mounting Vue components and inspecting their behaviour.
Testing Nuxt-specific hooks requires some additional care. This article looks at calling hooks directly in a unit test and explains what that approach does, and does not, verify.
Testing a Vue component
A basic component test only takes a few lines. Mount the component, inspect its initial state, call a method and check the result. With shallowMount, child components are stubbed so the test can focus on the component itself.
import { shallowMount } from '@vue/test-utils';
import ExampleComponent from './example-component.vue';
describe('Example component', () => {
it('should test something', () => {
const wrapper = shallowMount(ExampleComponent);
expect(wrapper.vm.anyProp).not.toEqual(anyExpectedValue);
wrapper.vm.myMethod();
expect(wrapper.vm.anyProp).toEqual(anyExpectedValue);
});
});
This test checks how the component's state changes after a method call. The assertions should describe the behaviour you expect from that component.
Testing a Nuxt.js component
Nuxt adds features such as asyncData, fetch and head to the component options. These features normally run within Nuxt's runtime. Mounting a component with Vue Test Utils alone does not reproduce that runtime.
For a focused unit test, you can call a hook directly. That gives you control over its execution and the inputs used by the test.
Calling a hook directly
import ExampleComponent from './example-component.vue';
describe('Example component', () => {
it('should test something', async () => {
await ExampleComponent.asyncData();
expect(something).toEqual(somethingExpected);
});
});
This calls the function without mounting the component. You can make assertions about its return value or calls to mocked dependencies. It does not show how Nuxt integrates the result into a rendered page.
Passing an explicit context
JavaScript's Function.prototype.call() lets you choose the this value for a function call. Its first argument supplies that value; the remaining arguments are passed to the function:
call(thisArg, arg1, ... , argN);
The following example mounts the component and passes wrapper.vm as the this value for the direct call. Assertions then inspect the mounted component's state:
import { shallowMount } from '@vue/test-utils';
import ExampleComponent from './example-component.vue';
describe('Example component', () => {
it('should test something', async () => {
const wrapper = shallowMount(ExampleComponent);
expect(wrapper.vm.anyProp).not.toEqual(anyExpectedValue);
await ExampleComponent.asyncData.call(wrapper.vm);
expect(wrapper.vm.anyProp).toEqual(anyExpectedValue);
});
});
What these unit tests verify
A direct call tests the function under the conditions you supply. Depending on the assertions, that can cover returned data, calls to mocked dependencies or changes to the state provided by the test.
It does not verify that Nuxt invokes the hook with those same conditions. In particular, these examples do not test:
- When and how Nuxt runs hooks during its lifecycle.
- Server-side rendering, hydration or route navigation.
- Nuxt's automatic handling of loading and error states.
For those behaviours, add integration or end-to-end tests that run the application through Nuxt. Use direct unit tests for focused checks of function behaviour, and test the complete page separately when the result depends on the framework's runtime.
