docling-studio/frontend/src/shared/ui/navActive.test.ts
Pier-Jean Malandrino 9d4d53b9e0 feat(#209): rework sidebar nav (Home / Docs / Stores / Runs / Settings)
The sidebar was the project's actual nav (the design doc called it
'top nav' but the existing app is sidebar-driven). Five entries
reflecting the doc-centric IA replace the seven analysis-centric ones.

Sidebar
- shared/ui/AppSidebar.vue: data-driven over a NavItem[] table
  instead of seven hard-coded RouterLinks. Inline SVG icon
  components keep the visual weight close to the previous version
  with no new dependency.
- Five entries: Home / Docs (★ primary, bolder label) / Stores /
  Runs / Settings.
- Active state via matchesActive(path, prefixes): exact match for
  Home, prefix match (with segment / query boundary) for the others.
  Pure helper in shared/ui/navActive.ts, unit tested.

Removed from the sidebar (legacy pages still reachable by URL):
  Studio, Documents, Search, Reasoning, History.

i18n
- nav.docs / nav.stores / nav.runs added in fr + en, grouped under
  the 0.6.0 nav block.
- Legacy nav labels (nav.studio / nav.documents / nav.history /
  nav.reasoning / nav.search) kept — the legacy pages still render
  headings using them. Duplicate nav.search entries removed (the key
  now lives once per locale, in the nav block).

Tests
- shared/ui/navActive.test.ts (5 cases): exact-match for Home,
  prefix boundary semantics, multi-prefix matching, empty list edge.

Refs #209
2026-04-29 17:53:23 +02:00

33 lines
1.3 KiB
TypeScript

import { describe, expect, it } from 'vitest'
import { matchesActive } from './navActive'
describe('matchesActive', () => {
it('matches Home only on the exact / path', () => {
expect(matchesActive('/', ['/'])).toBe(true)
expect(matchesActive('/docs', ['/'])).toBe(false)
expect(matchesActive('/anything', ['/'])).toBe(false)
})
it('matches a non-root prefix on exact, segment, and query boundaries', () => {
expect(matchesActive('/docs', ['/docs'])).toBe(true)
expect(matchesActive('/docs/abc', ['/docs'])).toBe(true)
expect(matchesActive('/docs/abc/123', ['/docs'])).toBe(true)
expect(matchesActive('/docs?foo=bar', ['/docs'])).toBe(true)
})
it('does not match prefixes that are part of a longer segment', () => {
expect(matchesActive('/documents', ['/docs'])).toBe(false)
expect(matchesActive('/docsy', ['/docs'])).toBe(false)
})
it('returns true if any prefix in the list matches', () => {
expect(matchesActive('/runs/abc', ['/index', '/runs'])).toBe(true)
expect(matchesActive('/index/foo/query', ['/index', '/runs'])).toBe(true)
expect(matchesActive('/somewhere-else', ['/index', '/runs'])).toBe(false)
})
it('returns false on empty prefix list', () => {
expect(matchesActive('/docs', [])).toBe(false)
})
})