tool-registry.test.js 2.42 KB
/**
 * tool-registry 单测
 */

const registry = require('../../../src/tools/devloop/tool-registry');

describe('tool-registry', () => {
  beforeEach(() => registry._resetForTesting());

  it('loadAllTools returns a Map with unique tool names', () => {
    const all = registry.loadAllTools();
    expect(all instanceof Map).toBe(true);
    expect(all.size).toBeGreaterThanOrEqual(30);
    for (const [name, tool] of all) {
      expect(typeof name).toBe('string');
      expect(tool.name).toBe(name);
      expect(typeof tool.execute).toBe('function');
    }
  });

  it('listToolNames includes core 5 persistence tools', () => {
    const names = registry.listToolNames();
    expect(names).toContain('write_todolist');
    expect(names).toContain('update_todo_item');
    expect(names).toContain('timeline_append');
    expect(names).toContain('record_memory');
    expect(names).toContain('update_runtime_state');
  });

  it('listToolNames includes PM/Architect doc tools', () => {
    const names = registry.listToolNames();
    expect(names).toContain('write_chapter');
    expect(names).toContain('write_mvcp_page');
    expect(names).toContain('hash_contract');
    expect(names).toContain('validate_prd_site');
  });

  it('listToolNames includes Coder/Tester/Integrator/Triager tools', () => {
    const names = registry.listToolNames();
    expect(names).toContain('contract_bridge');     // coder
    expect(names).toContain('parse_vitest');        // tester
    expect(names).toContain('port_picker');         // integrator
    expect(names).toContain('extract_evidence');    // triager
  });

  it('getDevLoopTools filters by toolPolicy', () => {
    const subset = registry.getDevLoopTools(['hash_contract', 'parse_vitest', 'nope']);
    expect(subset).toHaveLength(2);
    expect(subset.map(t => t.name).sort()).toEqual(['hash_contract', 'parse_vitest']);
  });

  it('dispatch invokes a known tool', async () => {
    const r = await registry.dispatch('hash_contract', {
      contract: { name: 'login', method: 'POST' },
    }, {});
    expect(r.ok).toBe(true);
    expect(r.hash).toMatch(/^sha256:[a-f0-9]{16}$/);
  });

  it('dispatch rejects unknown tool', async () => {
    await expect(registry.dispatch('does_not_exist', {}, {})).rejects.toThrow(/Unknown tool/);
  });

  it('dispatch validates required fields', async () => {
    await expect(registry.dispatch('hash_contract', {}, {})).rejects.toThrow(/missing required field "contract"/);
  });
});