Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Testing basics

A test is code that checks other code: it calls a function or renders a component and compares the result with the expected one. Tests run with one command and quickly show that a change broke something. For Nuxt you use the Vitest test runner and the @nuxt/test-utils package, which runs tests in a Nuxt environment, with auto-imports and plugins.

Installing

npm install -D @nuxt/test-utils vitest @vue/test-utils happy-dom

vitest runs the tests, @vue/test-utils renders components, and happy-dom stands in for the browser. Create a config file in the project root:

// vitest.config.ts
import { defineVitestConfig } from '@nuxt/test-utils/config'
 
export default defineVitestConfig({
  test: {
    environment: 'nuxt'
  }
})

The nuxt environment gives tests everything the app has: the ~ alias, auto-imports, modules. Add a command to the scripts section of package.json: "test": "vitest".

Testing a function

Let us check formatDate from the composables lesson. Create test/formatDate.test.ts:

// test/formatDate.test.ts
import { describe, expect, it } from 'vitest'
import { formatDate } from '~/utils/formatDate'
 
describe('formatDate', () => {
  it('formats a date in English', () => {
    expect(formatDate('2025-03-14')).toBe('March 14, 2025')
  })
})

describe groups tests, it describes one test, and expect(...).toBe(...) compares the result with the expected value. Run:

npm run test

Vitest finds the .test.ts files, runs them and prints a green tick and the line 1 passed in the terminal. Vitest keeps running and reruns the tests on every file save; press q to quit.

Testing a component

Nuxt components are rendered with mountSuspended: it can wait for an async <script setup> and knows about auto-imports.

// test/PostCard.test.ts
import { describe, expect, it } from 'vitest'
import { mountSuspended } from '@nuxt/test-utils/runtime'
import PostCard from '~/components/PostCard.vue'
 
describe('PostCard', () => {
  it('shows the post title', async () => {
    const wrapper = await mountSuspended(PostCard, {
      props: { post: { id: 1, title: 'First post', text: 'Hello, world!' } }
    })
 
    expect(wrapper.text()).toContain('First post')
  })
})

The test renders a card with a post and checks that the title is in its text. If you accidentally delete {{ post.title }} from the PostCard.vue template, the test fails and shows what is missing.

Kinds of tests

KindWhat it checksWith
UnitOne functionVitest
ComponentOne componentVitest and mountSuspended
End-to-endThe whole site in a real browser@nuxt/test-utils/e2e and Playwright

End-to-end tests build the app, start a server and open pages, so they are slower. Start with unit and component tests.

Common mistake

Rendering a Nuxt component with the plain mount function from @vue/test-utils, or running tests without environment: 'nuxt'. Auto-imports do not work then, and the test fails with errors like useLikes is not defined, even though the app works. For Nuxt components use mountSuspended and the nuxt environment.

Thanks for reading!

Donate to the site — we work hard for you.