Files
apes-sidebar/tests/apes-tabs.spec.ts
T
figmar a6dd8aa42a fix(test): add missing devDeps + sourcemap transform + jsdom directives
WorkBuddy review found 38 of 131 spec files failed at collection time
(0 tests executed) — the '1015 passed' was a false green because vitest
only counts 'Tests failed', not 'Test Files failed'.

Root cause: dsh-client-ui-primitives@0.2.0-rc.2 declares dependencies:null
but statically imports 23 external root packages. Our project declared
only 18. Under pnpm strict layout, the missing 5 (dsh-client-store,
dsh-util-code-language, dsh-util-workspace-path, diff, simple-icons)
were unresolvable when Vite inlined the primitives package.

Fixes:
- Add 7 missing devDeps: dsh-client-store@0.2.0-rc.2,
  dsh-util-code-language@0.2.0-rc.2, dsh-util-workspace-path@0.2.0-rc.2,
  diff@9.0.0, simple-icons@16.35.0, zustand@5.0.15, immer@11.1.21
- vitest.config.ts: add transform plugin to strip sourceMappingURL
  comments from dsh-client-ui-primitives (upstream ships lib/index.js
  with trailing sourceMappingURL but package.json files excludes .map)
- 5 spec files: add @vitest-environment jsdom directive (they import
  dsh-client-ui-primitives which calls window.addEventListener at module
  load; node environment lacks window)
- Remove empty .map file hack from node_modules (ineffective + .gitignore
  blocks it from version control)

Result: Test Files 131 passed (131), Tests 1367 passed | 9 skipped,
EXIT=0.

Verified: simple-icons 25 named exports all present.
Typecheck + build pass.
2026-10-11 19:33:01 +08:00

124 lines
4.7 KiB
TypeScript

// @vitest-environment jsdom
/**
* apes:* tab registration tests (Phase 1/1b, C6: 3 tabs). The fork registers
* its three information-layer tabs (agents / apps / profile) through the same
* BetterSidebarService the upstream builtins use (dogfood). `apes:tasks` was
* removed in C6 — it overlaps the official DSH session tree in the native
* sidebar. The spec pins the registration contract (id / single / order /
* component presence) and the isolated i18n contract (the apes namespace
* resolves zh vs en through the attached locale service, and every apesZh
* key has an apesEn entry).
*
* Runs in the node vitest environment like builtins.spec.ts — no DOM, no
* real DSH host (a live cordis scratch mount is Phase 2+).
*/
import { describe, expect, it } from 'vitest'
// Browser globals before the client graph loads (mirror of builtins.spec.ts).
import './browser-globals.ts'
import type { Context } from '../src/context-types.ts'
import { createBetterSidebarService } from '../src/client/service.ts'
import { createSidebarStore } from '../src/client/state.ts'
import { registerApesTabs } from '../src/client/apes/index.ts'
import { apesZh, apesEn, attachApesLocale, t, type ApesCopyKey } from '../src/client/apes/locales.ts'
function setup(): {
service: ReturnType<typeof createBetterSidebarService>
store: ReturnType<typeof createSidebarStore>
dispose: () => void
} {
const store = createSidebarStore()
const service = createBetterSidebarService(store)
const dispose = registerApesTabs({} as Context, service)
return { service, store, dispose }
}
describe('apes:* tab registrations', () => {
it('registers the 3 apes tabs with the apes: namespace', () => {
const { service, dispose } = setup()
try {
expect(service.getTabs().map(t => t.id).sort()).toEqual(
['apes:agents', 'apes:apps', 'apes:profile'],
)
} finally {
dispose()
}
})
it('every apes tab is single-instance, visible, and component-carrying', () => {
const { service, dispose } = setup()
try {
for (const id of ['apes:agents', 'apes:apps', 'apes:profile']) {
const tab = service.getTab(id)
expect(tab, `${id} registered`).toBeDefined()
expect(tab?.single, `${id} single`).toBe(true)
expect(tab?.hidden, `${id} hidden`).not.toBe(true)
expect(tab?.component, `${id} component`).toBeDefined()
expect(tab?.icon, `${id} icon`).toBeDefined()
}
} finally {
dispose()
}
})
it('apes tabs sort after the upstream builtins (order 40+)', () => {
const { service, dispose } = setup()
try {
const orders = {
agents: service.getTab('apes:agents')?.order,
apps: service.getTab('apes:apps')?.order,
profile: service.getTab('apes:profile')?.order,
}
// C8: order 40-50 places apes tabs immediately after the native builtins
// (10-35), not in a far-away 900+ band — visual unity in the tab strip.
expect(orders.agents).toBeGreaterThanOrEqual(40)
expect(orders.apps).toBeGreaterThanOrEqual(40)
expect(orders.profile).toBeGreaterThanOrEqual(40)
// Strictly ordered: agents < apps < profile.
expect(orders.agents!).toBeLessThan(orders.apps!)
expect(orders.apps!).toBeLessThan(orders.profile!)
} finally {
dispose()
}
})
it('the disposer unregisters all apes tabs (HMR-safe)', () => {
const store = createSidebarStore()
const service = createBetterSidebarService(store)
const dispose = registerApesTabs({} as Context, service)
expect(service.getTabs()).toHaveLength(3)
dispose()
expect(service.getTabs()).toHaveLength(0)
})
})
describe('apes i18n contract', () => {
it('every apesZh key has an apesEn entry (no missing translations)', () => {
const zhKeys = Object.keys(apesZh) as ApesCopyKey[]
for (const key of zhKeys) {
expect(apesEn[key], `en entry for ${key}`).toBeDefined()
expect(typeof apesEn[key]).toBe('string')
expect((apesEn[key] ?? '').length).toBeGreaterThan(0)
}
})
it('resolves zh when the DSH preference is zh', () => {
attachApesLocale({ getSnapshot: () => ({ active: 'zh-CN' }) })
expect(t('apesAgentsTitle')).toBe('智能体')
expect(t('apesAppsTitle')).toBe('应用')
expect(t('apesProfileTitle')).toBe('画像')
})
it('resolves en when the DSH preference is en', () => {
attachApesLocale({ getSnapshot: () => ({ active: 'en' }) })
expect(t('apesAgentsTitle')).toBe('Agents')
expect(t('apesAppsTitle')).toBe('Apps')
expect(t('apesProfileTitle')).toBe('Profile')
})
it('falls back to zh when no locale service is attached', () => {
attachApesLocale(undefined)
expect(t('apesAgentsTitle')).toBe('智能体')
})
})