Testing

How to write and run tests with Vitest and Vue Test Utils.

Testing Approach

Haze Dashboard uses Vitest for unit and component testing, combined with Vue Test Utils for mounting and interacting with Vue components. Vitest is Vite-native, so it shares the same configuration and plugin pipeline as your dev server — tests run fast and resolve path aliases automatically.

Tests live alongside the code they test or in a dedicated tests/ directory. Use the .test.ts or .spec.ts file extension.

Setup

Install the testing dependencies:

bash
npm install -D vitest @vue/test-utils @vitejs/plugin-vue happy-dom

Create a vitest.config.ts at the project root:

typescript
// vitest.config.ts
import { defineConfig } from 'vitest/config'
import vue from '@vitejs/plugin-vue'
import { resolve } from 'path'

export default defineConfig({
  plugins: [vue()],
  test: {
    environment: 'happy-dom',
    globals: true,
    include: ['tests/**/*.test.ts', 'app/**/*.test.ts'],
  },
  resolve: {
    alias: {
      '~': resolve(__dirname, 'app'),
      '#imports': resolve(__dirname, '.nuxt/imports.d.ts'),
    },
  },
})

Writing a Component Test

Test that a component renders correctly with given props and responds to user interaction:

typescript
// tests/components/StatusBadge.test.ts
import { describe, it, expect } from 'vitest'
import { mount } from '@vue/test-utils'
import StatusBadge from '~/components/shared/StatusBadge.vue'

describe('SharedStatusBadge', () => {
  it('renders the status text', () => {
    const wrapper = mount(StatusBadge, {
      props: { status: 'active' },
    })
    expect(wrapper.text()).toContain('active')
  })

  it('applies success color for completed status', () => {
    const wrapper = mount(StatusBadge, {
      props: { status: 'completed' },
    })
    expect(wrapper.html()).toContain('success')
  })

  it('applies error color for cancelled status', () => {
    const wrapper = mount(StatusBadge, {
      props: { status: 'cancelled' },
    })
    expect(wrapper.html()).toContain('error')
  })
})

Writing a Page Test

Page tests verify that a page component renders its main elements. Since pages may use auto-imported composables and components, you may need to provide stubs:

typescript
// tests/pages/Dashboard.test.ts
import { describe, it, expect } from 'vitest'
import { mount } from '@vue/test-utils'
import DashboardPage from '~/pages/dashboard/index.vue'

describe('Dashboard Page', () => {
  it('renders the page heading', () => {
    const wrapper = mount(DashboardPage, {
      global: {
        stubs: {
          SharedPageHeader: {
            template: '
', props: ['title'], }, SharedGlassCard: { template: '
', }, ClientOnly: { template: '
', }, }, }, }) expect(wrapper.html()).toBeTruthy() }) })

Testing Composables

Test composables by calling them within a Vue component context. Use a small wrapper component or withSetup helper:

typescript
// tests/composables/useThemeSettings.test.ts
import { describe, it, expect, beforeEach } from 'vitest'

describe('useThemeSettings', () => {
  beforeEach(() => {
    localStorage.clear()
  })

  it('returns default settings', () => {
    // Note: testing composables that use useLocalStorage
    // requires the happy-dom environment
    const settings = {
      accentColor: 'teal',
      density: 'default',
      rtl: false,
    }
    expect(settings.accentColor).toBe('teal')
    expect(settings.density).toBe('default')
    expect(settings.rtl).toBe(false)
  })

  it('persists accent color changes', () => {
    localStorage.setItem('haze-theme', JSON.stringify({
      accentColor: 'blue',
      density: 'default',
      rtl: false,
    }))
    const stored = JSON.parse(localStorage.getItem('haze-theme')!)
    expect(stored.accentColor).toBe('blue')
  })
})

Running Tests

CommandDescription
npx vitestRun tests in watch mode (re-runs on file changes)
npx vitest runRun all tests once and exit (CI-friendly)
npx vitest --uiOpen the interactive Vitest UI in a browser
npx vitest --coverageGenerate code coverage report (requires @vitest/coverage-v8)
npx vitest run tests/components/Run tests in a specific directory

Mocking API Routes

Components that use useFetch can be tested by mocking the composable:

typescript
// tests/components/OrdersList.test.ts
import { describe, it, expect, vi } from 'vitest'
import { mount } from '@vue/test-utils'

// Mock useFetch globally
vi.mock('#imports', () => ({
  useFetch: vi.fn(() => ({
    data: ref({
      data: [
        { id: 1, orderNumber: 'ORD-001', status: 'active' },
        { id: 2, orderNumber: 'ORD-002', status: 'pending' },
      ],
      meta: { total: 2, page: 1, perPage: 10, lastPage: 1 },
    }),
    pending: ref(false),
    error: ref(null),
  })),
  ref: (v: any) => ({ value: v }),
}))

Tip

Mock server routes with vi.mock() for API-dependent components. For simpler components that only take props, you can test them directly without mocking.

Next Steps

Ready to go live? See the Deployment guide for step-by-step instructions on deploying to Vercel, Netlify, Cloudflare Pages, or a Node.js server.