/** * Phase 0 smoke spec: mounts the host plugin against a minimal fake context, * verifies the plugin export shape (no stray default, so the cordis Loader * keeps name/inject/apply), and exercises the invariant surface. Runs with * `pnpm test`. * * The client half (lib/client.js closure factory) is a browser artifact — it * registers tabs into the better-sidebar host registry at runtime, which * needs a live DSH shell. The client registration contract is therefore * covered by a focused unit spec (locales) + the build's purity gate; a full * mount smoke (cordis scratch profile) lands in Phase 1 with the real tabs. */ import { describe, expect, it } from 'vitest' import * as host from '../src/index.ts' import { InvariantError, assert, assertBetterSidebarPeer, compareSemver, } from '../src/invariant.ts' /** * Run the real namespace export through `Loader.unwrapExports`; a stray * default would discard `name`, `inject`, and `apply`. Same guard the * official plugin repos ship. */ describe('apes-sidebar host plugin shape', () => { it('has the namespace-plugin export shape (no stray default)', () => { expect('default' in host).toBe(false) expect(typeof host.apply).toBe('function') expect(host.name).toBe('apes-sidebar') expect(host.inject).toEqual(['logger']) }) it('apply mounts a logger line through the effect (Phase 0 minimal)', () => { const logs: string[] = [] let effects = 0 const ctx = { logger: { info: (msg: string) => logs.push(msg) }, effect: (fn: () => void | (() => void)) => { effects += 1 const cleanup = fn() return () => { if (typeof cleanup === 'function') cleanup() } }, } host.apply(ctx as never) expect(effects).toBe(1) expect(logs).toEqual(['[apes-sidebar] host half mounted (Phase 0 skeleton)']) }) it('apply survives a missing logger (degrades, never throws)', () => { let effects = 0 const ctx = { effect: (fn: () => void | (() => void)) => { effects += 1 fn() }, } expect(() => host.apply(ctx as never)).not.toThrow() expect(effects).toBe(1) }) it('apply without an effect API still runs once synchronously', () => { const logs: string[] = [] const ctx = { logger: { info: (msg: string) => logs.push(msg) } } host.apply(ctx as never) expect(logs).toEqual(['[apes-sidebar] host half mounted (Phase 0 skeleton)']) }) }) describe('apes-sidebar invariant surface', () => { it('assert throws an InvariantError on a falsy condition', () => { expect(() => assert(false, 'boom')).toThrow(InvariantError) expect(() => assert(false, 'boom')).toThrow('boom') // A truthy condition passes silently. expect(() => assert(true, 'ok')).not.toThrow() expect(() => assert(1, 'ok')).not.toThrow() }) it('compareSemver orders versions (numeric + rc prerelease)', () => { expect(compareSemver('0.17.9', '0.18.0')).toBeLessThan(0) expect(compareSemver('0.18.0', '0.18.0')).toBe(0) expect(compareSemver('0.19.0', '0.18.0')).toBeGreaterThan(0) expect(compareSemver('1.0.0', '0.99.99')).toBeGreaterThan(0) // Prerelease sorts below the release it qualifies. expect(compareSemver('0.18.0-rc.1', '0.18.0')).toBeLessThan(0) expect(compareSemver('0.18.0-rc.1', '0.18.0-rc.2')).toBeLessThan(0) }) it('assertBetterSidebarPeer warns on an old peer (no logger → no throw)', () => { const warnings: string[] = [] const warn = (msg: string) => warnings.push(msg) // An old peer (0.17.x) triggers a warn. ;(globalThis as Record).__apesPeer__ = { version: '0.17.9' } assertBetterSidebarPeer({ warn }) expect(warnings).toHaveLength(1) expect(warnings[0]).toContain('0.17.9') // A new peer (0.18.x) does not. warnings.length = 0 ;(globalThis as Record).__apesPeer__ = { version: '0.18.0' } assertBetterSidebarPeer({ warn }) expect(warnings).toHaveLength(0) // No logger at all: still no throw. ;(globalThis as Record).__apesPeer__ = { version: '0.17.0' } expect(() => assertBetterSidebarPeer(undefined)).not.toThrow() delete (globalThis as Record).__apesPeer__ }) })