@brookmind/ai-toolkit 1.2.0 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/__tests__/constants.test.d.ts +2 -0
- package/dist/__tests__/constants.test.d.ts.map +1 -0
- package/dist/__tests__/constants.test.js +102 -0
- package/dist/__tests__/constants.test.js.map +1 -0
- package/dist/__tests__/index.test.js +2 -102
- package/dist/__tests__/index.test.js.map +1 -1
- package/dist/__tests__/integration/installer.test.d.ts +2 -0
- package/dist/__tests__/integration/installer.test.d.ts.map +1 -0
- package/dist/__tests__/integration/installer.test.js +425 -0
- package/dist/__tests__/integration/installer.test.js.map +1 -0
- package/dist/__tests__/services/installers.test.d.ts +2 -0
- package/dist/__tests__/services/installers.test.d.ts.map +1 -0
- package/dist/__tests__/services/installers.test.js +222 -0
- package/dist/__tests__/services/installers.test.js.map +1 -0
- package/dist/__tests__/services/opencode.test.d.ts +2 -0
- package/dist/__tests__/services/opencode.test.d.ts.map +1 -0
- package/dist/__tests__/services/opencode.test.js +120 -0
- package/dist/__tests__/services/opencode.test.js.map +1 -0
- package/dist/__tests__/ui/categorize.test.d.ts +2 -0
- package/dist/__tests__/ui/categorize.test.d.ts.map +1 -0
- package/dist/__tests__/ui/categorize.test.js +194 -0
- package/dist/__tests__/ui/categorize.test.js.map +1 -0
- package/dist/__tests__/ui/choices.test.d.ts +2 -0
- package/dist/__tests__/ui/choices.test.d.ts.map +1 -0
- package/dist/__tests__/ui/choices.test.js +180 -0
- package/dist/__tests__/ui/choices.test.js.map +1 -0
- package/dist/__tests__/ui/display.test.d.ts +2 -0
- package/dist/__tests__/ui/display.test.d.ts.map +1 -0
- package/dist/__tests__/ui/display.test.js +142 -0
- package/dist/__tests__/ui/display.test.js.map +1 -0
- package/dist/__tests__/utils/fs.test.d.ts +2 -0
- package/dist/__tests__/utils/fs.test.d.ts.map +1 -0
- package/dist/__tests__/utils/fs.test.js +142 -0
- package/dist/__tests__/utils/fs.test.js.map +1 -0
- package/dist/__tests__/utils/terminal.test.d.ts +2 -0
- package/dist/__tests__/utils/terminal.test.d.ts.map +1 -0
- package/dist/__tests__/utils/terminal.test.js +97 -0
- package/dist/__tests__/utils/terminal.test.js.map +1 -0
- package/dist/constants.d.ts +1 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +1 -0
- package/dist/constants.js.map +1 -1
- package/dist/ui/display.d.ts.map +1 -1
- package/dist/ui/display.js +3 -1
- package/dist/ui/display.js.map +1 -1
- package/package.json +3 -1
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
|
2
|
+
import { buildAgentChoices, buildSkillChoices, buildCommandChoices, buildMcpChoices, } from '../../ui/choices.js';
|
|
3
|
+
vi.mock('../../utils/fs.js', () => ({
|
|
4
|
+
exists: vi.fn(),
|
|
5
|
+
readJsonConfig: vi.fn(),
|
|
6
|
+
}));
|
|
7
|
+
vi.mock('../../services/installers.js', () => ({
|
|
8
|
+
getInstalledMcps: vi.fn(),
|
|
9
|
+
}));
|
|
10
|
+
vi.mock('../../constants.js', async (importOriginal) => {
|
|
11
|
+
const original = await importOriginal();
|
|
12
|
+
return {
|
|
13
|
+
...original,
|
|
14
|
+
getDescription: vi.fn((name) => {
|
|
15
|
+
const descriptions = {
|
|
16
|
+
'test-agent': 'Test agent description',
|
|
17
|
+
'test-skill': 'Test skill description',
|
|
18
|
+
'test-command': 'Test command description',
|
|
19
|
+
'test-mcp': 'Test MCP description',
|
|
20
|
+
};
|
|
21
|
+
return descriptions[name] ?? null;
|
|
22
|
+
}),
|
|
23
|
+
MCP_DISPLAY_NAMES: {
|
|
24
|
+
'pg-aiguide': 'postgres-mcp',
|
|
25
|
+
},
|
|
26
|
+
OPENCODE_DIR: '/fake/opencode',
|
|
27
|
+
TOOLS_DIR: '/fake/tools',
|
|
28
|
+
};
|
|
29
|
+
});
|
|
30
|
+
describe('ui/choices', () => {
|
|
31
|
+
let mockExists;
|
|
32
|
+
let mockReadJsonConfig;
|
|
33
|
+
let mockGetInstalledMcps;
|
|
34
|
+
beforeEach(async () => {
|
|
35
|
+
vi.resetAllMocks();
|
|
36
|
+
const fsModule = await import('../../utils/fs.js');
|
|
37
|
+
mockExists = fsModule.exists;
|
|
38
|
+
mockReadJsonConfig = fsModule.readJsonConfig;
|
|
39
|
+
const installersModule = await import('../../services/installers.js');
|
|
40
|
+
mockGetInstalledMcps = installersModule.getInstalledMcps;
|
|
41
|
+
mockExists.mockResolvedValue(false);
|
|
42
|
+
mockReadJsonConfig.mockResolvedValue({});
|
|
43
|
+
mockGetInstalledMcps.mockResolvedValue(new Set());
|
|
44
|
+
});
|
|
45
|
+
afterEach(() => {
|
|
46
|
+
vi.clearAllMocks();
|
|
47
|
+
});
|
|
48
|
+
describe('buildAgentChoices', () => {
|
|
49
|
+
it('should return empty array for empty agents', async () => {
|
|
50
|
+
const result = await buildAgentChoices([]);
|
|
51
|
+
expect(result).toEqual([]);
|
|
52
|
+
});
|
|
53
|
+
it('should build choices for new agents', async () => {
|
|
54
|
+
mockExists.mockResolvedValue(false);
|
|
55
|
+
const result = await buildAgentChoices(['test-agent']);
|
|
56
|
+
expect(result).toHaveLength(1);
|
|
57
|
+
expect(result[0].value).toBe('test-agent');
|
|
58
|
+
expect(result[0].name).toContain('test-agent');
|
|
59
|
+
expect(result[0].name).toContain('Test agent description');
|
|
60
|
+
expect(result[0].name).not.toContain('(installed)');
|
|
61
|
+
});
|
|
62
|
+
it('should mark installed agents', async () => {
|
|
63
|
+
mockExists.mockResolvedValue(true);
|
|
64
|
+
const result = await buildAgentChoices(['test-agent']);
|
|
65
|
+
expect(result[0].name).toContain('(installed)');
|
|
66
|
+
});
|
|
67
|
+
it('should build choices for multiple agents', async () => {
|
|
68
|
+
mockExists.mockResolvedValueOnce(false).mockResolvedValueOnce(true);
|
|
69
|
+
const result = await buildAgentChoices(['agent1', 'agent2']);
|
|
70
|
+
expect(result).toHaveLength(2);
|
|
71
|
+
expect(result[0].value).toBe('agent1');
|
|
72
|
+
expect(result[1].value).toBe('agent2');
|
|
73
|
+
});
|
|
74
|
+
it('should handle agents without description', async () => {
|
|
75
|
+
mockExists.mockResolvedValue(false);
|
|
76
|
+
const result = await buildAgentChoices(['unknown-agent']);
|
|
77
|
+
expect(result[0].value).toBe('unknown-agent');
|
|
78
|
+
expect(result[0].name).toContain('unknown-agent');
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
describe('buildSkillChoices', () => {
|
|
82
|
+
it('should return empty array for empty skills', async () => {
|
|
83
|
+
const result = await buildSkillChoices([]);
|
|
84
|
+
expect(result).toEqual([]);
|
|
85
|
+
});
|
|
86
|
+
it('should build choices for new skills', async () => {
|
|
87
|
+
mockExists.mockResolvedValue(false);
|
|
88
|
+
const result = await buildSkillChoices(['test-skill']);
|
|
89
|
+
expect(result).toHaveLength(1);
|
|
90
|
+
expect(result[0].value).toBe('test-skill');
|
|
91
|
+
expect(result[0].name).toContain('test-skill');
|
|
92
|
+
expect(result[0].name).toContain('Test skill description');
|
|
93
|
+
});
|
|
94
|
+
it('should mark installed skills', async () => {
|
|
95
|
+
mockExists.mockResolvedValue(true);
|
|
96
|
+
const result = await buildSkillChoices(['test-skill']);
|
|
97
|
+
expect(result[0].name).toContain('(installed)');
|
|
98
|
+
});
|
|
99
|
+
it('should build choices for multiple skills', async () => {
|
|
100
|
+
mockExists.mockResolvedValueOnce(false).mockResolvedValueOnce(true);
|
|
101
|
+
const result = await buildSkillChoices(['skill1', 'skill2']);
|
|
102
|
+
expect(result).toHaveLength(2);
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
describe('buildCommandChoices', () => {
|
|
106
|
+
it('should return empty array for empty commands', async () => {
|
|
107
|
+
const result = await buildCommandChoices([]);
|
|
108
|
+
expect(result).toEqual([]);
|
|
109
|
+
});
|
|
110
|
+
it('should build choices for new commands', async () => {
|
|
111
|
+
mockExists.mockResolvedValue(false);
|
|
112
|
+
const result = await buildCommandChoices(['test-command']);
|
|
113
|
+
expect(result).toHaveLength(1);
|
|
114
|
+
expect(result[0].value).toBe('test-command');
|
|
115
|
+
expect(result[0].name).toContain('test-command');
|
|
116
|
+
expect(result[0].name).toContain('Test command description');
|
|
117
|
+
});
|
|
118
|
+
it('should mark installed commands', async () => {
|
|
119
|
+
mockExists.mockResolvedValue(true);
|
|
120
|
+
const result = await buildCommandChoices(['test-command']);
|
|
121
|
+
expect(result[0].name).toContain('(installed)');
|
|
122
|
+
});
|
|
123
|
+
it('should build choices for multiple commands', async () => {
|
|
124
|
+
mockExists.mockResolvedValueOnce(true).mockResolvedValueOnce(false);
|
|
125
|
+
const result = await buildCommandChoices(['cmd1', 'cmd2']);
|
|
126
|
+
expect(result).toHaveLength(2);
|
|
127
|
+
expect(result[0].name).toContain('(installed)');
|
|
128
|
+
expect(result[1].name).not.toContain('(installed)');
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
describe('buildMcpChoices', () => {
|
|
132
|
+
it('should return empty array for empty mcps', async () => {
|
|
133
|
+
const result = await buildMcpChoices([]);
|
|
134
|
+
expect(result).toEqual([]);
|
|
135
|
+
});
|
|
136
|
+
it('should build choices for new mcps', async () => {
|
|
137
|
+
mockGetInstalledMcps.mockResolvedValue(new Set());
|
|
138
|
+
mockReadJsonConfig.mockResolvedValue({
|
|
139
|
+
mcpServers: { 'test-server': {} },
|
|
140
|
+
});
|
|
141
|
+
const result = await buildMcpChoices(['test-mcp']);
|
|
142
|
+
expect(result).toHaveLength(1);
|
|
143
|
+
expect(result[0].value).toBe('test-mcp');
|
|
144
|
+
expect(result[0].name).toContain('test-mcp');
|
|
145
|
+
});
|
|
146
|
+
it('should mark installed mcps based on server names', async () => {
|
|
147
|
+
mockGetInstalledMcps.mockResolvedValue(new Set(['test-server']));
|
|
148
|
+
mockReadJsonConfig.mockResolvedValue({
|
|
149
|
+
mcpServers: { 'test-server': {} },
|
|
150
|
+
});
|
|
151
|
+
const result = await buildMcpChoices(['test-mcp']);
|
|
152
|
+
expect(result[0].name).toContain('(installed)');
|
|
153
|
+
});
|
|
154
|
+
it('should use display name from MCP_DISPLAY_NAMES', async () => {
|
|
155
|
+
mockGetInstalledMcps.mockResolvedValue(new Set());
|
|
156
|
+
mockReadJsonConfig.mockResolvedValue({
|
|
157
|
+
mcpServers: { 'pg-server': {} },
|
|
158
|
+
});
|
|
159
|
+
const result = await buildMcpChoices(['pg-aiguide']);
|
|
160
|
+
expect(result[0].name).toContain('postgres-mcp');
|
|
161
|
+
expect(result[0].value).toBe('pg-aiguide');
|
|
162
|
+
});
|
|
163
|
+
it('should handle mcps without servers', async () => {
|
|
164
|
+
mockGetInstalledMcps.mockResolvedValue(new Set());
|
|
165
|
+
mockReadJsonConfig.mockResolvedValue({});
|
|
166
|
+
const result = await buildMcpChoices(['test-mcp']);
|
|
167
|
+
expect(result).toHaveLength(1);
|
|
168
|
+
expect(result[0].name).not.toContain('(installed)');
|
|
169
|
+
});
|
|
170
|
+
it('should build choices for multiple mcps', async () => {
|
|
171
|
+
mockGetInstalledMcps.mockResolvedValue(new Set(['server1']));
|
|
172
|
+
mockReadJsonConfig
|
|
173
|
+
.mockResolvedValueOnce({ mcpServers: { server1: {} } })
|
|
174
|
+
.mockResolvedValueOnce({ mcpServers: { server2: {} } });
|
|
175
|
+
const result = await buildMcpChoices(['mcp1', 'mcp2']);
|
|
176
|
+
expect(result).toHaveLength(2);
|
|
177
|
+
});
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
//# sourceMappingURL=choices.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"choices.test.js","sourceRoot":"","sources":["../../../src/__tests__/ui/choices.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"display.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/ui/display.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
|
2
|
+
import { displayHeader, formatCategorized, formatTheme, showSelectionResult, getSeparator, displaySummary, } from '../../ui/display.js';
|
|
3
|
+
vi.mock('../../utils/fs.js', () => ({
|
|
4
|
+
readJsonConfig: vi.fn(),
|
|
5
|
+
}));
|
|
6
|
+
vi.mock('../../utils/terminal.js', () => ({
|
|
7
|
+
clearScreen: vi.fn(),
|
|
8
|
+
}));
|
|
9
|
+
describe('ui/display', () => {
|
|
10
|
+
let mockReadJsonConfig;
|
|
11
|
+
let mockClearScreen;
|
|
12
|
+
let consoleLogSpy;
|
|
13
|
+
beforeEach(async () => {
|
|
14
|
+
vi.resetAllMocks();
|
|
15
|
+
const fsModule = await import('../../utils/fs.js');
|
|
16
|
+
mockReadJsonConfig = fsModule.readJsonConfig;
|
|
17
|
+
const terminalModule = await import('../../utils/terminal.js');
|
|
18
|
+
mockClearScreen = terminalModule.clearScreen;
|
|
19
|
+
consoleLogSpy = vi.spyOn(console, 'log').mockImplementation(() => undefined);
|
|
20
|
+
mockReadJsonConfig.mockResolvedValue({ version: '1.0.0' });
|
|
21
|
+
});
|
|
22
|
+
afterEach(() => {
|
|
23
|
+
consoleLogSpy.mockRestore();
|
|
24
|
+
vi.clearAllMocks();
|
|
25
|
+
});
|
|
26
|
+
describe('displayHeader', () => {
|
|
27
|
+
it('should read package.json and display header', async () => {
|
|
28
|
+
await displayHeader();
|
|
29
|
+
expect(mockReadJsonConfig).toHaveBeenCalled();
|
|
30
|
+
expect(mockClearScreen).toHaveBeenCalled();
|
|
31
|
+
expect(consoleLogSpy).toHaveBeenCalled();
|
|
32
|
+
});
|
|
33
|
+
it('should call clearScreen', async () => {
|
|
34
|
+
await displayHeader();
|
|
35
|
+
expect(mockClearScreen).toHaveBeenCalled();
|
|
36
|
+
});
|
|
37
|
+
it('should display logo', async () => {
|
|
38
|
+
await displayHeader();
|
|
39
|
+
expect(consoleLogSpy).toHaveBeenCalled();
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
describe('formatCategorized', () => {
|
|
43
|
+
it('should return "none" for empty categorized items', () => {
|
|
44
|
+
const cat = { new: [], update: [] };
|
|
45
|
+
const result = formatCategorized(cat);
|
|
46
|
+
expect(result).toContain('none');
|
|
47
|
+
});
|
|
48
|
+
it('should format only new items', () => {
|
|
49
|
+
const cat = { new: ['item1', 'item2'], update: [] };
|
|
50
|
+
const result = formatCategorized(cat);
|
|
51
|
+
expect(result).toContain('+ item1, item2');
|
|
52
|
+
});
|
|
53
|
+
it('should format only update items', () => {
|
|
54
|
+
const cat = { new: [], update: ['item1', 'item2'] };
|
|
55
|
+
const result = formatCategorized(cat);
|
|
56
|
+
expect(result).toContain('↻ item1, item2');
|
|
57
|
+
});
|
|
58
|
+
it('should format mixed new and update items', () => {
|
|
59
|
+
const cat = { new: ['new1'], update: ['upd1'] };
|
|
60
|
+
const result = formatCategorized(cat);
|
|
61
|
+
expect(result).toContain('+ new1');
|
|
62
|
+
expect(result).toContain('↻ upd1');
|
|
63
|
+
});
|
|
64
|
+
it('should join items with comma and space', () => {
|
|
65
|
+
const cat = { new: ['a', 'b', 'c'], update: [] };
|
|
66
|
+
const result = formatCategorized(cat);
|
|
67
|
+
expect(result).toContain('a, b, c');
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
describe('formatTheme', () => {
|
|
71
|
+
it('should return "none" when installThemeChoice is false', () => {
|
|
72
|
+
const result = formatTheme(false, false);
|
|
73
|
+
expect(result).toContain('none');
|
|
74
|
+
});
|
|
75
|
+
it('should return new format when installing new theme', () => {
|
|
76
|
+
const result = formatTheme(true, false);
|
|
77
|
+
expect(result).toContain('+ claude-vivid');
|
|
78
|
+
});
|
|
79
|
+
it('should return update format when updating theme', () => {
|
|
80
|
+
const result = formatTheme(true, true);
|
|
81
|
+
expect(result).toContain('↻ claude-vivid');
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
describe('showSelectionResult', () => {
|
|
85
|
+
it('should show checkmark for count > 0', () => {
|
|
86
|
+
showSelectionResult(3, 'agents');
|
|
87
|
+
expect(consoleLogSpy).toHaveBeenCalled();
|
|
88
|
+
const call = consoleLogSpy.mock.calls[0][0];
|
|
89
|
+
expect(call).toContain('✓');
|
|
90
|
+
expect(call).toContain('3 agents selected');
|
|
91
|
+
});
|
|
92
|
+
it('should show dim message for count = 0', () => {
|
|
93
|
+
showSelectionResult(0, 'skills');
|
|
94
|
+
expect(consoleLogSpy).toHaveBeenCalled();
|
|
95
|
+
const call = consoleLogSpy.mock.calls[0][0];
|
|
96
|
+
expect(call).toContain('No skills selected');
|
|
97
|
+
});
|
|
98
|
+
it('should use singular/plural label as provided', () => {
|
|
99
|
+
showSelectionResult(1, 'item');
|
|
100
|
+
expect(consoleLogSpy).toHaveBeenCalled();
|
|
101
|
+
const call = consoleLogSpy.mock.calls[0][0];
|
|
102
|
+
expect(call).toContain('1 item selected');
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
describe('getSeparator', () => {
|
|
106
|
+
it('should return separator line', () => {
|
|
107
|
+
const result = getSeparator();
|
|
108
|
+
expect(result).toContain('─'.repeat(50));
|
|
109
|
+
});
|
|
110
|
+
it('should return consistent length', () => {
|
|
111
|
+
const result1 = getSeparator();
|
|
112
|
+
const result2 = getSeparator();
|
|
113
|
+
expect(result1).toBe(result2);
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
describe('displaySummary', () => {
|
|
117
|
+
it('should display summary with all categories', () => {
|
|
118
|
+
const agents = { new: ['a1'], update: [] };
|
|
119
|
+
const skills = { new: [], update: ['s1'] };
|
|
120
|
+
const commands = { new: ['c1'], update: ['c2'] };
|
|
121
|
+
const mcps = { new: [], update: [] };
|
|
122
|
+
displaySummary(agents, skills, commands, mcps, false, false);
|
|
123
|
+
expect(consoleLogSpy).toHaveBeenCalled();
|
|
124
|
+
});
|
|
125
|
+
it('should display summary box', () => {
|
|
126
|
+
const empty = { new: [], update: [] };
|
|
127
|
+
displaySummary(empty, empty, empty, empty, false, false);
|
|
128
|
+
expect(consoleLogSpy).toHaveBeenCalled();
|
|
129
|
+
});
|
|
130
|
+
it('should include all category labels', () => {
|
|
131
|
+
const empty = { new: [], update: [] };
|
|
132
|
+
displaySummary(empty, empty, empty, empty, true, false);
|
|
133
|
+
expect(consoleLogSpy).toHaveBeenCalled();
|
|
134
|
+
});
|
|
135
|
+
it('should count theme update in totalUpdate', () => {
|
|
136
|
+
const empty = { new: [], update: [] };
|
|
137
|
+
displaySummary(empty, empty, empty, empty, true, true);
|
|
138
|
+
expect(consoleLogSpy).toHaveBeenCalled();
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
//# sourceMappingURL=display.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"display.test.js","sourceRoot":"","sources":["../../../src/__tests__/ui/display.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fs.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/utils/fs.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
import { mkdir, rm, writeFile } from 'fs/promises';
|
|
3
|
+
import { join } from 'path';
|
|
4
|
+
import { tmpdir } from 'os';
|
|
5
|
+
import { exists, getDirectories, getFiles, readJsonConfig } from '../../utils/fs.js';
|
|
6
|
+
describe('utils/fs', () => {
|
|
7
|
+
const testDir = join(tmpdir(), 'ai-toolkit-fs-test');
|
|
8
|
+
beforeEach(async () => {
|
|
9
|
+
await mkdir(testDir, { recursive: true });
|
|
10
|
+
});
|
|
11
|
+
afterEach(async () => {
|
|
12
|
+
await rm(testDir, { recursive: true, force: true });
|
|
13
|
+
});
|
|
14
|
+
describe('exists', () => {
|
|
15
|
+
it('should return true for existing directory', async () => {
|
|
16
|
+
const result = await exists(testDir);
|
|
17
|
+
expect(result).toBe(true);
|
|
18
|
+
});
|
|
19
|
+
it('should return true for existing file', async () => {
|
|
20
|
+
const filePath = join(testDir, 'test.txt');
|
|
21
|
+
await writeFile(filePath, 'test content');
|
|
22
|
+
const result = await exists(filePath);
|
|
23
|
+
expect(result).toBe(true);
|
|
24
|
+
});
|
|
25
|
+
it('should return false for non-existing path', async () => {
|
|
26
|
+
const result = await exists(join(testDir, 'non-existing'));
|
|
27
|
+
expect(result).toBe(false);
|
|
28
|
+
});
|
|
29
|
+
it('should return false for non-existing nested path', async () => {
|
|
30
|
+
const result = await exists(join(testDir, 'a', 'b', 'c', 'd'));
|
|
31
|
+
expect(result).toBe(false);
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
describe('getDirectories', () => {
|
|
35
|
+
it('should return empty array for empty directory', async () => {
|
|
36
|
+
const result = await getDirectories(testDir);
|
|
37
|
+
expect(result).toEqual([]);
|
|
38
|
+
});
|
|
39
|
+
it('should return only directories, not files', async () => {
|
|
40
|
+
await mkdir(join(testDir, 'dir1'));
|
|
41
|
+
await mkdir(join(testDir, 'dir2'));
|
|
42
|
+
await writeFile(join(testDir, 'file.txt'), 'content');
|
|
43
|
+
const result = await getDirectories(testDir);
|
|
44
|
+
expect(result).toHaveLength(2);
|
|
45
|
+
expect(result).toContain('dir1');
|
|
46
|
+
expect(result).toContain('dir2');
|
|
47
|
+
expect(result).not.toContain('file.txt');
|
|
48
|
+
});
|
|
49
|
+
it('should return empty array for non-existing directory', async () => {
|
|
50
|
+
const result = await getDirectories(join(testDir, 'non-existing'));
|
|
51
|
+
expect(result).toEqual([]);
|
|
52
|
+
});
|
|
53
|
+
it('should return empty array on error', async () => {
|
|
54
|
+
const result = await getDirectories('/root/definitely/does/not/exist/xyz');
|
|
55
|
+
expect(result).toEqual([]);
|
|
56
|
+
});
|
|
57
|
+
it('should handle directory with only files', async () => {
|
|
58
|
+
await writeFile(join(testDir, 'file1.txt'), 'content1');
|
|
59
|
+
await writeFile(join(testDir, 'file2.txt'), 'content2');
|
|
60
|
+
const result = await getDirectories(testDir);
|
|
61
|
+
expect(result).toEqual([]);
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
describe('getFiles', () => {
|
|
65
|
+
it('should return files with specified extension', async () => {
|
|
66
|
+
await writeFile(join(testDir, 'file1.md'), 'content1');
|
|
67
|
+
await writeFile(join(testDir, 'file2.md'), 'content2');
|
|
68
|
+
await writeFile(join(testDir, 'file3.txt'), 'content3');
|
|
69
|
+
const result = await getFiles(testDir, '.md');
|
|
70
|
+
expect(result).toHaveLength(2);
|
|
71
|
+
expect(result).toContain('file1');
|
|
72
|
+
expect(result).toContain('file2');
|
|
73
|
+
expect(result).not.toContain('file3');
|
|
74
|
+
});
|
|
75
|
+
it('should return empty array when no files match extension', async () => {
|
|
76
|
+
await writeFile(join(testDir, 'file1.txt'), 'content1');
|
|
77
|
+
await writeFile(join(testDir, 'file2.txt'), 'content2');
|
|
78
|
+
const result = await getFiles(testDir, '.md');
|
|
79
|
+
expect(result).toEqual([]);
|
|
80
|
+
});
|
|
81
|
+
it('should return empty array for empty directory', async () => {
|
|
82
|
+
const result = await getFiles(testDir, '.md');
|
|
83
|
+
expect(result).toEqual([]);
|
|
84
|
+
});
|
|
85
|
+
it('should return empty array for non-existing directory', async () => {
|
|
86
|
+
const result = await getFiles(join(testDir, 'non-existing'), '.md');
|
|
87
|
+
expect(result).toEqual([]);
|
|
88
|
+
});
|
|
89
|
+
it('should not include directories', async () => {
|
|
90
|
+
await mkdir(join(testDir, 'dir.md'));
|
|
91
|
+
await writeFile(join(testDir, 'file.md'), 'content');
|
|
92
|
+
const result = await getFiles(testDir, '.md');
|
|
93
|
+
expect(result).toHaveLength(1);
|
|
94
|
+
expect(result).toContain('file');
|
|
95
|
+
});
|
|
96
|
+
it('should strip extension from file names', async () => {
|
|
97
|
+
await writeFile(join(testDir, 'my-file.json'), '{}');
|
|
98
|
+
const result = await getFiles(testDir, '.json');
|
|
99
|
+
expect(result).toEqual(['my-file']);
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
describe('readJsonConfig', () => {
|
|
103
|
+
it('should read and parse valid JSON file', async () => {
|
|
104
|
+
const jsonPath = join(testDir, 'config.json');
|
|
105
|
+
const data = { key: 'value', number: 42, nested: { foo: 'bar' } };
|
|
106
|
+
await writeFile(jsonPath, JSON.stringify(data));
|
|
107
|
+
const result = await readJsonConfig(jsonPath);
|
|
108
|
+
expect(result).toEqual(data);
|
|
109
|
+
});
|
|
110
|
+
it('should return empty object for non-existing file', async () => {
|
|
111
|
+
const result = await readJsonConfig(join(testDir, 'non-existing.json'));
|
|
112
|
+
expect(result).toEqual({});
|
|
113
|
+
});
|
|
114
|
+
it('should return empty object for invalid JSON', async () => {
|
|
115
|
+
const jsonPath = join(testDir, 'invalid.json');
|
|
116
|
+
await writeFile(jsonPath, '{ invalid json }');
|
|
117
|
+
const result = await readJsonConfig(jsonPath);
|
|
118
|
+
expect(result).toEqual({});
|
|
119
|
+
});
|
|
120
|
+
it('should return empty object for empty file', async () => {
|
|
121
|
+
const jsonPath = join(testDir, 'empty.json');
|
|
122
|
+
await writeFile(jsonPath, '');
|
|
123
|
+
const result = await readJsonConfig(jsonPath);
|
|
124
|
+
expect(result).toEqual({});
|
|
125
|
+
});
|
|
126
|
+
it('should handle JSON with arrays', async () => {
|
|
127
|
+
const jsonPath = join(testDir, 'array.json');
|
|
128
|
+
const data = { items: [1, 2, 3], names: ['a', 'b'] };
|
|
129
|
+
await writeFile(jsonPath, JSON.stringify(data));
|
|
130
|
+
const result = await readJsonConfig(jsonPath);
|
|
131
|
+
expect(result).toEqual(data);
|
|
132
|
+
});
|
|
133
|
+
it('should handle deeply nested JSON', async () => {
|
|
134
|
+
const jsonPath = join(testDir, 'nested.json');
|
|
135
|
+
const data = { level1: { level2: { level3: { value: 'deep' } } } };
|
|
136
|
+
await writeFile(jsonPath, JSON.stringify(data));
|
|
137
|
+
const result = await readJsonConfig(jsonPath);
|
|
138
|
+
expect(result).toEqual(data);
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
//# sourceMappingURL=fs.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fs.test.js","sourceRoot":"","sources":["../../../src/__tests__/utils/fs.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"terminal.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/utils/terminal.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
|
2
|
+
import { setupScrollRegion, resetScrollRegion, handleResize, clearScreen, } from '../../utils/terminal.js';
|
|
3
|
+
import { BOTTOM_PADDING } from '../../constants.js';
|
|
4
|
+
describe('utils/terminal', () => {
|
|
5
|
+
let writeSpy;
|
|
6
|
+
let originalRows;
|
|
7
|
+
beforeEach(() => {
|
|
8
|
+
writeSpy = vi.spyOn(process.stdout, 'write').mockImplementation(() => true);
|
|
9
|
+
originalRows = process.stdout.rows;
|
|
10
|
+
});
|
|
11
|
+
afterEach(() => {
|
|
12
|
+
writeSpy.mockRestore();
|
|
13
|
+
Object.defineProperty(process.stdout, 'rows', {
|
|
14
|
+
value: originalRows,
|
|
15
|
+
writable: true,
|
|
16
|
+
});
|
|
17
|
+
});
|
|
18
|
+
describe('setupScrollRegion', () => {
|
|
19
|
+
it('should set scroll region when terminal has enough rows', () => {
|
|
20
|
+
Object.defineProperty(process.stdout, 'rows', { value: 40, writable: true });
|
|
21
|
+
setupScrollRegion();
|
|
22
|
+
expect(writeSpy).toHaveBeenCalledTimes(2);
|
|
23
|
+
expect(writeSpy).toHaveBeenNthCalledWith(1, `\x1b[1;${40 - BOTTOM_PADDING}r`);
|
|
24
|
+
expect(writeSpy).toHaveBeenNthCalledWith(2, '\x1b[H');
|
|
25
|
+
});
|
|
26
|
+
it('should not set scroll region when terminal is too small', () => {
|
|
27
|
+
Object.defineProperty(process.stdout, 'rows', { value: 10, writable: true });
|
|
28
|
+
setupScrollRegion();
|
|
29
|
+
expect(writeSpy).not.toHaveBeenCalled();
|
|
30
|
+
});
|
|
31
|
+
it('should use default rows (24) when process.stdout.rows is undefined', () => {
|
|
32
|
+
Object.defineProperty(process.stdout, 'rows', { value: undefined, writable: true });
|
|
33
|
+
setupScrollRegion();
|
|
34
|
+
expect(writeSpy).toHaveBeenCalledTimes(2);
|
|
35
|
+
expect(writeSpy).toHaveBeenNthCalledWith(1, `\x1b[1;${24 - BOTTOM_PADDING}r`);
|
|
36
|
+
expect(writeSpy).toHaveBeenNthCalledWith(2, '\x1b[H');
|
|
37
|
+
});
|
|
38
|
+
it('should not set scroll region at boundary (rows = BOTTOM_PADDING + 10)', () => {
|
|
39
|
+
Object.defineProperty(process.stdout, 'rows', {
|
|
40
|
+
value: BOTTOM_PADDING + 10,
|
|
41
|
+
writable: true,
|
|
42
|
+
});
|
|
43
|
+
setupScrollRegion();
|
|
44
|
+
expect(writeSpy).not.toHaveBeenCalled();
|
|
45
|
+
});
|
|
46
|
+
it('should set scroll region when rows is just above boundary', () => {
|
|
47
|
+
Object.defineProperty(process.stdout, 'rows', {
|
|
48
|
+
value: BOTTOM_PADDING + 11,
|
|
49
|
+
writable: true,
|
|
50
|
+
});
|
|
51
|
+
setupScrollRegion();
|
|
52
|
+
expect(writeSpy).toHaveBeenCalledTimes(2);
|
|
53
|
+
});
|
|
54
|
+
it('should handle very large terminal rows', () => {
|
|
55
|
+
Object.defineProperty(process.stdout, 'rows', { value: 200, writable: true });
|
|
56
|
+
setupScrollRegion();
|
|
57
|
+
expect(writeSpy).toHaveBeenCalledTimes(2);
|
|
58
|
+
expect(writeSpy).toHaveBeenNthCalledWith(1, `\x1b[1;${200 - BOTTOM_PADDING}r`);
|
|
59
|
+
});
|
|
60
|
+
it('should use default rows (24) when rows is 0', () => {
|
|
61
|
+
Object.defineProperty(process.stdout, 'rows', { value: 0, writable: true });
|
|
62
|
+
setupScrollRegion();
|
|
63
|
+
// 0 is falsy, so it falls back to 24
|
|
64
|
+
expect(writeSpy).toHaveBeenCalledTimes(2);
|
|
65
|
+
expect(writeSpy).toHaveBeenNthCalledWith(1, `\x1b[1;${24 - BOTTOM_PADDING}r`);
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
describe('resetScrollRegion', () => {
|
|
69
|
+
it('should write reset escape sequence', () => {
|
|
70
|
+
resetScrollRegion();
|
|
71
|
+
expect(writeSpy).toHaveBeenCalledTimes(1);
|
|
72
|
+
expect(writeSpy).toHaveBeenCalledWith('\x1b[r');
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
describe('handleResize', () => {
|
|
76
|
+
it('should call setupScrollRegion logic when terminal has enough rows', () => {
|
|
77
|
+
Object.defineProperty(process.stdout, 'rows', { value: 40, writable: true });
|
|
78
|
+
handleResize();
|
|
79
|
+
expect(writeSpy).toHaveBeenCalledTimes(2);
|
|
80
|
+
expect(writeSpy).toHaveBeenNthCalledWith(1, `\x1b[1;${40 - BOTTOM_PADDING}r`);
|
|
81
|
+
expect(writeSpy).toHaveBeenNthCalledWith(2, '\x1b[H');
|
|
82
|
+
});
|
|
83
|
+
it('should not write when terminal is too small', () => {
|
|
84
|
+
Object.defineProperty(process.stdout, 'rows', { value: 5, writable: true });
|
|
85
|
+
handleResize();
|
|
86
|
+
expect(writeSpy).not.toHaveBeenCalled();
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
describe('clearScreen', () => {
|
|
90
|
+
it('should write clear screen and home cursor escape sequences', () => {
|
|
91
|
+
clearScreen();
|
|
92
|
+
expect(writeSpy).toHaveBeenCalledTimes(1);
|
|
93
|
+
expect(writeSpy).toHaveBeenCalledWith('\x1b[2J\x1b[H');
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
//# sourceMappingURL=terminal.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"terminal.test.js","sourceRoot":"","sources":["../../../src/__tests__/utils/terminal.test.ts"],"names":[],"mappings":"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"}
|