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>
39 lines
1.3 KiB
TypeScript
39 lines
1.3 KiB
TypeScript
import { describe, expect, it } from 'vitest'
|
|
import { defineComponent, h } from 'vue'
|
|
import { mountWithVuexy } from '../utils/mountWithVuexy'
|
|
|
|
describe('mountWithVuexy harness', () => {
|
|
it('mounts a trivial component with the full Vuexy stack', () => {
|
|
const Trivial = defineComponent({
|
|
setup() {
|
|
return () => h('div', { 'data-test': 'ok' }, 'hello')
|
|
},
|
|
})
|
|
|
|
const { wrapper, queryClient, pinia, router, notificationMock } = mountWithVuexy(Trivial)
|
|
|
|
expect(wrapper.find('[data-test="ok"]').text()).toBe('hello')
|
|
expect(queryClient).toBeDefined()
|
|
expect(pinia).toBeDefined()
|
|
expect(router).toBeDefined()
|
|
expect(notificationMock.show).toBeTypeOf('function')
|
|
})
|
|
|
|
it('loads the timetable CSS token sheet so var(--tt-…) resolves on :root', () => {
|
|
const Probe = defineComponent({
|
|
setup() {
|
|
return () => h('div', { id: 'probe' })
|
|
},
|
|
})
|
|
|
|
mountWithVuexy(Probe)
|
|
|
|
// The CSS file is imported at module load time inside mountWithVuexy.
|
|
// Resolving against documentElement (=:root) avoids ambiguity around
|
|
// jsdom's default style-cascade behaviour on arbitrary elements.
|
|
const value = getComputedStyle(document.documentElement).getPropertyValue('--tt-status-confirmed-bg').trim()
|
|
|
|
expect(value).toBe('#e8f8f0')
|
|
})
|
|
})
|