Testing
The Vue Quasar playground uses Vitest with the Vue Vite plugin so .vue SFC files are compiled at test time. Tests run in a plain Node environment — no browser required.
Install dev dependencies
bash
pnpm add -D vitest @vitest/coverage-v8 @vitejs/plugin-vueConfigure Vitest
Create a vitest.config.mts with the Vue plugin, @ alias, and a setup file:
typescript
// vitest.config.mts
import { defineConfig } from 'vitest/config'
import vue from '@vitejs/plugin-vue'
import { resolve } from 'path'
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
'@': resolve(__dirname, './src'),
},
},
test: {
environment: 'node',
include: ['tests/**/*.test.{ts,tsx}'],
setupFiles: ['tests/setup.ts'],
coverage: {
reportsDirectory: 'tests/.coverage',
include: ['src/**'],
},
},
})vue() compiles .vue single-file components during test transforms. The @ alias maps to ./src for cleaner imports.
Mock strategy
Global setup
The setup file mocks @ybyra/persistence/web globally since createWebDriver uses localStorage:
typescript
// tests/setup.ts
import { vi } from 'vitest'
vi.mock('@ybyra/persistence/web', () => ({
createWebDriver: vi.fn(() => ({
initialize: vi.fn(),
create: vi.fn(),
read: vi.fn(),
update: vi.fn(),
destroy: vi.fn(),
search: vi.fn(),
})),
}))Page mocks
Page components depend on vue-router, vue-i18n, and quasar. A shared tests/pages/mocks.ts stubs them:
typescript
// tests/pages/mocks.ts
import { vi } from 'vitest'
vi.mock('vue-router', () => ({
useRouter: vi.fn(() => ({
push: vi.fn(),
back: vi.fn(),
replace: vi.fn(),
})),
useRoute: vi.fn(() => ({
params: { id: '1' },
path: '/person',
})),
createRouter: vi.fn(() => ({
push: vi.fn(),
back: vi.fn(),
replace: vi.fn(),
install: vi.fn(),
})),
createWebHistory: vi.fn(),
}))
vi.mock('vue-i18n', () => ({
useI18n: vi.fn(() => ({
t: (key: string) => key,
te: (key: string) => key.startsWith('person.') || key.startsWith('common.'),
})),
createI18n: vi.fn(() => ({
global: { t: (key: string) => key, te: () => true },
install: vi.fn(),
})),
}))
vi.mock('quasar', () => ({
Notify: { create: vi.fn() },
Dialog: { create: vi.fn() },
Loading: { show: vi.fn(), hide: vi.fn() },
QCard: { name: 'QCard', template: '<div><slot /></div>' },
QCardSection: { name: 'QCardSection', template: '<div><slot /></div>' },
QLayout: { name: 'QLayout', template: '<div><slot /></div>' },
QPageContainer: { name: 'QPageContainer', template: '<div><slot /></div>' },
}))Each page test imports '../mocks' before any source imports.
Testing pages
Vue SFC components export an object with a setup function. Page tests verify both:
typescript
// tests/pages/person/add.test.ts
import '../mocks'
import { describe, it, expect } from 'vitest'
describe('pages/PersonAdd', () => {
it('exports default component', async () => {
const { default: PersonAdd } = await import('../../../src/pages/PersonAdd.vue')
expect(PersonAdd).toBeDefined()
})
it('has a setup function', async () => {
const { default: PersonAdd } = await import('../../../src/pages/PersonAdd.vue')
expect(PersonAdd.setup).toBeTypeOf('function')
})
})The same pattern applies to list, view, and edit pages.
Running tests
bash
pnpm test # run all tests
pnpm test -- --coverage # run with coverage reportTest structure
tests/
setup.ts
src/
settings/
i18n.test.ts
icons.test.ts
application/service/
personService.test.ts
domain/person/
schema.test.ts
events.test.ts
handlers.test.ts
hooks.test.ts
routes/
router.test.ts
pages/
mocks.ts
person/
list.test.ts
add.test.ts
view.test.ts
edit.test.ts