import { describe, it } from 'node:test'; import assert from 'node:assert/strict'; import { getTriggerInfo, filteredSkills } from '../utils/autocomplete.js'; const mockConfig = { trigger: '/', skills: [ { name: 'commit', description: 'Create a git commit' }, { name: 'review-pr', description: 'Review a pull request' }, { name: 'comment', description: 'Add a comment' }, ], }; describe('getTriggerInfo', () => { it('returns null when no autocompleteConfig', () => { const result = getTriggerInfo('/hello', 1, null); assert.equal(result, null); }); it('returns null when autocompleteConfig is undefined', () => { const result = getTriggerInfo('/hello', 1, undefined); assert.equal(result, null); }); it('detects trigger at position 0', () => { const result = getTriggerInfo('/', 1, mockConfig); assert.deepEqual(result, { trigger: '/', filterText: '', replaceStart: 0, replaceEnd: 1, }); }); it('detects trigger after space', () => { const result = getTriggerInfo('hello /co', 9, mockConfig); assert.deepEqual(result, { trigger: '/', filterText: 'co', replaceStart: 6, replaceEnd: 9, }); }); it('detects trigger after newline', () => { const result = getTriggerInfo('line1\n/rev', 10, mockConfig); assert.deepEqual(result, { trigger: '/', filterText: 'rev', replaceStart: 6, replaceEnd: 10, }); }); it('returns null for non-trigger character', () => { const result = getTriggerInfo('hello world', 5, mockConfig); assert.equal(result, null); }); it('returns null for wrong trigger (! when config expects /)', () => { const result = getTriggerInfo('!commit', 7, mockConfig); assert.equal(result, null); }); it('returns null for trigger embedded in a word', () => { const result = getTriggerInfo('path/to/file', 5, mockConfig); assert.equal(result, null); }); it('extracts filterText correctly', () => { const result = getTriggerInfo('/commit', 7, mockConfig); assert.equal(result.filterText, 'commit'); assert.equal(result.replaceStart, 0); assert.equal(result.replaceEnd, 7); }); it('filterText is lowercase', () => { const result = getTriggerInfo('/CoMmIt', 7, mockConfig); assert.equal(result.filterText, 'commit'); }); it('replaceStart and replaceEnd are correct for mid-input trigger', () => { const result = getTriggerInfo('foo /bar', 8, mockConfig); assert.equal(result.replaceStart, 4); assert.equal(result.replaceEnd, 8); }); it('works with a different trigger character', () => { const codexConfig = { trigger: '!', skills: [] }; const result = getTriggerInfo('!test', 5, codexConfig); assert.deepEqual(result, { trigger: '!', filterText: 'test', replaceStart: 0, replaceEnd: 5, }); }); }); describe('filteredSkills', () => { it('returns empty array without config', () => { const info = { filterText: '' }; assert.deepEqual(filteredSkills(null, info), []); }); it('returns empty array without triggerInfo', () => { assert.deepEqual(filteredSkills(mockConfig, null), []); }); it('returns empty array when both are null', () => { assert.deepEqual(filteredSkills(null, null), []); }); it('returns all skills with empty filter', () => { const info = { filterText: '' }; const result = filteredSkills(mockConfig, info); assert.equal(result.length, 3); }); it('filters case-insensitively', () => { const info = { filterText: 'com' }; const result = filteredSkills(mockConfig, info); const names = result.map(s => s.name); assert.ok(names.includes('commit')); assert.ok(names.includes('comment')); assert.ok(!names.includes('review-pr')); }); it('matches anywhere in name', () => { const info = { filterText: 'view' }; const result = filteredSkills(mockConfig, info); assert.equal(result.length, 1); assert.equal(result[0].name, 'review-pr'); }); it('sorts alphabetically', () => { const info = { filterText: '' }; const result = filteredSkills(mockConfig, info); const names = result.map(s => s.name); assert.deepEqual(names, ['comment', 'commit', 'review-pr']); }); it('returns empty array when no matches', () => { const info = { filterText: 'zzz' }; const result = filteredSkills(mockConfig, info); assert.deepEqual(result, []); }); it('does not mutate the original skills array', () => { const config = { trigger: '/', skills: [ { name: 'zebra', description: 'z' }, { name: 'alpha', description: 'a' }, ], }; const info = { filterText: '' }; filteredSkills(config, info); assert.equal(config.skills[0].name, 'zebra'); assert.equal(config.skills[1].name, 'alpha'); }); });