desktop coverage: every CLI command mapped to its window place (cli/lib/desktop-coverage.ts), docs/desktop-coverage.md generated from it, guard test fails on a gap or an unjustified not-for-desktop
This commit is contained in:
parent
a95aa6dd49
commit
dc6bb088a1
4 changed files with 371 additions and 0 deletions
44
tests/desktop-coverage.test.ts
Normal file
44
tests/desktop-coverage.test.ts
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
// Every CLI command is reachable in the desktop app, or listed as not for the desktop with a reason
|
||||
// (cli/lib/desktop-coverage.ts; the same analysis writes docs/desktop-coverage.md).
|
||||
import { describe, expect, test } from 'bun:test';
|
||||
import { readFileSync } from 'node:fs';
|
||||
import { join } from 'node:path';
|
||||
import { DESKTOP_COVERAGE, OWNER_STEPS, TOOLBOX } from '../cli/lib/desktop-coverage';
|
||||
import { describeMethods } from '../cli/serve';
|
||||
import { analyze, render } from '../tools/gen-desktop-coverage';
|
||||
|
||||
/** The only commands that make no sense in a window. Adding one here needs a reason in the coverage map. */
|
||||
const NOT_FOR_DESKTOP = ['mcp', 'serve', 'desktop', 'api'];
|
||||
|
||||
describe('desktop coverage', () => {
|
||||
const { rows, extra } = analyze();
|
||||
test('every CLI command has a desktop place (no gaps)', () => {
|
||||
expect(rows.filter(r => r.status === 'gap').map(r => `${r.command}: ${r.problems.join('; ')}`)).toEqual([]);
|
||||
expect(extra).toEqual([]);
|
||||
});
|
||||
test('not-for-desktop is short and each has a reason', () => {
|
||||
const not = rows.filter(r => r.status === 'not-for-desktop');
|
||||
expect(not.map(r => r.command).sort()).toEqual([...NOT_FOR_DESKTOP].sort());
|
||||
for (const r of not) expect(r.where.length).toBeGreaterThan(20);
|
||||
});
|
||||
test('the More tools tab offers no owner action and no unknown method', () => {
|
||||
const ms = new Map(describeMethods().map(m => [m.method, m] as const));
|
||||
for (const m of TOOLBOX.flatMap(g => g.methods)) {
|
||||
expect(ms.has(m)).toBe(true);
|
||||
expect(['read', 'write']).toContain(ms.get(m)!.kind);
|
||||
}
|
||||
for (const s of OWNER_STEPS) expect(s.command.startsWith('storebound ')).toBe(true);
|
||||
for (const [, c] of Object.entries(DESKTOP_COVERAGE)) if ('owner' in c && c.owner) expect(c.owner.length).toBeGreaterThan(2);
|
||||
});
|
||||
test('docs/desktop-coverage.md is generated and current', () => {
|
||||
expect(readFileSync(join(import.meta.dir, '../docs/desktop-coverage.md'), 'utf8')).toBe(render(rows));
|
||||
});
|
||||
test('every More tools group and owner step has en and tr strings', () => {
|
||||
const en = readFileSync(join(import.meta.dir, '../apps/desktop/src/i18n/en.ts'), 'utf8');
|
||||
const tr = readFileSync(join(import.meta.dir, '../apps/desktop/src/i18n/tr.ts'), 'utf8');
|
||||
for (const k of [...TOOLBOX.map(g => `tools.g.${g.id}`), ...OWNER_STEPS.map(s => `tools.o.${s.id}`)]) {
|
||||
expect(en).toContain(`'${k}'`);
|
||||
expect(tr).toContain(`'${k}'`);
|
||||
}
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue