Skip to content

Getting Started

  • vitest — test runner
  • @vue/test-utils — Vue component test utils
  • @vue/test-utils — DOM testing utilities tailored for Vue
  • happy-dom — Node environment to simulate browser APIs

Install

bash
pnpm add -D @nuxt/test-utils vitest @vue/test-utils happy-dom

There is a great vscode plugin for vitest.

fun gif

Nuxt module

ts
export default defineNuxtConfig({
    modules: ["@nuxt/test-utils/module"],
})

Then add this to your project root along side nuxt.config.ts at vitest.config.ts.

ts
import { defineVitestConfig } from "@nuxt/test-utils/config"

export default defineVitestConfig({
    root: ".",
    test: {
        environment: "nuxt",
        globals: true,
        setupFiles: [],
        include: ["**/tests/**/*.test.ts", "**/*.test.ts"],
        exclude: ["tests/setup.ts", "node_modules", "dist", ".output", ".nuxt", "coverage"],
    },
})

What this does is runs vitest tests inside a nuxt runtime, installing modules and plugins. This is really powerful for quickly validating the quality of our logic and composables.

Setup Global Test Utilities (optional)

Create a vitest.setup.ts file if you want to add global mocks or utilities:

ts
import { describe, expect, beforeEach, it, test } from "vitest"

describe("description", () => {
    beforeEach(() => {
        // setup code
    })

    it("should do something", async () => {
        // ... in a nuxt context!
    })

    it("should do something else", async () => {
        // test logic 2
    })

    it("should handle edge case", async () => {
        // test logic 3
    })
})

Component Lifecycle

Nuxt Testing: Getting started

If you need access to component lifecycles, while testing composables, then mount the component in a beforeEach hook.

ts
import { describe, expect, beforeEach, it, test } from "vitest"
import { mountSuspended } from "@nuxt/test-utils/runtime"
import Login from "~/pages/auth/login.vue"

describe("description", () => {
    beforeEach(async () => {
        await mountSuspended(Login) // access to the component lifecycle
    })

    it("wrong email: fails to login", async () => {
        const { submit, formInput } = useLoginForm()

        formInput.value = {
            email: "mail.com",
            password,
        }

        const out = await submit()
        expect(out.ok).toBe(false)
        expect(out.code).toBe(401)
    })

    it("wrong password: fails to login", async () => {
        const { submit, formInput } = useLoginForm()

        formInput.value = {
            email: email,
            password: badPassword,
        }

        const out = await submit()
        expect(out.ok).toBe(false)
        expect(out.code).toBe(401)
    })
})

Running Tests

For watch mode during development:

bash
npx vitest

Tips for Nuxt-Specific Testing

  • Use aliases: Nuxt resolves ~ and @ to project root, Vitest picks this up if you use Vite config aliases.
  • Mock runtime config or composables when needed, e.g., useRuntimeConfig().
  • Testing server-side code: Vitest supports it, but keep your server logic isolated and test with direct imports.
  • Use @vue/test-utils and @testing-library/vue for component testing, depending on your preference for interaction or snapshot tests.