11import { expect } from 'chai' ;
2+ import sinon from 'sinon' ;
3+ import { Command as CsCommand } from '@contentstack/cli-command' ;
4+ import * as cliUtilities from '@contentstack/cli-utilities' ;
25import { BaseCommand } from '../../src/base-command' ;
36
7+ /** Concrete command for exercising BaseCommand without production commands. */
8+ class TestExportCommand extends BaseCommand {
9+ static id = 'cm:test-export-cmd' ;
10+ static description = 'Unit test command' ;
11+ async run ( ) : Promise < void > {
12+ // intentionally empty
13+ }
14+
15+ public buildContext ( apiKey ?: string ) {
16+ return this . createCommandContext ( apiKey ) ;
17+ }
18+
19+ public async exposeCatch ( err : Error & { exitCode ?: number } ) {
20+ return this . catch ( err ) ;
21+ }
22+
23+ public async exposeFinally ( err : Error | undefined ) {
24+ return this . finally ( err ) ;
25+ }
26+ }
27+
28+ class CommandWithoutStaticId extends BaseCommand {
29+ static description = 'No static id' ;
30+ async run ( ) : Promise < void > { }
31+
32+ public buildContext ( ) {
33+ return this . createCommandContext ( ) ;
34+ }
35+ }
36+
37+ const minimalConfig = { bin : 'csdx' } as any ;
38+
439describe ( 'BaseCommand' , ( ) => {
540 describe ( 'class definition' , ( ) => {
641 it ( 'should be an abstract class that extends Command' , ( ) => {
@@ -14,4 +49,130 @@ describe('BaseCommand', () => {
1449 expect ( BaseCommand . prototype ) . to . have . property ( 'createCommandContext' ) ;
1550 } ) ;
1651 } ) ;
52+
53+ describe ( 'createCommandContext' , ( ) => {
54+ let sandbox : sinon . SinonSandbox ;
55+
56+ beforeEach ( ( ) => {
57+ sandbox = sinon . createSandbox ( ) ;
58+ sandbox . stub ( cliUtilities . configHandler , 'get' ) . callsFake ( ( key : string ) => {
59+ const map : Record < string , string > = {
60+ userUid : 'user-uid-1' ,
61+ email : 'test@example.com' ,
62+ oauthOrgUid : 'org-uid-1' ,
63+ } ;
64+ return map [ key ] ;
65+ } ) ;
66+ } ) ;
67+
68+ afterEach ( ( ) => {
69+ sandbox . restore ( ) ;
70+ } ) ;
71+
72+ it ( 'should map configHandler fields and command id' , ( ) => {
73+ const cmd = new TestExportCommand ( [ ] , minimalConfig ) ;
74+ const ctx = cmd . buildContext ( ) ;
75+ expect ( ctx . command ) . to . equal ( 'cm:test-export-cmd' ) ;
76+ expect ( ctx . module ) . to . equal ( 'export-to-csv' ) ;
77+ expect ( ctx . userId ) . to . equal ( 'user-uid-1' ) ;
78+ expect ( ctx . email ) . to . equal ( 'test@example.com' ) ;
79+ expect ( ctx . orgId ) . to . equal ( 'org-uid-1' ) ;
80+ expect ( ctx . apiKey ) . to . equal ( '' ) ;
81+ } ) ;
82+
83+ it ( 'should set apiKey when provided' , ( ) => {
84+ const cmd = new TestExportCommand ( [ ] , minimalConfig ) ;
85+ const ctx = cmd . buildContext ( 'stack-api-key' ) ;
86+ expect ( ctx . apiKey ) . to . equal ( 'stack-api-key' ) ;
87+ } ) ;
88+
89+ it ( 'should fall back to default command id when this.id is missing' , ( ) => {
90+ const cmd = new CommandWithoutStaticId ( [ ] , minimalConfig ) ;
91+ ( cmd as any ) . id = undefined ;
92+ const ctx = cmd . buildContext ( ) ;
93+ expect ( ctx . command ) . to . equal ( 'cm:export-to-csv' ) ;
94+ } ) ;
95+
96+ it ( 'should use empty strings when config keys are missing' , ( ) => {
97+ ( sandbox as sinon . SinonSandbox ) . restore ( ) ;
98+ sandbox = sinon . createSandbox ( ) ;
99+ sandbox . stub ( cliUtilities . configHandler , 'get' ) . returns ( undefined ) ;
100+ const cmd = new TestExportCommand ( [ ] , minimalConfig ) ;
101+ const ctx = cmd . buildContext ( ) ;
102+ expect ( ctx . userId ) . to . equal ( '' ) ;
103+ expect ( ctx . email ) . to . equal ( '' ) ;
104+ expect ( ctx . orgId ) . to . equal ( '' ) ;
105+ } ) ;
106+ } ) ;
107+
108+ describe ( 'init' , ( ) => {
109+ let sandbox : sinon . SinonSandbox ;
110+
111+ beforeEach ( ( ) => {
112+ sandbox = sinon . createSandbox ( ) ;
113+ sandbox . stub ( CsCommand . prototype as any , 'init' ) . resolves ( undefined ) ;
114+ sandbox . stub ( cliUtilities . configHandler , 'get' ) . callsFake ( ( key : string ) => {
115+ const map : Record < string , string > = {
116+ userUid : 'u1' ,
117+ email : 'e1@test.com' ,
118+ oauthOrgUid : 'o1' ,
119+ } ;
120+ return map [ key ] ;
121+ } ) ;
122+ } ) ;
123+
124+ afterEach ( ( ) => {
125+ sandbox . restore ( ) ;
126+ } ) ;
127+
128+ it ( 'should await parent init and assign commandContext' , async ( ) => {
129+ const cmd = new TestExportCommand ( [ ] , minimalConfig ) ;
130+ await cmd . init ( ) ;
131+ expect ( cmd . commandContext . userId ) . to . equal ( 'u1' ) ;
132+ expect ( cmd . commandContext . email ) . to . equal ( 'e1@test.com' ) ;
133+ } ) ;
134+ } ) ;
135+
136+ describe ( 'catch and finally' , ( ) => {
137+ let sandbox : sinon . SinonSandbox ;
138+
139+ beforeEach ( ( ) => {
140+ sandbox = sinon . createSandbox ( ) ;
141+ sandbox . stub ( CsCommand . prototype as any , 'init' ) . resolves ( undefined ) ;
142+ sandbox . stub ( cliUtilities . configHandler , 'get' ) . callsFake ( ( key : string ) => {
143+ const map : Record < string , string > = { userUid : 'u' , email : 'e' , oauthOrgUid : 'o' } ;
144+ return map [ key ] ;
145+ } ) ;
146+ } ) ;
147+
148+ afterEach ( ( ) => {
149+ sandbox . restore ( ) ;
150+ } ) ;
151+
152+ it ( 'should delegate catch to parent Command' , async ( ) => {
153+ const parentCatch = sandbox . stub ( CsCommand . prototype as any , 'catch' ) . resolves ( undefined ) ;
154+ const cmd = new TestExportCommand ( [ ] , minimalConfig ) ;
155+ await cmd . init ( ) ;
156+ const err = new Error ( 'test failure' ) as Error & { exitCode ?: number } ;
157+ await cmd . exposeCatch ( err ) ;
158+ expect ( parentCatch . calledOnceWithExactly ( err ) ) . to . be . true ;
159+ } ) ;
160+
161+ it ( 'should delegate finally to parent Command' , async ( ) => {
162+ const parentFinally = sandbox . stub ( CsCommand . prototype as any , 'finally' ) . resolves ( undefined ) ;
163+ const cmd = new TestExportCommand ( [ ] , minimalConfig ) ;
164+ await cmd . init ( ) ;
165+ const err = new Error ( 'x' ) ;
166+ await cmd . exposeFinally ( err ) ;
167+ expect ( parentFinally . calledOnceWithExactly ( err ) ) . to . be . true ;
168+ } ) ;
169+
170+ it ( 'should pass undefined to finally when no error' , async ( ) => {
171+ const parentFinally = sandbox . stub ( CsCommand . prototype as any , 'finally' ) . resolves ( undefined ) ;
172+ const cmd = new TestExportCommand ( [ ] , minimalConfig ) ;
173+ await cmd . init ( ) ;
174+ await cmd . exposeFinally ( undefined ) ;
175+ expect ( parentFinally . calledOnceWithExactly ( undefined ) ) . to . be . true ;
176+ } ) ;
177+ } ) ;
17178} ) ;
0 commit comments