Plan 2.5 final phase (P8). Closes the PrimeVue shell-migration workstream. - RFC-WS-PRIMEVUE-PLAN-2-5: added Supersessions section recording the governing-RFC divergences (§4 dark mode `<body>`→`<html>` per AD-2.5-D1; §7.4 workspace sub option A reversed to placeholder after visual review). Added closure summary (phases, ADs, brand-square recipe, suite delta, lessons). Status → COMPLETE. - BACKLOG: landed 8 items surfaced during Plan 2.5 (MOBILE-SHELL-PARITY, WORKSPACE-DROPDOWN-SUB-CONTENT, DENSITY-AWARE-SPACING, TOPBAR-H-VAR- DECLARE, CSP-FONT-SRC-LOCKDOWN, AUTO-IMPORTS-V2-SCAN, PNPM-RESOLUTIONS- ROOT, SHELLUI-STALE-DATA-THEME-CLEANUP). Marked GRADIENT-BRAND- ALIGNMENT as resolved. - useShellUiStore.toggleDensity: removed redundant applyDomAttributes() call (the AppShellV2 watch already covers density changes). Moved the DOM-write assertion to AppShellV2 watcher-coverage specs. Plan 2.5 status: COMPLETE. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
71 lines
2.9 KiB
TypeScript
71 lines
2.9 KiB
TypeScript
import { describe, expect, it, vi } from 'vitest'
|
|
import { mount } from '@vue/test-utils'
|
|
import { createPinia } from 'pinia'
|
|
import AppShellV2 from '@/layouts/components/AppShellV2.vue'
|
|
|
|
describe('AppShellV2 (skeleton)', () => {
|
|
it('renders the grid regions and default slot content', () => {
|
|
const wrapper = mount(AppShellV2, {
|
|
global: { plugins: [createPinia()] },
|
|
slots: {
|
|
sidebar: '<nav data-testid="sb">SB</nav>',
|
|
topbar: '<header data-testid="tb">TB</header>',
|
|
default: '<main data-testid="content">CONTENT</main>',
|
|
drawer: '<aside data-testid="dr">DR</aside>',
|
|
},
|
|
})
|
|
|
|
expect(wrapper.find('[data-testid="appshell-v2"]').exists()).toBe(true)
|
|
expect(wrapper.find('[data-testid="sb"]').exists()).toBe(true)
|
|
expect(wrapper.find('[data-testid="tb"]').exists()).toBe(true)
|
|
expect(wrapper.find('[data-testid="content"]').text()).toBe('CONTENT')
|
|
expect(wrapper.find('[data-testid="dr"]').exists()).toBe(true)
|
|
})
|
|
|
|
it('applies the collapsed modifier from useShellUiStore', async () => {
|
|
const pinia = createPinia()
|
|
const wrapper = mount(AppShellV2, { global: { plugins: [pinia] } })
|
|
const { useShellUiStore } = await import('@/stores/useShellUiStore')
|
|
|
|
useShellUiStore().toggleSidebar()
|
|
await wrapper.vm.$nextTick()
|
|
expect(wrapper.find('[data-testid="appshell-v2"]').classes()).toContain('is-collapsed')
|
|
})
|
|
|
|
// Plan 2.5 P8 dedupe — AppShellV2's watch([theme, density]) is the single
|
|
// applyDomAttributes() authority. toggleDensity() (useShellUiStore) no longer
|
|
// writes the DOM itself; the watch covers it. These specs lock that contract:
|
|
// the density change reaches <html> via the watch, and exactly one
|
|
// applyDomAttributes() call fires per toggle (no redundant double-call).
|
|
it('watch writes the toggled density to <html data-density>', async () => {
|
|
document.documentElement.removeAttribute('data-density')
|
|
|
|
const pinia = createPinia()
|
|
const wrapper = mount(AppShellV2, { global: { plugins: [pinia] } })
|
|
const { useShellUiStore } = await import('@/stores/useShellUiStore')
|
|
const shell = useShellUiStore()
|
|
|
|
// onMounted seeded the comfortable default.
|
|
expect(document.documentElement.getAttribute('data-density')).toBe('comfortable')
|
|
|
|
shell.toggleDensity()
|
|
await wrapper.vm.$nextTick()
|
|
expect(document.documentElement.getAttribute('data-density')).toBe('compact')
|
|
})
|
|
|
|
it('density toggle fires applyDomAttributes exactly once (via the watch, not toggleDensity)', async () => {
|
|
const pinia = createPinia()
|
|
const wrapper = mount(AppShellV2, { global: { plugins: [pinia] } })
|
|
const { useShellUiStore } = await import('@/stores/useShellUiStore')
|
|
const shell = useShellUiStore()
|
|
|
|
// Spy AFTER mount so the onMounted seed call is excluded from the count.
|
|
const spy = vi.spyOn(shell, 'applyDomAttributes')
|
|
|
|
shell.toggleDensity()
|
|
await wrapper.vm.$nextTick()
|
|
|
|
expect(spy).toHaveBeenCalledTimes(1)
|
|
})
|
|
})
|