1
+ import assert from 'assert' ;
2
+ import sinon from 'sinon' ;
3
+ import auth from '../../../../Auth.js' ;
4
+ import { CommandInfo } from "../../../../cli/CommandInfo.js" ;
5
+ import { Logger } from '../../../../cli/Logger.js' ;
6
+ import request from '../../../../request.js' ;
7
+ import { telemetry } from '../../../../telemetry.js' ;
8
+ import { pid } from '../../../../utils/pid.js' ;
9
+ import { session } from '../../../../utils/session.js' ;
10
+ import { sinonUtil } from '../../../../utils/sinonUtil.js' ;
11
+ import { cli } from '../../../../cli/cli.js' ;
12
+ import commands from '../../commands.js' ;
13
+ import command from './container-add.js' ;
14
+ import { spo } from '../../../../utils/spo.js' ;
15
+ import { z } from 'zod' ;
16
+ import { CommandError } from '../../../../Command.js' ;
17
+ import { spe } from '../../../../utils/spe.js' ;
18
+
19
+ describe ( commands . CONTAINER_ADD , ( ) => {
20
+ const spoAdminUrl = 'https://contoso-admin.sharepoint.com' ;
21
+ const containerTypeId = 'c6f08d91-77fa-485f-9369-f246ec0fc19c' ;
22
+ const containerTypeName = 'Container type name' ;
23
+ const containerName = 'Invoices' ;
24
+
25
+ const requestResponse = {
26
+ id : 'b!ISJs1WRro0y0EWgkUYcktDa0mE8zSlFEqFzqRn70Zwp1CEtDEBZgQICPkRbil_5Z' ,
27
+ displayName : containerName ,
28
+ description : 'Description of My Application Storage Container' ,
29
+ containerTypeId : containerTypeId ,
30
+ status : 'inactive' ,
31
+ createdDateTime : '2025-04-15T13:31:09.62Z' ,
32
+ lockState : 'unlocked' ,
33
+ settings : {
34
+ isOcrEnabled : false ,
35
+ itemMajorVersionLimit : 500 ,
36
+ isItemVersioningEnabled : true
37
+ }
38
+ } ;
39
+
40
+ let log : string [ ] ;
41
+ let logger : Logger ;
42
+ let loggerLogSpy : sinon . SinonSpy ;
43
+ let commandInfo : CommandInfo ;
44
+ let commandOptionsSchema : z . ZodTypeAny ;
45
+
46
+ before ( ( ) => {
47
+ sinon . stub ( auth , 'restoreAuth' ) . resolves ( ) ;
48
+ sinon . stub ( telemetry , 'trackEvent' ) . resolves ( ) ;
49
+ sinon . stub ( pid , 'getProcessName' ) . returns ( '' ) ;
50
+ sinon . stub ( session , 'getId' ) . returns ( '' ) ;
51
+
52
+ sinon . stub ( spe , 'getContainerTypeIdByName' ) . resolves ( containerTypeId ) ;
53
+
54
+ auth . connection . active = true ;
55
+ auth . connection . spoUrl = spoAdminUrl . replace ( '-admin.sharepoint.com' , '.sharepoint.com' ) ;
56
+ commandInfo = cli . getCommandInfo ( command ) ;
57
+ commandOptionsSchema = commandInfo . command . getSchemaToParse ( ) ! ;
58
+ } ) ;
59
+
60
+ beforeEach ( ( ) => {
61
+ log = [ ] ;
62
+ logger = {
63
+ log : async ( msg : string ) => {
64
+ log . push ( msg ) ;
65
+ } ,
66
+ logRaw : async ( msg : string ) => {
67
+ log . push ( msg ) ;
68
+ } ,
69
+ logToStderr : async ( msg : string ) => {
70
+ log . push ( msg ) ;
71
+ }
72
+ } ;
73
+ loggerLogSpy = sinon . spy ( logger , 'log' ) ;
74
+ } ) ;
75
+
76
+ afterEach ( ( ) => {
77
+ sinonUtil . restore ( [
78
+ request . post
79
+ ] ) ;
80
+ } ) ;
81
+
82
+ after ( ( ) => {
83
+ sinon . restore ( ) ;
84
+ auth . connection . active = false ;
85
+ auth . connection . spoUrl = undefined ;
86
+ } ) ;
87
+
88
+ it ( 'has correct name' , ( ) => {
89
+ assert . strictEqual ( command . name , commands . CONTAINER_ADD ) ;
90
+ } ) ;
91
+
92
+ it ( 'has a description' , ( ) => {
93
+ assert . notStrictEqual ( command . description , null ) ;
94
+ } ) ;
95
+
96
+ it ( 'fails validation if both containerTypeId and containerTypeName options are passed' , async ( ) => {
97
+ const actual = commandOptionsSchema . safeParse ( { name : containerName , containerTypeId : containerTypeId , containerTypeName : containerTypeName } ) ;
98
+ assert . strictEqual ( actual . success , false ) ;
99
+ } ) ;
100
+
101
+ it ( 'fails validation if neither containerTypeId nor containerTypeName options are passed' , async ( ) => {
102
+ const actual = commandOptionsSchema . safeParse ( { name : containerName } ) ;
103
+ assert . strictEqual ( actual . success , false ) ;
104
+ } ) ;
105
+
106
+ it ( 'fails validation if containerTypeId is not a valid GUID' , async ( ) => {
107
+ const actual = commandOptionsSchema . safeParse ( { name : containerName , containerTypeId : 'invalid' } ) ;
108
+ assert . strictEqual ( actual . success , false ) ;
109
+ } ) ;
110
+
111
+ it ( 'passes validation if containerTypeId is a valid GUID' , async ( ) => {
112
+ const actual = commandOptionsSchema . safeParse ( { name : containerName , containerTypeId : containerTypeId } ) ;
113
+ assert . strictEqual ( actual . success , true ) ;
114
+ } ) ;
115
+
116
+ it ( 'fails validation if itemMajorVersionLimit is not a positive integer' , async ( ) => {
117
+ const actual = commandOptionsSchema . safeParse ( { name : containerName , itemMajorVersionLimit : 12.5 } ) ;
118
+ assert . strictEqual ( actual . success , false ) ;
119
+ } ) ;
120
+
121
+ it ( 'correctly logs an output' , async ( ) => {
122
+ sinon . stub ( request , 'post' ) . callsFake ( async ( opts ) => {
123
+ if ( opts . url === 'https://graph.microsoft.com/v1.0/storage/fileStorage/containers' ) {
124
+ return requestResponse ;
125
+ }
126
+
127
+ throw 'Invalid POST request: ' + opts . url ;
128
+ } ) ;
129
+
130
+ await command . action ( logger , { options : { name : containerName , containerTypeId : containerTypeId } } ) ;
131
+ assert ( loggerLogSpy . calledOnceWith ( requestResponse ) ) ;
132
+ } ) ;
133
+
134
+ it ( 'correctly creates a new container with containerTypeId' , async ( ) => {
135
+ const postStub = sinon . stub ( request , 'post' ) . callsFake ( async ( opts ) => {
136
+ if ( opts . url === 'https://graph.microsoft.com/v1.0/storage/fileStorage/containers' ) {
137
+ return requestResponse ;
138
+ }
139
+
140
+ throw 'Invalid POST request: ' + opts . url ;
141
+ } ) ;
142
+
143
+ await command . action ( logger , { options : { name : containerName , description : 'Lorem ipsum' , ocrEnabled : true , itemMajorVersionLimit : 250 , itemVersioningEnabled : true , containerTypeId : containerTypeId } } ) ;
144
+ assert . deepStrictEqual ( postStub . lastCall . args [ 0 ] . data , {
145
+ displayName : containerName ,
146
+ description : 'Lorem ipsum' ,
147
+ containerTypeId : containerTypeId ,
148
+ settings : {
149
+ isOcrEnabled : true ,
150
+ itemMajorVersionLimit : 250 ,
151
+ isItemVersioningEnabled : true
152
+ }
153
+ } ) ;
154
+ } ) ;
155
+
156
+ it ( 'correctly creates a new container with containerTypeName' , async ( ) => {
157
+ const postStub = sinon . stub ( request , 'post' ) . callsFake ( async ( opts ) => {
158
+ if ( opts . url === 'https://graph.microsoft.com/v1.0/storage/fileStorage/containers' ) {
159
+ return requestResponse ;
160
+ }
161
+
162
+ throw 'Invalid POST request: ' + opts . url ;
163
+ } ) ;
164
+
165
+ sinon . stub ( spo , 'getAllContainerTypes' ) . resolves ( [
166
+ {
167
+ AzureSubscriptionId : '/Guid(f08575e2-36c4-407f-a891-eabae23f66bc)/' ,
168
+ ContainerTypeId : `/Guid(${ containerTypeId } )/` ,
169
+ CreationDate : '3/11/2024 2:38:56 PM' ,
170
+ DisplayName : containerTypeName ,
171
+ ExpiryDate : '3/11/2028 2:38:56 PM' ,
172
+ IsBillingProfileRequired : true ,
173
+ OwningAppId : '/Guid(1b3b8660-9a44-4a7c-9c02-657f3ff5d5ac)/' ,
174
+ OwningTenantId : '/Guid(e1dd4023-a656-480a-8a0e-c1b1eec51e1d)/' ,
175
+ Region : 'West Europe' ,
176
+ ResourceGroup : 'Standard group' ,
177
+ SPContainerTypeBillingClassification : 'Standard'
178
+ }
179
+ ] ) ;
180
+
181
+ await command . action ( logger , { options : { name : containerName , description : 'Lorem ipsum' , ocrEnabled : true , itemMajorVersionLimit : 250 , itemVersioningEnabled : true , containerTypeName : containerTypeName , verbose : true } } ) ;
182
+ assert . deepStrictEqual ( postStub . lastCall . args [ 0 ] . data , {
183
+ displayName : containerName ,
184
+ description : 'Lorem ipsum' ,
185
+ containerTypeId : containerTypeId ,
186
+ settings : {
187
+ isOcrEnabled : true ,
188
+ itemMajorVersionLimit : 250 ,
189
+ isItemVersioningEnabled : true
190
+ }
191
+ } ) ;
192
+ } ) ;
193
+
194
+ it ( 'correctly handles error' , async ( ) => {
195
+ sinon . stub ( request , 'post' ) . rejects ( {
196
+ error : {
197
+ code : 'accessDenied' ,
198
+ message : 'Access denied'
199
+ }
200
+ } ) ;
201
+
202
+ await assert . rejects ( command . action ( logger , { options : { name : containerName , containerTypeId : containerTypeId } } ) ,
203
+ new CommandError ( 'Access denied' ) ) ;
204
+ } ) ;
205
+ } ) ;
0 commit comments