diff --git a/src/lib/pagination.ts b/src/lib/pagination.ts index 107c9a06..20f93b1a 100644 --- a/src/lib/pagination.ts +++ b/src/lib/pagination.ts @@ -3,8 +3,8 @@ import { maskKey } from './config'; import { outputError } from './output'; export function parseLimitOpt(raw: string, globalOpts: GlobalOpts): number { - const limit = parseInt(raw, 10); - if (Number.isNaN(limit) || limit < 1 || limit > 100) { + const limit = Number(raw); + if (!Number.isInteger(limit) || limit < 1 || limit > 100) { outputError( { message: '--limit must be an integer between 1 and 100', diff --git a/tests/lib/pagination.test.ts b/tests/lib/pagination.test.ts index a039394f..9aa05b29 100644 --- a/tests/lib/pagination.test.ts +++ b/tests/lib/pagination.test.ts @@ -10,6 +10,7 @@ import { import type { GlobalOpts } from '../../src/lib/client'; import { buildPaginationOpts, + parseLimitOpt, printPaginationHint, } from '../../src/lib/pagination'; import { captureTestEnv, mockExitThrow, setNonInteractive } from '../helpers'; @@ -67,6 +68,45 @@ describe('buildPaginationOpts', () => { }); }); +describe('parseLimitOpt', () => { + const restoreEnv = captureTestEnv(); + let exitSpy: MockInstance | undefined; + let logSpy: MockInstance | undefined; + + afterEach(() => { + restoreEnv(); + exitSpy?.mockRestore(); + logSpy?.mockRestore(); + exitSpy = undefined; + logSpy = undefined; + }); + + const globalOpts = {} as GlobalOpts; + + it.each(['1', '10', '100'])('accepts %s', (raw) => { + expect(parseLimitOpt(raw, globalOpts)).toBe(Number(raw)); + }); + + it.each([ + '0', + '101', + '', + 'abc', + '2.5', + '25abc', + '1,000', + ])('errors with invalid_limit for %j', (raw) => { + setNonInteractive(); + logSpy = vi.spyOn(console, 'error').mockImplementation(() => {}); + exitSpy = mockExitThrow(); + + expect(() => parseLimitOpt(raw, globalOpts)).toThrow(); + + const output = logSpy.mock.calls.map((call) => call[0]).join(' '); + expect(output).toContain('invalid_limit'); + }); +}); + describe('printPaginationHint', () => { let logSpy: MockInstance;