Skip to content

Jest with Vue

Vue projects can use Jest alongside Vue Test Utils to mount and test components. This lesson covers setup and the core testing patterns specific to Vue's component model.

Mounting Vue Components with Vue Test Utils

@vue/test-utils provides a mount() function that renders a Vue component into a simulated DOM (via jsdom), returning a wrapper object with methods for finding elements, reading text, and simulating interaction — conceptually similar to React Testing Library, but tailored to Vue's reactivity system.

Jest needs a transformer capable of handling .vue single-file components; vue-jest (for Vue 3) or Vite's native test runner Vitest (a common alternative for newer Vue/Vite projects) fills that role.

// Counter.vue
<template>
  <button @click="count++">Count: {{ count }}</button>
</template>
<script setup>
import { ref } from 'vue';
const count = ref(0);
</script>

// Counter.test.js
import { mount } from '@vue/test-utils';
import Counter from './Counter.vue';

test('increments the count when clicked', async () => {
  const wrapper = mount(Counter);

  await wrapper.find('button').trigger('click');

  expect(wrapper.text()).toContain('Count: 1');
});

await is required after .trigger() because Vue batches DOM updates asynchronously after reactive state changes.

Jest Configuration for Vue Single-File Components

// jest.config.js
module.exports = {
  testEnvironment: 'jsdom',
  transform: {
    '^.+\\.vue$': '@vue/vue3-jest',
    '^.+\\.js$': 'babel-jest',
  },
  moduleFileExtensions: ['js', 'json', 'vue'],
};
  • @vue/vue3-jest transforms .vue files so Jest can parse and run them.
  • moduleFileExtensions must include 'vue' so Jest resolves imports without an explicit extension.
  • Vitest is a popular Jest-API-compatible alternative that many Vite-based Vue projects use instead.
  • Testing Library also offers @testing-library/vue for a more RTL-style query API on Vue components.

Jest + Vue Cheat Sheet

Core Vue Test Utils methods you'll use constantly.

Method Purpose
mount(Component, options) Renders a component into a test DOM
wrapper.find(selector) Finds a single matching element
wrapper.trigger('click') Simulates a DOM event
wrapper.text() Gets the rendered text content
wrapper.emitted('event-name') Checks emitted custom events
mount(Component, { props: {...} }) Passes props into the component

Testing Props and Emitted Events

Passing props into mount() lets you test how a component renders with different inputs, and wrapper.emitted() lets you assert on custom events a component emits, which is Vue's primary mechanism for child-to-parent communication.

test('emits an update event with the new value', async () => {
  const wrapper = mount(QuantityInput, { props: { value: 1 } });

  await wrapper.find('button.increment').trigger('click');

  expect(wrapper.emitted('update:value')).toBeTruthy();
  expect(wrapper.emitted('update:value')[0]).toEqual([2]);
});

Awaiting Vue's Reactivity System

Vue batches DOM updates after a reactive value changes, so assertions checking the updated DOM need to happen after an await on the triggering action (or await nextTick()), otherwise the test may check the DOM before Vue has actually re-rendered.

import { nextTick } from 'vue';

wrapper.vm.count = 5;
await nextTick();
expect(wrapper.text()).toContain('5');

Common Mistakes

  • Forgetting to await wrapper.trigger(), checking the DOM before Vue re-renders.
  • Missing 'vue' in moduleFileExtensions, causing import resolution errors.
  • Testing a component's internal reactive state directly instead of its rendered output.
  • Not configuring a .vue file transformer, leading to syntax errors when Jest tries to parse single-file components.

Key Takeaways

  • Vue Test Utils' mount() renders components into a simulated DOM for testing.
  • Testing .vue files with Jest requires a dedicated transformer like @vue/vue3-jest.
  • wrapper.emitted() lets you assert on custom events emitted by a component.
  • Always await triggered interactions to let Vue's reactivity system update the DOM first.

Pro Tip

If your Vue project uses Vite, consider Vitest instead of Jest — it shares almost the same API (describe, it, expect) but integrates more directly with Vite's build pipeline, avoiding extra transformer configuration.