@@ -130,5 +130,196 @@ describe('#Auth0 class', () => {
130130 expect ( output ) . to . match ( / │ R e s o u r c e S e r v e r s \s + │ U P D A T E \s + │ R o l e t e s t A P I \s + │ / ) ;
131131 expect ( output ) . to . match ( / └ [ ─ ┴ ] + ┘ / ) ;
132132 } ) ;
133+
134+ it ( 'should output "No changes detected" when all handlers report no changes' , async ( ) => {
135+ process . env . AUTH0_DEBUG = 'true' ;
136+
137+ sandbox
138+ . stub ( calculateDryRunChanges , 'dryRunFormatAssets' )
139+ . callsFake ( async ( assets ) => assets ) ;
140+
141+ const printedMessages : string [ ] = [ ] ;
142+ sandbox . stub ( utils , 'printCLIMessage' ) . callsFake ( ( message : string ) => {
143+ printedMessages . push ( message ) ;
144+ } ) ;
145+
146+ const auth0 = new Auth0 ( mockEmptyClient , mockEmptyAssets , ( key ) => {
147+ const config = {
148+ AUTH0_DOMAIN : 'example-tenant.auth0.com' ,
149+ AUTH0_INPUT_FILE : './tenant.yaml' ,
150+ } ;
151+ return config [ key ] ;
152+ } ) ;
153+
154+ auth0 . handlers = [
155+ {
156+ type : 'clients' ,
157+ dryRunChanges : async ( ) => ( { create : [ ] , update : [ ] , del : [ ] } ) ,
158+ getResourceName : ( item : { name : string } ) => item . name ,
159+ } ,
160+ ] as any ;
161+
162+ const hasChanges = await auth0 . dryRun ( ) ;
163+ const output = printedMessages [ printedMessages . length - 1 ] . replace (
164+ new RegExp ( `${ String . fromCharCode ( 27 ) } \\[[0-9;]*m` , 'g' ) ,
165+ ''
166+ ) ;
167+
168+ expect ( hasChanges ) . to . equal ( false ) ;
169+ expect ( output ) . to . include ( 'No changes detected' ) ;
170+ } ) ;
171+
172+ it ( 'should show DELETE with asterisk note when AUTH0_ALLOW_DELETE is false' , async ( ) => {
173+ process . env . AUTH0_DEBUG = 'true' ;
174+
175+ sandbox
176+ . stub ( calculateDryRunChanges , 'dryRunFormatAssets' )
177+ . callsFake ( async ( assets ) => assets ) ;
178+
179+ const printedMessages : string [ ] = [ ] ;
180+ sandbox . stub ( utils , 'printCLIMessage' ) . callsFake ( ( message : string ) => {
181+ printedMessages . push ( message ) ;
182+ } ) ;
183+
184+ const auth0 = new Auth0 ( mockEmptyClient , mockEmptyAssets , ( key ) => {
185+ const config = {
186+ AUTH0_ALLOW_DELETE : false ,
187+ AUTH0_DOMAIN : 'example-tenant.auth0.com' ,
188+ AUTH0_INPUT_FILE : './tenant.yaml' ,
189+ } ;
190+ return config [ key ] ;
191+ } ) ;
192+
193+ auth0 . handlers = [
194+ {
195+ type : 'clients' ,
196+ dryRunChanges : async ( ) => ( {
197+ create : [ ] ,
198+ update : [ ] ,
199+ del : [ { name : 'Old App' } ] ,
200+ } ) ,
201+ getResourceName : ( item : { name : string } ) => item . name ,
202+ } ,
203+ ] as any ;
204+
205+ const hasChanges = await auth0 . dryRun ( ) ;
206+ const output = printedMessages [ printedMessages . length - 1 ] . replace (
207+ new RegExp ( `${ String . fromCharCode ( 27 ) } \\[[0-9;]*m` , 'g' ) ,
208+ ''
209+ ) ;
210+
211+ expect ( hasChanges ) . to . equal ( true ) ;
212+ expect ( output ) . to . include ( 'Requires AUTH0_ALLOW_DELETE to be enabled' ) ;
213+ expect ( output ) . to . include ( 'DELETE' ) ;
214+ } ) ;
215+
216+ it ( 'should show CREATE changes in the table' , async ( ) => {
217+ process . env . AUTH0_DEBUG = 'true' ;
218+
219+ sandbox
220+ . stub ( calculateDryRunChanges , 'dryRunFormatAssets' )
221+ . callsFake ( async ( assets ) => assets ) ;
222+
223+ const printedMessages : string [ ] = [ ] ;
224+ sandbox . stub ( utils , 'printCLIMessage' ) . callsFake ( ( message : string ) => {
225+ printedMessages . push ( message ) ;
226+ } ) ;
227+
228+ const auth0 = new Auth0 ( mockEmptyClient , mockEmptyAssets , ( key ) => {
229+ const config = {
230+ AUTH0_DOMAIN : 'example-tenant.auth0.com' ,
231+ AUTH0_INPUT_FILE : './tenant.yaml' ,
232+ } ;
233+ return config [ key ] ;
234+ } ) ;
235+
236+ auth0 . handlers = [
237+ {
238+ type : 'actions' ,
239+ dryRunChanges : async ( ) => ( {
240+ create : [ { name : 'New Action' } ] ,
241+ update : [ ] ,
242+ del : [ ] ,
243+ } ) ,
244+ getResourceName : ( item : { name : string } ) => item . name ,
245+ } ,
246+ ] as any ;
247+
248+ const hasChanges = await auth0 . dryRun ( ) ;
249+ const output = printedMessages [ printedMessages . length - 1 ] . replace (
250+ new RegExp ( `${ String . fromCharCode ( 27 ) } \\[[0-9;]*m` , 'g' ) ,
251+ ''
252+ ) ;
253+
254+ expect ( hasChanges ) . to . equal ( true ) ;
255+ expect ( output ) . to . include ( 'CREATE' ) ;
256+ expect ( output ) . to . include ( 'New Action' ) ;
257+ } ) ;
258+
259+ it ( 'should propagate handler errors with type and stage annotations' , async ( ) => {
260+ process . env . AUTH0_DEBUG = 'true' ;
261+
262+ sandbox
263+ . stub ( calculateDryRunChanges , 'dryRunFormatAssets' )
264+ . callsFake ( async ( assets ) => assets ) ;
265+
266+ sandbox . stub ( utils , 'printCLIMessage' ) ;
267+
268+ const auth0 = new Auth0 ( mockEmptyClient , mockEmptyAssets , ( key ) => {
269+ const config = {
270+ AUTH0_DOMAIN : 'example-tenant.auth0.com' ,
271+ } ;
272+ return config [ key ] ;
273+ } ) ;
274+
275+ auth0 . handlers = [
276+ {
277+ type : 'clients' ,
278+ dryRunChanges : async ( ) => {
279+ throw new Error ( 'API failure' ) ;
280+ } ,
281+ getResourceName : ( item : { name : string } ) => item . name ,
282+ } ,
283+ ] as any ;
284+
285+ try {
286+ await auth0 . dryRun ( ) ;
287+ expect . fail ( 'Expected dryRun to throw' ) ;
288+ } catch ( err ) {
289+ expect ( err . message ) . to . equal ( 'API failure' ) ;
290+ expect ( err . type ) . to . equal ( 'clients' ) ;
291+ expect ( err . stage ) . to . equal ( 'dryRun' ) ;
292+ }
293+ } ) ;
294+
295+ it ( 'should use default input path when AUTH0_INPUT_FILE is not set' , async ( ) => {
296+ process . env . AUTH0_DEBUG = 'true' ;
297+
298+ sandbox
299+ . stub ( calculateDryRunChanges , 'dryRunFormatAssets' )
300+ . callsFake ( async ( assets ) => assets ) ;
301+
302+ const printedMessages : string [ ] = [ ] ;
303+ sandbox . stub ( utils , 'printCLIMessage' ) . callsFake ( ( message : string ) => {
304+ printedMessages . push ( message ) ;
305+ } ) ;
306+
307+ const auth0 = new Auth0 ( mockEmptyClient , mockEmptyAssets , ( key ) => {
308+ const config = {
309+ AUTH0_DOMAIN : 'example-tenant.auth0.com' ,
310+ } ;
311+ return config [ key ] ;
312+ } ) ;
313+
314+ auth0 . handlers = [ ] as any ;
315+
316+ await auth0 . dryRun ( ) ;
317+ const output = printedMessages [ printedMessages . length - 1 ] . replace (
318+ new RegExp ( `${ String . fromCharCode ( 27 ) } \\[[0-9;]*m` , 'g' ) ,
319+ ''
320+ ) ;
321+
322+ expect ( output ) . to . include ( './tenant-config-directory/' ) ;
323+ } ) ;
133324 } ) ;
134325} ) ;
0 commit comments