@@ -199,6 +199,47 @@ describe('runList', () => {
199199 } ) ;
200200 } ) ;
201201
202+ it ( 'rejects invalid pagination before requiring credentials' , async ( ) => {
203+ const credentialsPath = join ( mkdtempSync ( join ( tmpdir ( ) , 'cli-p2-no-creds-' ) ) , 'credentials' ) ;
204+ const fetchImpl = vi . fn ( ) ;
205+
206+ await expect (
207+ runList (
208+ { profile : 'default' , output : 'json' , debug : false , pageSize : 1.5 } ,
209+ { credentialsPath, fetchImpl : fetchImpl as unknown as typeof globalThis . fetch } ,
210+ ) ,
211+ ) . rejects . toMatchObject ( {
212+ code : 'VALIDATION_ERROR' ,
213+ exitCode : 5 ,
214+ details : { field : 'page-size' } ,
215+ } ) ;
216+
217+ expect ( fetchImpl ) . not . toHaveBeenCalled ( ) ;
218+ } ) ;
219+
220+ it ( 'rejects invalid dry-run pagination before emitting the dry-run banner' , async ( ) => {
221+ const stderr : string [ ] = [ ] ;
222+ const fetchImpl = vi . fn ( ) ;
223+
224+ await expect (
225+ runList (
226+ { profile : 'default' , output : 'json' , debug : false , dryRun : true , pageSize : 1.5 } ,
227+ {
228+ credentialsPath : join ( mkdtempSync ( join ( tmpdir ( ) , 'cli-p2-dryrun-' ) ) , 'credentials' ) ,
229+ fetchImpl : fetchImpl as unknown as typeof globalThis . fetch ,
230+ stderr : line => stderr . push ( line ) ,
231+ } ,
232+ ) ,
233+ ) . rejects . toMatchObject ( {
234+ code : 'VALIDATION_ERROR' ,
235+ exitCode : 5 ,
236+ details : { field : 'page-size' } ,
237+ } ) ;
238+
239+ expect ( fetchImpl ) . not . toHaveBeenCalled ( ) ;
240+ expect ( stderr . join ( '\n' ) ) . not . toContain ( DRY_RUN_BANNER ) ;
241+ } ) ;
242+
202243 it ( 'rejects pageSize=101 with VALIDATION_ERROR exit 5 (Fix 7 — upper-bound enforced client-side)' , async ( ) => {
203244 // Previously silently clamped to 100; now rejected so callers get fast feedback.
204245 const { credentialsPath } = makeCreds ( ) ;
0 commit comments