Files
crewli/apps/app/src/composables/__tests__/useV2Nav.spec.ts
bert.hausmans 8444ea7443 fix(gui-v2): SidebarNav uses RouterLink (a11y) + review-nit cleanup
- FIX 1: Replace <button @click="router.push"> with <RouterLink custom>
  + <a> for real link semantics (middle-click, ⌘-click, screen-reader);
  custom isNavItemActive prefix-match stays the active source of truth;
  adds :aria-current="page" on active items; drops useRouter/router.push.
  RouterLink to prop cast via itemTo() helper (RouteLocationRaw from
  unplugin-vue-router) to satisfy typed RouterLinkTyped<RouteNamedMap>.
- FIX 2: Align .nav-item comment to actual template values (py-[9px]
  rounded-md, not CSS vars); replace inaccurate Tailwind v3/v4 before:
  composability justification in <style scoped> with the real reason
  (accent bar at left:-10px is clipped by the overflow-y-auto nav).
- FIX 3: text-left → text-start (logical property, RTL-safe).
- FIX 4: Document id=route-name assumption in useV2Nav.ts with a
  one-line comment at the id: assignment.
- FIX 5: Reword misleading "dotted names" spec description to state
  the real invariant (id = v1 route name, already kebab-case).
- FIX 6: Add 2 tests — useV2Nav wrapper .value equality, and
  consecutive-headings edge case (empty-items group produced).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-16 19:39:56 +02:00

102 lines
3.2 KiB
TypeScript

import { describe, expect, it } from 'vitest'
import { toV2NavGroups, useV2Nav } from '@/composables/useV2Nav'
import type { V2NavItem } from '@/types/v2/nav'
// Hand-built fixture — does NOT depend on the real orgNavItems contents.
const fixture = [
{ title: 'Alpha', to: { name: 'alpha' }, icon: { icon: 'tabler-home' } },
{ title: 'Beta', to: { name: 'beta' }, icon: { icon: 'tabler-bell' } },
{ heading: 'Group One' },
{ title: 'Gamma', to: { name: 'gamma' }, icon: { icon: 'tabler-star' }, count: 5 },
{ heading: 'Group Two' },
{ title: 'Delta', to: { name: 'delta' }, icon: { icon: 'tabler-settings' } },
] as const
describe('toV2NavGroups', () => {
it('places items before the first heading into a leading group with label ""', () => {
const groups = toV2NavGroups(fixture)
expect(groups[0].label).toBe('')
expect(groups[0].items).toHaveLength(2)
})
it('starts a new group when a heading entry is encountered', () => {
const groups = toV2NavGroups(fixture)
expect(groups).toHaveLength(3)
expect(groups[1].label).toBe('Group One')
expect(groups[2].label).toBe('Group Two')
})
it('maps item fields correctly: id, label, icon, to', () => {
const groups = toV2NavGroups(fixture)
const alpha = groups[0].items[0] as V2NavItem
expect(alpha.id).toBe('alpha')
expect(alpha.label).toBe('Alpha')
expect(alpha.icon).toBe('tabler-home')
expect(alpha.to).toEqual({ name: 'alpha' })
})
it('passes count through when present', () => {
const groups = toV2NavGroups(fixture)
const gamma = groups[1].items[0] as V2NavItem
expect(gamma.count).toBe(5)
})
it('leaves count undefined when absent', () => {
const groups = toV2NavGroups(fixture)
const alpha = groups[0].items[0] as V2NavItem
expect(alpha.count).toBeUndefined()
})
it('id equals the v1 route name (already kebab-case; no normalisation applied)', () => {
const groups = toV2NavGroups(fixture)
const delta = groups[2].items[0] as V2NavItem
expect(delta.id).toBe('delta')
})
it('returns empty groups array for an empty input', () => {
expect(toV2NavGroups([])).toEqual([])
})
it('items-only input (no headings) returns a single leading group', () => {
const onlyItems = [
{ title: 'A', to: { name: 'a' }, icon: { icon: 'tabler-a' } },
] as const
const groups = toV2NavGroups(onlyItems)
expect(groups).toHaveLength(1)
expect(groups[0].label).toBe('')
expect(groups[0].items).toHaveLength(1)
})
})
describe('useV2Nav', () => {
it('returns a computed whose .value equals toV2NavGroups(items)', () => {
const { groups } = useV2Nav(fixture)
expect(groups.value).toEqual(toV2NavGroups(fixture))
})
it('consecutive headings produce an empty-items group then the next group', () => {
const consecutiveHeadings = [
{ heading: 'First' },
{ heading: 'Second' },
{ title: 'Alpha', to: { name: 'alpha' }, icon: { icon: 'tabler-home' } },
] as const
const groups = toV2NavGroups(consecutiveHeadings)
expect(groups).toHaveLength(2)
expect(groups[0].label).toBe('First')
expect(groups[0].items).toHaveLength(0)
expect(groups[1].label).toBe('Second')
expect(groups[1].items).toHaveLength(1)
})
})