test(freight-api): cover export field/limit/format resolution

Extracted the export route's format/cap/column-whitelist branching out
of the controller into pure functions (resolveExportFormat,
resolveExportCap, resolveExportColumns) and added a spec: unknown
format falls back to xlsx, limit clamps to the format cap and ignores
non-positive/NaN input, unknown field keys are dropped and an
all-unknown fields list falls back to every column instead of
shipping a blank sheet. Was untested branching logic before this.
This commit is contained in:
Nathnael
2026-08-13 09:07:49 +00:00
parent 6a102bf938
commit cb27d82e8f
3 changed files with 96 additions and 13 deletions

View File

@@ -8,7 +8,8 @@ import { BookingStaff } from '../../common/booking-guards';
import { assertFreightPermission, hasFreightPermission } from '../../common/freight-permission.util';
import { FREIGHT_PERMS, reportPermissionKey } from '../../seed/freight-permissions.registry';
import { UserTradeAccessService } from '../user-trade-access/user-trade-access.service';
import { PDF_ROW_CAP, ReportExportService, XLSX_ROW_CAP } from './report-export.service';
import { ReportExportService } from './report-export.service';
import { resolveExportCap, resolveExportColumns, resolveExportFormat } from './report-export-request.util';
import { RawReportQuery, ReportRunnerService } from './report-runner.service';
import { REPORTS, getReport } from './report.registry';
import { ReportCatalogEntry, ReportDefinition } from './report.types';
@@ -59,18 +60,9 @@ export class ReportsController {
): Promise<void> {
const def = this.resolve(key, user);
const directions = await this.userTradeAccessService.resolveAllowedDirections(user);
const format = query.format === 'pdf' ? 'pdf' : 'xlsx';
const formatCap = format === 'pdf' ? PDF_ROW_CAP : XLSX_ROW_CAP;
const requestedLimit = Number(query.limit);
const cap = requestedLimit > 0 ? Math.min(requestedLimit, formatCap) : formatCap;
// Whitelist against the report's own columns — an unknown/empty `fields`
// value falls back to every column rather than shipping a blank sheet.
const requestedFields = query.fields?.split(',').filter(Boolean);
const columns = requestedFields?.length
? def.columns.filter((c) => requestedFields.includes(c.key))
: def.columns;
const exportColumns = columns.length ? columns : def.columns;
const format = resolveExportFormat(query.format);
const cap = resolveExportCap(format, query.limit);
const exportColumns = resolveExportColumns(def, query.fields);
const { items, kpis } = await this.runner.runAll(def, query, directions, cap);
const buffer =