Files
brain/tools/registry-load.test.mjs
T
Дмитрий 524bcfd05f feat: разворачивание комка ui-ux-pro-max — 7 навыков (роутер-реестр)
Эпик роутер-реестр, спека v2 §2, этап 1. Решение владельца 19.06 (путь 2):
зонтик ui-ux-pro-max развёрнут в 7 карточек-навыков + 7 под-узлов #31a..#31g.
Роль сохранена в каждой карточке: материал/решение по UI → стек Vue+Vuetify
(R6.0), финальный код — Frontend Design #30.

- 7 карточек: banner-design, brand, design, design-system, slides, ui-styling,
  ui-ux-pro-max (master)
- nodes.yaml: узел #31 → #31a..#31g; мастер #31g держит конфликт-треугольник
  (frontend-design ↔ 21st-magic); обратные ссылки у #30/#32 перенаправлены на
  ui-ux-pro-max:ui-ux-pro-max → симметрия конфликтов сохранена (m3e зелёный)
- зонтик убран; registry-load.test: 153 узла / 145 active
- hookify оставлен одной карточкой (решение владельца)

Правка PSR (роль UPM: материал → решатель-с-ограничением) — отдельным шагом.

Регрессия (без 5 pre-existing node:test файлов): 4365 passed, exit 0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 04:35:14 +03:00

82 lines
3.0 KiB
JavaScript

// tools/registry-load.test.mjs
import { describe, it, expect, beforeEach } from 'vitest';
import { loadRegistry, clearCache, findByClassification, findByKeyword, findActiveNodes, findChainsByNode } from './registry-load.mjs';
describe('registry-load', () => {
beforeEach(() => clearCache());
it('loads registry (153 nodes: разворачивание 11 комков (+#31 ui-ux-pro-max) 18-19.06.2026)', () => {
const r = loadRegistry();
expect(r.nodes).toHaveLength(153);
expect(r.version).toBe('0.1.0');
});
it('indexes by classification', () => {
const r = loadRegistry();
const features = findByClassification(r, 'feature');
expect(features).toHaveLength(1);
expect(features[0].node.id).toBe('#19a'); // feature → superpowers:brainstorming после разворачивания #19
expect(features[0].weight).toBe(1.0);
});
it('returns empty array for unknown classification', () => {
const r = loadRegistry();
expect(findByClassification(r, 'nonexistent')).toEqual([]);
});
it('indexes by keyword case-insensitive', () => {
const r = loadRegistry();
expect(findByKeyword(r, 'tdd')).toHaveLength(1);
expect(findByKeyword(r, 'TDD')).toHaveLength(1);
});
it('excludes historic/dormant from trigger index', () => {
const r = loadRegistry();
// #1 PostgreSQL MCP — historic, не должен попасть в индексы
for (const entries of r.indexByTrigger.values()) {
expect(entries.find(e => e.node.id === '#1')).toBeUndefined();
}
});
it('includes historic in nodes array (full reference)', () => {
const r = loadRegistry();
expect(r.indexById.get('#1').status).toBe('historic');
});
it('findActiveNodes excludes non-active (nodes.yaml registry)', () => {
const r = loadRegistry();
const active = findActiveNodes(r);
// 153 nodes total; #1 historic, #17 dormant, #44/#50/#54/#67/#82/#83 deferred;
// развёрнуты: ...,#76→3,#31 ui-ux-pro-max→7 (+6) → 145 active
expect(active).toHaveLength(145);
expect(active.map(n => n.id)).toContain('#18');
expect(active.map(n => n.id)).toContain('#19a');
expect(active.map(n => n.id)).not.toContain('#1');
expect(active.map(n => n.id)).not.toContain('#17');
});
it('findChainsByNode returns chain membership', () => {
const r = loadRegistry();
// L8 = runtime debug chain: systematic-debugging + Sentry (#34) + Redis (#35)
const sentryChains = findChainsByNode(r, '#34');
expect(sentryChains.map(c => c.chainId)).toContain('L8');
});
it('caches across calls in same process', () => {
const r1 = loadRegistry();
const r2 = loadRegistry();
expect(r1).toBe(r2); // same reference
});
it('clearCache forces reload', () => {
const r1 = loadRegistry();
clearCache();
const r2 = loadRegistry();
expect(r1).not.toBe(r2);
});
it('throws on schema violation', () => {
expect(() => loadRegistry({ registryPath: '/nonexistent/path.yaml', useCache: false })).toThrow();
});
});