import assert from 'node:assert/strict'; import { describe, it } from 'node:test'; import { loadCommands } from '../src/core/loader.js'; import { CommandRegistry } from '../src/core/registry.js'; const valid = { command: 'demo', handler: async () => {} }; describe('CommandRegistry', () => { it('ругается на дубли имён и алиасов', () => { const registry = new CommandRegistry(); registry.register(valid, 'a.js'); assert.throws(() => registry.register(valid, 'b.js'), /Конфликт триггеров/); assert.throws(() => registry.register({ ...valid, command: 'other', aliases: ['demo'] }, 'c.js'), /Конфликт/); }); it('проверяет обязательные поля', () => { const registry = new CommandRegistry(); assert.throws(() => registry.register({ handler: () => {} }, 'x.js'), /не задано поле "command"/); assert.throws(() => registry.register({ command: 'a' }, 'x.js'), /"handler" должно быть функцией/); assert.throws(() => registry.register({ ...valid, command: '/demo' }, 'x.js'), /без слэша/); assert.throws(() => registry.register({ ...valid, scope: 'group' }, 'x.js'), /неизвестный scope/); assert.throws(() => registry.register(null, 'x.js'), /объект по умолчанию/); }); it('в меню Telegram не попадают скрытые, админские и нелатинские', () => { const registry = new CommandRegistry(); registry.register({ ...valid, description: 'ок' }, 'a.js'); registry.register({ ...valid, command: 'secret', hidden: true }, 'b.js'); registry.register({ ...valid, command: 'root', adminOnly: true }, 'c.js'); registry.register({ ...valid, command: 'привет' }, 'd.js'); assert.deepEqual(registry.forTelegram(), [{ command: 'demo', description: 'ок' }]); }); }); describe('loadCommands', () => { it('поднимает все команды проекта и пропускает файлы с _', async () => { const registry = await loadCommands(); const names = registry.list().map((cmd) => cmd.command); assert.ok(names.includes('start')); assert.ok(names.includes('pause'), 'команды из подпапок тоже должны грузиться'); assert.ok(!names.includes('template'), '_template.js не должен попадать в реестр'); }); });