397777089e
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
50 lines
2.9 KiB
JavaScript
50 lines
2.9 KiB
JavaScript
// tools/skeleton-radar.test.mjs
|
|
import { describe, it, expect } from 'vitest';
|
|
import { buildSkeletonRadar, REPORT_STATUSES } from './skeleton-radar.mjs';
|
|
|
|
describe('buildSkeletonRadar (§5.7 скелет-радар)', () => {
|
|
const headers = ['## Auth', '## Billing', '## Webhooks'];
|
|
it('каждый заголовок → пункт; непрорепорченный → not-reported', () => {
|
|
const r = buildSkeletonRadar({ headers, reports: { '## Auth': 'touched' } });
|
|
expect(r.items).toHaveLength(3);
|
|
expect(r.items.find((i) => i.header === '## Auth').status).toBe('touched');
|
|
expect(r.items.find((i) => i.header === '## Billing').status).toBe('not-reported');
|
|
expect(r.unreported.map((i) => i.header).sort()).toEqual(['## Billing', '## Webhooks']);
|
|
});
|
|
it('REPORT_STATUSES заморожен и содержит 4 статуса', () => {
|
|
expect(Object.isFrozen(REPORT_STATUSES)).toBe(true);
|
|
expect(REPORT_STATUSES).toEqual(['touched', 'not-relevant', 'not-read', 'not-reported']);
|
|
});
|
|
it('невалидный статус в reports → not-reported (fail-safe)', () => {
|
|
const r = buildSkeletonRadar({ headers: ['## A'], reports: { '## A': 'выдумка' } });
|
|
expect(r.items[0].status).toBe('not-reported');
|
|
});
|
|
it('битые входы → пусто, не крашит', () => {
|
|
expect(buildSkeletonRadar({ headers: null }).items).toEqual([]);
|
|
expect(buildSkeletonRadar({}).unreported).toEqual([]);
|
|
});
|
|
|
|
// F-F3: пустой скелет виден — summary.headers=0 (зеркало F-F1 graph-radar)
|
|
it('F-F3: summary {headers, unreported}; пустой скелет = headers:0', () => {
|
|
const r = buildSkeletonRadar({ headers, reports: { '## Auth': 'touched' } });
|
|
expect(r.summary).toEqual({ headers: 3, unreported: 2 });
|
|
const empty = buildSkeletonRadar({ headers: [] });
|
|
expect(empty.summary).toEqual({ headers: 0, unreported: 0 });
|
|
});
|
|
|
|
// F-F4: items заморожены — машинная мутация статуса бросает TypeError (L2-пол)
|
|
it('F-F4: элементы items заморожены, мутация status бросает TypeError', () => {
|
|
const r = buildSkeletonRadar({ headers: ['## A'], reports: {} });
|
|
expect(r.items.every((i) => Object.isFrozen(i))).toBe(true);
|
|
expect(() => { r.items[0].status = 'touched'; }).toThrow(TypeError);
|
|
});
|
|
|
|
// F-F5 (характеризация, без RED — SE9): дубликаты заголовков сохраняются оба,
|
|
// делят один ключ отчёта (направление fail-safe — пункты не теряются)
|
|
it('F-F5: дубликаты заголовков → оба пункта, один статус на ключ', () => {
|
|
const r = buildSkeletonRadar({ headers: ['## A', '## A'], reports: { '## A': 'touched' } });
|
|
expect(r.items).toHaveLength(2);
|
|
expect(r.items.every((i) => i.status === 'touched')).toBe(true);
|
|
});
|
|
});
|