|
2 | 2 | * Tests for plugin management: install, uninstall, list. |
3 | 3 | */ |
4 | 4 |
|
5 | | -import { describe, it, expect, beforeEach, afterEach } from 'vitest'; |
| 5 | +import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'; |
6 | 6 | import * as fs from 'node:fs'; |
7 | 7 | import * as path from 'node:path'; |
8 | 8 | import { PLUGINS_DIR } from './discovery.js'; |
9 | | -import { listPlugins, uninstallPlugin, updatePlugin, _parseSource, _validatePluginStructure } from './plugin.js'; |
| 9 | +import * as pluginModule from './plugin.js'; |
| 10 | + |
| 11 | +const { |
| 12 | + listPlugins, |
| 13 | + uninstallPlugin, |
| 14 | + updatePlugin, |
| 15 | + _parseSource, |
| 16 | + _updateAllPlugins, |
| 17 | + _validatePluginStructure, |
| 18 | +} = pluginModule; |
10 | 19 |
|
11 | 20 | describe('parseSource', () => { |
12 | 21 | it('parses github:user/repo format', () => { |
@@ -151,3 +160,55 @@ describe('updatePlugin', () => { |
151 | 160 | expect(() => updatePlugin('__nonexistent__')).toThrow('not installed'); |
152 | 161 | }); |
153 | 162 | }); |
| 163 | + |
| 164 | +vi.mock('node:child_process', () => { |
| 165 | + return { |
| 166 | + execFileSync: vi.fn((_cmd, _args, opts) => { |
| 167 | + if (opts && opts.cwd && String(opts.cwd).endsWith('plugin-b')) { |
| 168 | + throw new Error('Network error'); |
| 169 | + } |
| 170 | + return ''; |
| 171 | + }), |
| 172 | + execSync: vi.fn(() => ''), |
| 173 | + }; |
| 174 | +}); |
| 175 | + |
| 176 | +describe('updateAllPlugins', () => { |
| 177 | + const testDirA = path.join(PLUGINS_DIR, 'plugin-a'); |
| 178 | + const testDirB = path.join(PLUGINS_DIR, 'plugin-b'); |
| 179 | + const testDirC = path.join(PLUGINS_DIR, 'plugin-c'); |
| 180 | + |
| 181 | + beforeEach(() => { |
| 182 | + fs.mkdirSync(testDirA, { recursive: true }); |
| 183 | + fs.mkdirSync(testDirB, { recursive: true }); |
| 184 | + fs.mkdirSync(testDirC, { recursive: true }); |
| 185 | + fs.writeFileSync(path.join(testDirA, 'cmd.yaml'), 'site: a'); |
| 186 | + fs.writeFileSync(path.join(testDirB, 'cmd.yaml'), 'site: b'); |
| 187 | + fs.writeFileSync(path.join(testDirC, 'cmd.yaml'), 'site: c'); |
| 188 | + }); |
| 189 | + |
| 190 | + afterEach(() => { |
| 191 | + try { fs.rmSync(testDirA, { recursive: true }); } catch {} |
| 192 | + try { fs.rmSync(testDirB, { recursive: true }); } catch {} |
| 193 | + try { fs.rmSync(testDirC, { recursive: true }); } catch {} |
| 194 | + vi.clearAllMocks(); |
| 195 | + }); |
| 196 | + |
| 197 | + it('collects successes and failures without throwing', () => { |
| 198 | + const results = _updateAllPlugins(); |
| 199 | + |
| 200 | + const resA = results.find(r => r.name === 'plugin-a'); |
| 201 | + const resB = results.find(r => r.name === 'plugin-b'); |
| 202 | + const resC = results.find(r => r.name === 'plugin-c'); |
| 203 | + |
| 204 | + expect(resA).toBeDefined(); |
| 205 | + expect(resA!.success).toBe(true); |
| 206 | + |
| 207 | + expect(resB).toBeDefined(); |
| 208 | + expect(resB!.success).toBe(false); |
| 209 | + expect(resB!.error).toContain('Network error'); |
| 210 | + |
| 211 | + expect(resC).toBeDefined(); |
| 212 | + expect(resC!.success).toBe(true); |
| 213 | + }); |
| 214 | +}); |
0 commit comments