diff --git a/src/middleware/entityIssueDetails.middleware.js b/src/middleware/entityIssueDetails.middleware.js index 866431cd4..19ce19707 100644 --- a/src/middleware/entityIssueDetails.middleware.js +++ b/src/middleware/entityIssueDetails.middleware.js @@ -26,7 +26,17 @@ export const IssueDetailsQueryParams = v.object({ dataset: v.string(), issue_type: v.string(), issue_field: v.string(), - pageNumber: v.optional(v.pipe(v.string(), v.transform(s => parseInt(s, 10)), v.minValue(1)), '1'), + pageNumber: v.optional( + v.pipe( + v.string(), + v.regex(/^\d+$/), + v.transform(s => Number(s)), + v.number(), + v.integer(), + v.minValue(1) + ), + '1' + ), resourceId: v.optional(v.string()) }) diff --git a/test/unit/middleware/entityIssueDetails.middleware.test.js b/test/unit/middleware/entityIssueDetails.middleware.test.js index 7e4704ca0..61dea1d9f 100644 --- a/test/unit/middleware/entityIssueDetails.middleware.test.js +++ b/test/unit/middleware/entityIssueDetails.middleware.test.js @@ -1,5 +1,7 @@ import { describe, it, vi, expect, beforeEach } from 'vitest' -import { getIssueDetails, getIssueField, prepareEntity, setRecordCount, show404ifNoIssues } from '../../../src/middleware/entityIssueDetails.middleware.js' +import * as v from 'valibot' +import { isValiError } from 'valibot' +import { IssueDetailsQueryParams, getIssueDetails, getIssueField, prepareEntity, setRecordCount, show404ifNoIssues } from '../../../src/middleware/entityIssueDetails.middleware.js' import { MiddlewareError } from '../../../src/utils/errors.js' vi.mock('../../../src/services/performanceDbApi.js') @@ -255,4 +257,29 @@ describe('issueDetails.middleware.js', () => { expect(next).toHaveBeenCalledWith() }) }) + + describe('IssueDetailsQueryParams', () => { + const validBaseParams = { + lpa: 'local-authority:LIV', + dataset: 'tree-preservation-zone', + issue_type: 'missing associated entity', + issue_field: 'tree-preservation-order' + } + + it('transforms a valid numeric pageNumber string to a number', () => { + const result = v.parse(IssueDetailsQueryParams, { ...validBaseParams, pageNumber: '2' }) + expect(result.pageNumber).toBe(2) + }) + + it('throws a ValiError when pageNumber is not numeric', () => { + let thrown + try { + v.parse(IssueDetailsQueryParams, { ...validBaseParams, pageNumber: 'TPO335.G19' }) + } catch (error) { + thrown = error + } + expect(thrown).toBeDefined() + expect(isValiError(thrown)).toBe(true) + }) + }) })