Files
govoplan-campaign/webui/tests/report-grid-query.test.ts

89 lines
5.8 KiB
TypeScript

import { campaignJobsQueryParams } from "../src/features/campaigns/utils/jobListQuery";
import {
activeReportGridShortcut,
reportGridQueryForShortcut,
toggleReportGridShortcut
} from "../src/features/campaigns/utils/reportGridShortcuts";
declare function require(name: string): {
readFileSync(path: string, encoding: string): string;
};
const { readFileSync } = require("node:fs");
function assert(condition: unknown, message: string): void {
if (!condition) throw new Error(message);
}
const params = campaignJobsQueryParams({
versionId: "version-1",
page: 2,
pageSize: 25,
query: " recipient ",
sortBy: "recipient",
sortDirection: "desc",
filters: {
recipient: "target",
send: 'list:["failed_temporary","outcome_unknown"]',
attempts: "gte:2",
unsupported: "must-not-leak"
}
});
assert(params.get("version_id") === "version-1", "the selected Campaign version is retained");
assert(params.get("page") === "2" && params.get("page_size") === "25", "server pagination is serialized");
assert(params.get("q") === "recipient", "the deep-link search query is normalized");
assert(params.get("sort_by") === "recipient" && params.get("sort_direction") === "desc", "DataGrid sorting is server-owned");
assert(params.get("filter_recipient") === "target", "text filters are sent to the backend");
assert(params.get("filter_send") === 'list:["failed_temporary","outcome_unknown"]', "stable list selections are sent intact");
assert(params.get("filter_attempts") === "gte:2", "typed number filters retain their operator");
assert(!params.toString().includes("unsupported") && !params.toString().includes("must-not-leak"), "only the declared backend filter contract is serialized");
const shortcutFilters = {
smtp_accepted: { send: 'list:["smtp_accepted","sent"]' },
failed: { send: 'list:["failed_temporary","failed_permanent"]' },
outcome_unknown: { send: 'list:["outcome_unknown"]' },
not_attempted: { send: 'list:["not_queued"]' },
smtp_skipped: { send: 'list:["skipped"]' },
cancelled: { send: 'list:["cancelled"]' },
imap_appended: { imap: 'list:["appended"]' },
imap_failed: { imap: 'list:["failed"]' },
imap_skipped: { imap: 'list:["skipped"]' }
} as const;
for (const [shortcutId, filters] of Object.entries(shortcutFilters)) {
const shortcut = reportGridQueryForShortcut(shortcutId as keyof typeof shortcutFilters);
assert(JSON.stringify(shortcut.filters) === JSON.stringify(filters), `${shortcutId} uses the exact backend list filter`);
assert(shortcut.sort?.columnId === "number" && shortcut.sort.direction === "asc", `${shortcutId} restores stable report ordering`);
}
const failedShortcut = toggleReportGridShortcut({
sort: { columnId: "updated", direction: "desc" },
filters: { recipient: "old search", imap: 'list:["appended"]' }
}, "failed");
assert(JSON.stringify(failedShortcut.filters) === JSON.stringify(shortcutFilters.failed), "a shortcut clears unrelated filters");
assert(activeReportGridShortcut(failedShortcut) === "failed", "the exact shortcut query is recognized as active");
const toggledBack = toggleReportGridShortcut(failedShortcut, "failed");
assert(Object.keys(toggledBack.filters).length === 0, "selecting an active count returns to all jobs");
assert(activeReportGridShortcut(toggledBack) === "all", "the cleared query activates the all-jobs shortcut");
const sortedFailedShortcut = { ...failedShortcut, sort: { columnId: "recipient", direction: "desc" as const } };
assert(Object.keys(toggleReportGridShortcut(sortedFailedShortcut, "failed").filters).length === 0, "the active shortcut toggles to all even after the user changes sorting");
const reportSource = readFileSync("src/features/campaigns/CampaignReportPage.tsx", "utf8");
assert(reportSource.includes('mode: "server"'), "the report DataGrid declares server query ownership");
assert(reportSource.includes("totalRows: jobs.total"), "the shared pagination count uses the filtered backend total");
assert(reportSource.includes("onQueryChange={handleJobGridQuery}"), "header sort and filter changes drive the backend query");
assert(reportSource.includes("initialReportGridFilters()"), "status deep links initialize the DataGrid filters");
assert(reportSource.includes("initialReportQuery()"), "q deep links initialize the report search");
assert(reportSource.includes("query={jobGridQuery}"), "external count shortcuts synchronize the visible DataGrid query");
assert(reportSource.includes('setQuery("");') && reportSource.includes('setAppliedQuery("");'), "count shortcuts clear both visible and applied search terms");
assert(reportSource.includes("deliveryOutcomeShortcuts.map") && reportSource.includes("imapOutcomeShortcuts.map"), "top-level delivery counts use one coherent shortcut model");
assert(reportSource.includes('<Button type="button" variant={active ? "primary" : "ghost"}'), "count shortcuts render the central Button directly");
assert(reportSource.includes('aria-pressed={active}'), "count shortcuts expose their selected state accessibly");
assert(reportSource.includes('"skipped",\n"queued"'), "SMTP skipped is a first-class report filter option");
assert(reportSource.includes("i18n:govoplan-campaign.excluded_rows_are_intentionally_omitted_from_del.421a1f00"), "the report explains excluded transport semantics through the bilingual catalog");
assert(reportSource.includes('return status === "skipped" ? "i18n:govoplan-campaign.skipped.5a000ad7"'), "the new skipped filter and status badges use the localized label");
assert(reportSource.includes("cards?.skipped ?? jobs.counts.send?.skipped"), "SMTP skipped has a separate report count");
assert(reportSource.includes("cards?.imap_skipped ?? jobs.counts.imap?.skipped"), "IMAP skipped has a separate report count");
assert(!reportSource.includes("setPage((value) => Math.max(1, value - 1))"), "the one-off report pager is removed in favor of the central DataGrid pager");