Testing Nuxt Applications
Building Confidence Through Tests
Testing ensures your application works as expected and prevents regressions. Nuxt apps can be tested at multiple levels.
Testing Pyramid
- Unit Tests - Test individual functions and composables
- Component Tests - Test Vue components in isolation
- E2E Tests - Test full user workflows
Unit Testing with Vitest
// composables/useCounter.test.ts
import { describe, expect, it } from 'vitest'
import { useCounter } from './useCounter'
describe('useCounter', () => {
it('increments count', () => {
const { count, increment } = useCounter()
expect(count.value).toBe(0)
increment()
expect(count.value).toBe(1)
})
})
Setup Vitest:
import vue from '@vitejs/plugin-vue'
// vitest.config.ts
import { defineConfig } from 'vitest/config'
export default defineConfig({
plugins: [vue()],
test: {
environment: 'jsdom',
},
})
Component Testing
// components/Counter.test.ts
import { mount } from '@vue/test-utils'
import { describe, expect, it } from 'vitest'
import Counter from './Counter.vue'
describe('Counter Component', () => {
it('renders count', () => {
const wrapper = mount(Counter, {
props: { initialValue: 5 }
})
expect(wrapper.text()).toContain('5')
})
it('increments on button click', async () => {
const wrapper = mount(Counter)
await wrapper.find('button').trigger('click')
expect(wrapper.emitted('update')).toBeTruthy()
})
})
E2E Testing with Playwright
// tests/e2e/homepage.spec.ts
import { expect, test } from '@playwright/test'
test('homepage loads correctly', async ({ page }) => {
await page.goto('http://localhost:3000')
await expect(page.getByRole('heading', { name: 'Welcome' })).toBeVisible()
})
test('navigation works', async ({ page }) => {
await page.goto('http://localhost:3000')
await page.click('text=About')
await expect(page).toHaveURL(/.*about/)
})
Testing Server Routes
import { $fetch, setup } from '@nuxt/test-utils'
// server/api/todos.test.ts
import { describe, expect, it } from 'vitest'
describe('Todos API', async () => {
await setup()
it('returns todos', async () => {
const todos = await $fetch('/api/todos')
expect(Array.isArray(todos)).toBe(true)
})
it('creates todo', async () => {
const newTodo = await $fetch('/api/todos', {
method: 'POST',
body: { title: 'Test' }
})
expect(newTodo.title).toBe('Test')
})
})
Testing Best Practices
- ✅ Write tests for critical paths
- ✅ Test business logic, not implementation details
- ✅ Use descriptive test names
- ✅ Keep tests isolated and independent
- ✅ Mock external dependencies
- ✅ Aim for good coverage, not 100%
- ✅ Run tests in CI/CD
Test Coverage
// package.json
{
"scripts": {
"test": "vitest",
"test:coverage": "vitest --coverage",
"test:e2e": "playwright test"
}
}
Testing is an investment that pays dividends. Start with critical paths, then expand coverage. Remember: some tests are better than no tests!