11import { Test } from '@nestjs/testing' ;
22
3+ import { InquirerService } from 'nest-commander' ;
34import { beforeEach , describe , expect , it , vi } from 'vitest' ;
45
56import { CliInternalClientService } from '@app/unraid-api/cli/internal-client.service.js' ;
@@ -10,6 +11,8 @@ import {
1011 RemovePluginCommand ,
1112} from '@app/unraid-api/cli/plugins/plugin.command.js' ;
1213import { RestartCommand } from '@app/unraid-api/cli/restart.command.js' ;
14+ import { PluginManagementService } from '@app/unraid-api/plugin/plugin-management.service.js' ;
15+ import { PluginService } from '@app/unraid-api/plugin/plugin.service.js' ;
1316
1417// Mock services
1518const mockInternalClient = {
@@ -20,12 +23,32 @@ const mockLogger = {
2023 log : vi . fn ( ) ,
2124 info : vi . fn ( ) ,
2225 error : vi . fn ( ) ,
26+ warn : vi . fn ( ) ,
27+ table : vi . fn ( ) ,
2328} ;
2429
2530const mockRestartCommand = {
2631 run : vi . fn ( ) ,
2732} ;
2833
34+ const mockPluginManagementService = {
35+ addPlugin : vi . fn ( ) ,
36+ addBundledPlugin : vi . fn ( ) ,
37+ removePlugin : vi . fn ( ) ,
38+ removeBundledPlugin : vi . fn ( ) ,
39+ plugins : [ ] as string [ ] ,
40+ } ;
41+
42+ const mockInquirerService = {
43+ prompt : vi . fn ( ) ,
44+ } ;
45+
46+ vi . mock ( '@app/unraid-api/plugin/plugin.service.js' , ( ) => ( {
47+ PluginService : {
48+ listPlugins : vi . fn ( ) ,
49+ } ,
50+ } ) ) ;
51+
2952describe ( 'Plugin Commands' , ( ) => {
3053 beforeEach ( ( ) => {
3154 // Clear mocks before each test
@@ -39,94 +62,40 @@ describe('Plugin Commands', () => {
3962 const module = await Test . createTestingModule ( {
4063 providers : [
4164 InstallPluginCommand ,
42- { provide : CliInternalClientService , useValue : mockInternalClient } ,
4365 { provide : LogService , useValue : mockLogger } ,
4466 { provide : RestartCommand , useValue : mockRestartCommand } ,
67+ { provide : PluginManagementService , useValue : mockPluginManagementService } ,
4568 ] ,
4669 } ) . compile ( ) ;
4770
4871 command = module . get < InstallPluginCommand > ( InstallPluginCommand ) ;
4972 } ) ;
5073
5174 it ( 'should install a plugin successfully' , async ( ) => {
52- const mockClient = {
53- mutate : vi . fn ( ) . mockResolvedValue ( {
54- data : {
55- addPlugin : false , // No manual restart required
56- } ,
57- } ) ,
58- } ;
59-
60- mockInternalClient . getClient . mockResolvedValue ( mockClient ) ;
61-
6275 await command . run ( [ '@unraid/plugin-example' ] , { bundled : false , restart : true } ) ;
6376
64- expect ( mockClient . mutate ) . toHaveBeenCalledWith ( {
65- mutation : expect . anything ( ) ,
66- variables : {
67- input : {
68- names : [ '@unraid/plugin-example' ] ,
69- bundled : false ,
70- restart : true ,
71- } ,
72- } ,
73- } ) ;
77+ expect ( mockPluginManagementService . addPlugin ) . toHaveBeenCalledWith ( '@unraid/plugin-example' ) ;
7478 expect ( mockLogger . log ) . toHaveBeenCalledWith ( 'Added plugin @unraid/plugin-example' ) ;
75- expect ( mockRestartCommand . run ) . not . toHaveBeenCalled ( ) ; // Because addPlugin returned false
79+ expect ( mockRestartCommand . run ) . toHaveBeenCalled ( ) ;
7680 } ) ;
7781
7882 it ( 'should handle bundled plugin installation' , async ( ) => {
79- const mockClient = {
80- mutate : vi . fn ( ) . mockResolvedValue ( {
81- data : {
82- addPlugin : true , // Manual restart required
83- } ,
84- } ) ,
85- } ;
86-
87- mockInternalClient . getClient . mockResolvedValue ( mockClient ) ;
88-
8983 await command . run ( [ '@unraid/bundled-plugin' ] , { bundled : true , restart : true } ) ;
9084
91- expect ( mockClient . mutate ) . toHaveBeenCalledWith ( {
92- mutation : expect . anything ( ) ,
93- variables : {
94- input : {
95- names : [ '@unraid/bundled-plugin' ] ,
96- bundled : true ,
97- restart : true ,
98- } ,
99- } ,
100- } ) ;
85+ expect ( mockPluginManagementService . addBundledPlugin ) . toHaveBeenCalledWith (
86+ '@unraid/bundled-plugin'
87+ ) ;
10188 expect ( mockLogger . log ) . toHaveBeenCalledWith ( 'Added bundled plugin @unraid/bundled-plugin' ) ;
102- expect ( mockRestartCommand . run ) . toHaveBeenCalled ( ) ; // Because addPlugin returned true
89+ expect ( mockRestartCommand . run ) . toHaveBeenCalled ( ) ;
10390 } ) ;
10491
10592 it ( 'should not restart when restart option is false' , async ( ) => {
106- const mockClient = {
107- mutate : vi . fn ( ) . mockResolvedValue ( {
108- data : {
109- addPlugin : true ,
110- } ,
111- } ) ,
112- } ;
113-
114- mockInternalClient . getClient . mockResolvedValue ( mockClient ) ;
115-
11693 await command . run ( [ '@unraid/plugin' ] , { bundled : false , restart : false } ) ;
11794
95+ expect ( mockPluginManagementService . addPlugin ) . toHaveBeenCalledWith ( '@unraid/plugin' ) ;
11896 expect ( mockRestartCommand . run ) . not . toHaveBeenCalled ( ) ;
11997 } ) ;
12098
121- it ( 'should handle errors' , async ( ) => {
122- mockInternalClient . getClient . mockRejectedValue ( new Error ( 'Connection failed' ) ) ;
123-
124- await command . run ( [ '@unraid/plugin' ] , { bundled : false , restart : true } ) ;
125-
126- expect ( mockLogger . error ) . toHaveBeenCalledWith ( 'Failed to add plugin:' , expect . any ( Error ) ) ;
127- expect ( process . exitCode ) . toBe ( 1 ) ;
128- } ) ;
129-
13099 it ( 'should error when no package name provided' , async ( ) => {
131100 await command . run ( [ ] , { bundled : false , restart : true } ) ;
132101
@@ -142,57 +111,58 @@ describe('Plugin Commands', () => {
142111 const module = await Test . createTestingModule ( {
143112 providers : [
144113 RemovePluginCommand ,
145- { provide : CliInternalClientService , useValue : mockInternalClient } ,
146114 { provide : LogService , useValue : mockLogger } ,
115+ { provide : PluginManagementService , useValue : mockPluginManagementService } ,
147116 { provide : RestartCommand , useValue : mockRestartCommand } ,
117+ { provide : InquirerService , useValue : mockInquirerService } ,
148118 ] ,
149119 } ) . compile ( ) ;
150120
151121 command = module . get < RemovePluginCommand > ( RemovePluginCommand ) ;
152122 } ) ;
153123
154- it ( 'should remove a plugin successfully' , async ( ) => {
155- const mockClient = {
156- mutate : vi . fn ( ) . mockResolvedValue ( {
157- data : {
158- removePlugin : false , // No manual restart required
159- } ,
160- } ) ,
161- } ;
124+ it ( 'should remove plugins successfully' , async ( ) => {
125+ mockInquirerService . prompt . mockResolvedValue ( {
126+ plugins : [ '@unraid/plugin-example' , '@unraid/plugin-test' ] ,
127+ restart : true ,
128+ } ) ;
162129
163- mockInternalClient . getClient . mockResolvedValue ( mockClient ) ;
130+ await command . run ( [ ] , { restart : true } ) ;
164131
165- await command . run ( [ '@unraid/plugin-example' ] , { bundled : false , restart : true } ) ;
132+ expect ( mockPluginManagementService . removePlugin ) . toHaveBeenCalledWith (
133+ '@unraid/plugin-example' ,
134+ '@unraid/plugin-test'
135+ ) ;
136+ expect ( mockLogger . log ) . toHaveBeenCalledWith ( 'Removed plugin @unraid/plugin-example' ) ;
137+ expect ( mockLogger . log ) . toHaveBeenCalledWith ( 'Removed plugin @unraid/plugin-test' ) ;
138+ expect ( mockRestartCommand . run ) . toHaveBeenCalled ( ) ;
139+ } ) ;
166140
167- expect ( mockClient . mutate ) . toHaveBeenCalledWith ( {
168- mutation : expect . anything ( ) ,
169- variables : {
170- input : {
171- names : [ '@unraid/plugin-example' ] ,
172- bundled : false ,
173- restart : true ,
174- } ,
175- } ,
141+ it ( 'should handle when no plugins are selected' , async ( ) => {
142+ mockInquirerService . prompt . mockResolvedValue ( {
143+ plugins : [ ] ,
144+ restart : true ,
176145 } ) ;
177- expect ( mockLogger . log ) . toHaveBeenCalledWith ( 'Removed plugin @unraid/plugin-example' ) ;
146+
147+ await command . run ( [ ] , { restart : true } ) ;
148+
149+ expect ( mockLogger . warn ) . toHaveBeenCalledWith ( 'No plugins selected for removal.' ) ;
150+ expect ( mockPluginManagementService . removePlugin ) . not . toHaveBeenCalled ( ) ;
178151 expect ( mockRestartCommand . run ) . not . toHaveBeenCalled ( ) ;
179152 } ) ;
180153
181- it ( 'should handle removing bundled plugins' , async ( ) => {
182- const mockClient = {
183- mutate : vi . fn ( ) . mockResolvedValue ( {
184- data : {
185- removePlugin : true , // Manual restart required
186- } ,
187- } ) ,
188- } ;
154+ it ( 'should skip restart when --no-restart is specified' , async ( ) => {
155+ mockInquirerService . prompt . mockResolvedValue ( {
156+ plugins : [ '@unraid/plugin-example' ] ,
157+ restart : false ,
158+ } ) ;
189159
190- mockInternalClient . getClient . mockResolvedValue ( mockClient ) ;
160+ await command . run ( [ ] , { restart : false } ) ;
191161
192- await command . run ( [ '@unraid/bundled-plugin' ] , { bundled : true , restart : true } ) ;
193-
194- expect ( mockLogger . log ) . toHaveBeenCalledWith ( 'Removed bundled plugin @unraid/bundled-plugin' ) ;
195- expect ( mockRestartCommand . run ) . toHaveBeenCalled ( ) ;
162+ expect ( mockPluginManagementService . removePlugin ) . toHaveBeenCalledWith (
163+ '@unraid/plugin-example'
164+ ) ;
165+ expect ( mockRestartCommand . run ) . not . toHaveBeenCalled ( ) ;
196166 } ) ;
197167 } ) ;
198168
@@ -203,72 +173,46 @@ describe('Plugin Commands', () => {
203173 const module = await Test . createTestingModule ( {
204174 providers : [
205175 ListPluginCommand ,
206- { provide : CliInternalClientService , useValue : mockInternalClient } ,
207176 { provide : LogService , useValue : mockLogger } ,
177+ { provide : PluginManagementService , useValue : mockPluginManagementService } ,
208178 ] ,
209179 } ) . compile ( ) ;
210180
211181 command = module . get < ListPluginCommand > ( ListPluginCommand ) ;
212182 } ) ;
213183
214184 it ( 'should list installed plugins' , async ( ) => {
215- const mockClient = {
216- query : vi . fn ( ) . mockResolvedValue ( {
217- data : {
218- plugins : [
219- {
220- name : '@unraid/plugin-1' ,
221- version : '1.0.0' ,
222- hasApiModule : true ,
223- hasCliModule : false ,
224- } ,
225- {
226- name : '@unraid/plugin-2' ,
227- version : '2.0.0' ,
228- hasApiModule : true ,
229- hasCliModule : true ,
230- } ,
231- ] ,
232- } ,
233- } ) ,
234- } ;
235-
236- mockInternalClient . getClient . mockResolvedValue ( mockClient ) ;
185+ vi . mocked ( PluginService . listPlugins ) . mockResolvedValue ( [
186+ [ '@unraid/plugin-1' , '1.0.0' ] ,
187+ [ '@unraid/plugin-2' , '2.0.0' ] ,
188+ ] ) ;
189+ mockPluginManagementService . plugins = [ '@unraid/plugin-1' , '@unraid/plugin-2' ] ;
237190
238191 await command . run ( ) ;
239192
240- expect ( mockClient . query ) . toHaveBeenCalledWith ( {
241- query : expect . anything ( ) ,
242- } ) ;
243193 expect ( mockLogger . log ) . toHaveBeenCalledWith ( 'Installed plugins:\n' ) ;
244- expect ( mockLogger . log ) . toHaveBeenCalledWith ( '☑️ @unraid/[email protected] [API] ' ) ; 245- expect ( mockLogger . log ) . toHaveBeenCalledWith ( '☑️ @unraid/[email protected] [API, CLI] ' ) ; 194+ expect ( mockLogger . log ) . toHaveBeenCalledWith ( '☑️ @unraid/[email protected] ' ) ; 195+ expect ( mockLogger . log ) . toHaveBeenCalledWith ( '☑️ @unraid/[email protected] ' ) ; 246196 expect ( mockLogger . log ) . toHaveBeenCalledWith ( ) ;
247197 } ) ;
248198
249199 it ( 'should handle no plugins installed' , async ( ) => {
250- const mockClient = {
251- query : vi . fn ( ) . mockResolvedValue ( {
252- data : {
253- plugins : [ ] ,
254- } ,
255- } ) ,
256- } ;
257-
258- mockInternalClient . getClient . mockResolvedValue ( mockClient ) ;
200+ vi . mocked ( PluginService . listPlugins ) . mockResolvedValue ( [ ] ) ;
201+ mockPluginManagementService . plugins = [ ] ;
259202
260203 await command . run ( ) ;
261204
262205 expect ( mockLogger . log ) . toHaveBeenCalledWith ( 'No plugins installed.' ) ;
263206 } ) ;
264207
265- it ( 'should handle errors' , async ( ) => {
266- mockInternalClient . getClient . mockRejectedValue ( new Error ( 'Connection failed' ) ) ;
208+ it ( 'should warn about plugins not installed' , async ( ) => {
209+ vi . mocked ( PluginService . listPlugins ) . mockResolvedValue ( [ [ '@unraid/plugin-1' , '1.0.0' ] ] ) ;
210+ mockPluginManagementService . plugins = [ '@unraid/plugin-1' , '@unraid/plugin-2' ] ;
267211
268212 await command . run ( ) ;
269213
270- expect ( mockLogger . error ) . toHaveBeenCalledWith ( 'Failed to list plugins:' , expect . any ( Error ) ) ;
271- expect ( process . exitCode ) . toBe ( 1 ) ;
214+ expect ( mockLogger . warn ) . toHaveBeenCalledWith ( '1 plugins are not installed:' ) ;
215+ expect ( mockLogger . table ) . toHaveBeenCalledWith ( 'warn' , [ '@unraid/plugin-2' ] ) ;
272216 } ) ;
273217 } ) ;
274218} ) ;
0 commit comments