Foundation for the upcoming component / integration / a11y tests.
vitest.config.ts now declares two projects:
- "unit" — pure-logic tests under tests/unit/, src/**/__tests__/,
and tests/*.spec.ts (the legacy sanity test).
happy-dom, no Vuetify, fast path.
- "component" — tests under tests/component/, tests/integration/,
tests/a11y/. jsdom, Vuetify inlined via SSR noExternal,
CSS imports processed (so :root token sheet loads), and
no global vue-router mock so the real router can run.
Both share the same alias map and AutoImport bag.
tests/utils/mountWithVuexy.ts (new):
- Real Vuetify with the Crewli theme tokens
- createTestingPinia (actions execute by default; stubActions opt-in)
- vue-router with memory history at the configured initialPath + ?query
- Fresh QueryClient per call (zero cross-test cache leak)
- Notification mock injected via Pinia plugin so any useNotificationStore()
resolves to { show: vi.fn(), hide: vi.fn() } — matches the actual
NotificationStore API surface (per Phase A finding A4)
- Imports `@/styles/tokens/_timetable.css` at module load so JSDOM resolves
var(--tt-…) when components call getComputedStyle()
tests/setup.component.ts (new):
- vitest-axe matcher registration
- JSDOM polyfills: scrollIntoView, ResizeObserver, visualViewport, body
bounding rect — Vuetify menus / overlays would crash without them
- Deterministic crypto polyfill (mirrors tests/setup.ts so
generateIdempotencyKey() is stable, but without the router mock)
tests/component/_smoke.test.ts (new):
- Mounts a trivial component → asserts wrapper, queryClient, pinia,
router, notificationMock all populated
- Calls getComputedStyle(documentElement).getPropertyValue('--tt-status-confirmed-bg')
→ asserts '#e8f8f0' (proves the CSS token sheet really loaded)
devDependencies added: jsdom, axe-core, vitest-axe, @pinia/testing.
Total: 319 → 321 tests; 42 → 43 files. Both projects green.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
85 lines
3.0 KiB
TypeScript
85 lines
3.0 KiB
TypeScript
import { fileURLToPath } from 'node:url'
|
|
import vue from '@vitejs/plugin-vue'
|
|
import AutoImport from 'unplugin-auto-import/vite'
|
|
import { defineConfig } from 'vitest/config'
|
|
|
|
// Two projects share one config:
|
|
//
|
|
// - "unit" — pure-logic tests under tests/unit/ + src/**/__tests__/.
|
|
// No Vuetify, no SCSS plugin, happy-dom only. Fast path.
|
|
// - "component" — component / integration / a11y tests under tests/component/,
|
|
// tests/integration/, tests/a11y/. Loads CSS imports so
|
|
// `import '@/styles/tokens/_timetable.css'` resolves and
|
|
// getComputedStyle() returns var(--tt-…) values in jsdom.
|
|
//
|
|
// Both share the same alias map and AutoImport bag so test paths and the
|
|
// auto-imported `ref/computed/watch` etc. work identically.
|
|
const sharedAliases = {
|
|
'@': fileURLToPath(new URL('./src', import.meta.url)),
|
|
'@core': fileURLToPath(new URL('./src/@core', import.meta.url)),
|
|
'@layouts': fileURLToPath(new URL('./src/@layouts', import.meta.url)),
|
|
'@images': fileURLToPath(new URL('./src/assets/images/', import.meta.url)),
|
|
'@styles': fileURLToPath(new URL('./src/assets/styles/', import.meta.url)),
|
|
}
|
|
|
|
const sharedAutoImport = AutoImport({
|
|
imports: ['vue', '@vueuse/core'],
|
|
dirs: ['./src/@core/utils', './src/@core/composable/', './src/composables/', './src/utils/'],
|
|
vueTemplate: true,
|
|
dts: false,
|
|
})
|
|
|
|
export default defineConfig({
|
|
test: {
|
|
projects: [
|
|
{
|
|
plugins: [vue(), sharedAutoImport],
|
|
resolve: { alias: sharedAliases },
|
|
test: {
|
|
name: 'unit',
|
|
environment: 'happy-dom',
|
|
globals: true,
|
|
include: [
|
|
'tests/unit/**/*.{test,spec}.ts',
|
|
'tests/*.{test,spec}.ts',
|
|
'src/**/__tests__/**/*.{test,spec}.ts',
|
|
],
|
|
setupFiles: ['./tests/setup.ts'],
|
|
},
|
|
},
|
|
{
|
|
plugins: [vue(), sharedAutoImport],
|
|
resolve: { alias: sharedAliases },
|
|
|
|
// Inline Vuetify so its ESM bits are processed by Vite's transform.
|
|
ssr: { noExternal: ['vuetify'] },
|
|
test: {
|
|
name: 'component',
|
|
environment: 'jsdom',
|
|
globals: true,
|
|
include: [
|
|
'tests/component/**/*.{test,spec}.ts',
|
|
'tests/integration/**/*.{test,spec}.ts',
|
|
'tests/a11y/**/*.{test,spec}.ts',
|
|
],
|
|
|
|
// Intentionally NOT including ./tests/setup.ts — it stubs `vue-router`
|
|
// globally for the unit project, which would defeat the real router
|
|
// wired by mountWithVuexy. setup.component.ts handles its own
|
|
// crypto/JSDOM stubs.
|
|
setupFiles: ['./tests/setup.component.ts'],
|
|
|
|
// CSS @import statements (e.g. `@/styles/tokens/_timetable.css`)
|
|
// need to actually load so getComputedStyle resolves CSS variables.
|
|
css: true,
|
|
server: {
|
|
deps: {
|
|
inline: ['vuetify'],
|
|
},
|
|
},
|
|
},
|
|
},
|
|
],
|
|
},
|
|
})
|