');
});
it("fetches period dataset and refreshes when date range changes", () => {
expect(periodRightSource).toContain("SessionUser.request(");
expect(periodRightSource).toContain("'/superuser/invoicing/period'");
expect(periodRightSource).toContain("dateFrom: dates.computed.formattedStartDate.value");
expect(periodRightSource).toContain("dateTo: dates.computed.formattedEndDate.value");
expect(periodRightSource).toContain("const applyRoutePeriodDates = () =>");
expect(periodRightSource).toContain("dates.functions.setSelection(requestedStartDate, requestedEndDate);");
expect(periodRightSource).toContain("startDate: dates.computed.formattedStartDate.value");
expect(periodRightSource).toContain("endDate: dates.computed.formattedEndDate.value");
expect(periodRightSource).toContain("watch(");
expect(periodRightSource).toContain("[() => dates.variables.start.value, () => dates.variables.end.value]");
expect(periodRightSource).toContain("const loadPeriodForDateChange = () =>");
expect(periodRightSource).toContain("periodPaging.isDateLoading = true;");
expect(periodRightSource).toContain("getPeriod({ forceRefresh: true, showLoading: true })");
expect(periodRightSource).toContain("status.loading = showLoading;");
});
it("uses the list-view reload button as the only visible manual refresh control in searchable period views", () => {
expect(periodViewAllSource).toContain('data-testid="invoicing-period-page-reload-button"');
expect(periodViewAllSource).not.toContain('data-testid="invoicing-period-refreshing"');
});
it("warms current and previous month period pages and preloads adjacent pages", () => {
expect(periodRightSource).toContain("const fetchAndCachePeriodPage = async");
expect(periodRightSource).toContain("preloadAdjacentPeriodPages(requestParameters, paginationMeta)");
expect(periodRightSource).toContain("const warmCurrentAndPreviousPeriodMonths = () =>");
expect(periodRightSource).toContain("const previousMonth = new Date(now.getFullYear(), now.getMonth() - 1, 1)");
expect(periodRightSource).toContain('periodViews = Array.from(new Set(["all", getBackendPeriodView()]))');
expect(periodRightSource).toContain("periodWarm: 1");
expect(periodRightSource).toContain("setCachedPeriodPage(cacheKey, normalizedPeriodResult, paginationMeta)");
expect(periodRightSource).toContain("periodCacheRequestInFlight");
});
it("keeps period statistics free of normal-path debug console noise", () => {
expect(periodStatisticsSource).not.toContain("Response from fixed pricing distribution API");
expect(periodStatisticsSource).not.toContain("Fixed pricing distribution fetched successfully");
expect(periodStatisticsSource).not.toContain("Response from vehicle subscription distribution API");
expect(periodStatisticsSource).not.toContain("Vehicle subscription distribution fetched successfully");
expect(periodStatisticsSource).not.toContain("Department 75 total calculation resulted in null");
expect(periodStatisticsSource).not.toContain("onMounted(() =>");
});
it("defines the open invoice collection label in loaded locale messages", () => {
localeMessages.forEach(({ messages }) => {
expect(messages.global.open).toBeTruthy();
});
});
it("exposes all right-panel period views and click switching", () => {
expect(periodRightSource).toContain("view: 'all'");
expect(periodRightSource).toContain("view: 'invoice_per_order'");
expect(periodRightSource).toContain("view: 'fixed_pricing'");
expect(periodRightSource).toContain("view: 'tank_cleaning'");
expect(periodRightSource).toContain("view: 'special_arrangements'");
expect(periodRightSource).toContain("view: 'vehicle_subscriptions'");
expect(periodRightSource).toContain("view: 'possible_duplicates'");
expect(periodRightSource).toContain("view: 'self_wash'");
expect(periodRightSource).toContain("pendingPeriodView.value = type.view;");
expect(periodRightSource).toContain("view.variables.currentView.value = viewToCommit");
});
it("keeps date selector update action and auto change emission", () => {
expect(periodDateSelectorSource).toContain("showReloadAnimation();");
expect(periodDateSelectorSource).toContain("dates.functions.setSelection(startDate, endDate);");
expect(periodDateSelectorSource).toContain('v-bind:auto-emit-change="true"');
expect(periodDateSelectorSource).toContain(
"const isReloadButtonLoading = computed(() => isReloadAnimationActive.value || periodPaging.isDateLoading)"
);
expect(periodDateSelectorSource).toContain(":class=\"{'is-loading': isReloadButtonLoading}\"");
expect(periodDateSelectorSource).toContain(
'@click="onSelectionChange(dates.variables.start.value, dates.variables.end.value); showReloadAnimation();"'
);
});
it("keeps import-view mapping for all period view keys", () => {
expect(periodViewImportSource).toContain("home: InvoicingBillingPeriodViewHome");
expect(periodViewImportSource).toContain("fixed_pricing: InvoicingBillingPeriodViewAll");
expect(periodViewImportSource).toContain("vehicle_subscriptions: InvoicingBillingPeriodViewAll");
expect(periodViewImportSource).toContain("tank_cleaning: InvoicingBillingPeriodViewAll");
expect(periodViewImportSource).toContain("all: InvoicingBillingPeriodViewAll");
expect(periodViewImportSource).toContain("special_arrangements: InvoicingBillingPeriodViewAll");
expect(periodViewImportSource).toContain("invoice_per_order: InvoicingBillingPeriodViewAll");
expect(periodViewImportSource).toContain("possible_duplicates: InvoicingBillingPeriodViewAll");
expect(periodViewImportSource).toContain("self_wash: InvoicingBillingPeriodViewSelfWash");
});
it("uses the selected period while keeping Selvvask results server-paginated", () => {
expect(periodViewSelfWashSource).toContain(':initial-date-from="initialDateFrom"');
expect(periodViewSelfWashSource).toContain(':initial-date-to="initialDateTo"');
expect(periodViewSelfWashSource).toContain("dates.computed.formattedStartDate.value");
expect(periodViewSelfWashSource).toContain("dates.computed.formattedEndDate.value");
expect(periodViewSelfWashSource).toContain("route.query.xlvaskUsageLogStartTime");
expect(periodViewSelfWashSource).toContain(':inherit-period-filters="true"');
expect(periodViewSelfWashSource).toContain(':load-all-at-once="false"');
expect(xlvaskUsagePaginationSource).toContain("inheritPeriodFilters");
expect(xlvaskUsagePaginationSource).toContain("loadAllAtOnce");
expect(xlvaskUsagePeriodConstantsSource).toContain("export const SELFWASH_PERIOD_ALL_LIMIT = 10000");
expect(xlvaskUsagePaginationSource).toContain("setMetaItemsPerPage(SELFWASH_PERIOD_ALL_LIMIT, false)");
expect(xlvaskUsagePaginationSource).toContain(
"const shouldShowLocalFilters = computed(() => !props.inheritPeriodFilters)"
);
expect(xlvaskUsagePaginationSource).toContain('v-if="shouldShowLocalFilters"');
expect(xlvaskUsagePaginationSource).toContain('v-if="!hideSearchField && shouldShowLocalFilters"');
expect(xlvaskUsagePaginationSource).toContain('v-if="!props.loadAllAtOnce"');
expect(xlvaskUsagePaginationSource).toContain("const buildUsagePaginationParams = (extra = {}) =>");
expect(xlvaskUsagePaginationSource).toContain("dateFrom: props.initialDateFrom");
expect(xlvaskUsagePaginationSource).toContain("dateTo: props.initialDateTo");
expect(xlvaskUsagePaginationSource).toContain("buildUsagePaginationParams()");
});
it("widens the date window around a flagged wash start time to ±7 days (TRU-10)", () => {
// The original spec called for a [start_time - 7d, start_time + 7d] window
// so the highlighted wash is always visible even when it spans midnight
// or falls on the edge of the calendar day.
expect(periodViewSelfWashSource).toContain("FLAGGED_WASH_DATE_WINDOW_DAYS");
expect(periodViewSelfWashSource).toContain("FLAGGED_WASH_DATE_WINDOW_DAYS = 7");
expect(periodViewSelfWashSource).toContain("const shiftDateOnly");
expect(periodViewSelfWashSource).toContain(
"shiftDateOnly(flaggedWashStartDate.value, -FLAGGED_WASH_DATE_WINDOW_DAYS)"
);
expect(periodViewSelfWashSource).toContain(
"shiftDateOnly(flaggedWashStartDate.value, FLAGGED_WASH_DATE_WINDOW_DAYS)"
);
});
it("loads Selvvask selector counts and progress from the selected period", () => {
expect(periodRightSource).toContain("normalizeXlvaskAutopilotSummary");
expect(periodRightSource).toContain("const selfWashCounts = ref(emptySelectorCounts())");
expect(periodRightSource).toContain("buildSelfWashCountsCacheKey");
expect(periodRightSource).toContain("getCachedSelfWashCounts");
expect(periodRightSource).toContain("setCachedSelfWashCounts");
expect(periodRightSource).toContain("'/modules/xlvask/services/usage/orders/summary'");
expect(periodRightSource).toContain("dateFrom");
expect(periodRightSource).toContain("dateTo");
expect(periodRightSource).toContain("if (type.name === 'self_wash')");
expect(periodRightSource).toContain("requires_action: Math.max(0, total - completed)");
expect(periodRightSource).not.toContain("showCounts: false");
expect(periodRightSource).not.toContain("showProgress: false");
});
it("keeps Selvvask usage pagination scoped to the period view", () => {
expect(xlvaskUsagePaginationSource).toContain("usePaginatedList");
expect(xlvaskUsagePaginationSource).toContain("provide(PaginatedListKey, paginatedList)");
expect(xlvaskUsageOrdersTableSource).toContain("usePaginatedListInstance");
expect(xlvaskUsageOrdersTableSource).toContain("const { loadList } = usePaginatedListInstance();");
});
it("wires the Selvvask surface to operator-only accept / reject / ignore actions", () => {
// The Selvvask view (Superuser → Fakturaer → Periode → Selvvask) must
// exclusively surface the operator review actions (Accept / Reject /
// Ignore / Unignore). The autopilot / dry-run / execute / AI adjudication
// flows are no longer wired here — operator review is the whole surface.
expect(periodViewSelfWashSource).not.toContain(":automation-workspace=");
expect(periodViewSelfWashSource).not.toContain("can_review");
expect(periodViewSelfWashSource).not.toContain("can_manage_policy");
expect(xlvaskUsagePaginationSource).toContain(':allow-review-actions="true"');
expect(xlvaskUsagePaginationSource).toContain(':allow-select-multiple="true"');
expect(xlvaskUsagePaginationSource).toContain(':allow-adjudication-actions="false"');
// The orders table exposes the per-row Accept / Reject / Ignore / Unignore
// buttons gated on `allowReviewActions`. The AI-adjudication buttons and
// the legacy "adjudication" tag must never appear in this surface.
expect(xlvaskUsageOrdersTableSource).toContain(
'
'
);
expect(xlvaskUsageOrdersTableSource).toContain(":data-testid=\"'xlvask-accept-' + object.id\"");
expect(xlvaskUsageOrdersTableSource).toContain(":data-testid=\"'xlvask-reject-' + object.id\"");
expect(xlvaskUsageOrdersTableSource).toContain(":data-testid=\"'xlvask-ignore-' + object.id\"");
expect(xlvaskUsageOrdersTableSource).not.toContain("xlvask-adjudication-");
});
it("keeps Selvvask usage entries wrapped inside the period content area", () => {
expect(xlvaskUsageOrdersTableSource).toContain("xlvask-review-table");
expect(xlvaskUsageOrdersTableSource).toContain("xlvask-usage-card");
expect(xlvaskUsageOrdersTableSource).toContain("getCachedXlvaskUsageAmount");
expect(xlvaskUsageOrdersTableSource).toContain("setCachedXlvaskUsageAmount");
expect(xlvaskUsageOrdersTableSource).toContain("object?.total_net_amount");
expect(xlvaskUsageOrdersTableSource).toContain("object.resolution_state");
expect(xlvaskUsageOrdersTableSource).toContain("onClickAccept(object)");
expect(xlvaskUsageOrdersTableSource).toContain("onClickReject(object)");
expect(xlvaskUsageOrdersTableSource).toContain("onClickIgnore(object)");
expect(xlvaskUsageOrdersTableSource).toContain("onClickUnignore(object)");
expect(xlvaskUsageOrdersTableSource).not.toContain("automation.status");
expect(xlvaskUsageOrdersTableSource).not.toContain("scheduleFastLink(object)");
expect(xlvaskUsageOrdersTableSource).not.toContain("xlvask-order-comparison-columns");
});
it("uses summary refresh after operator review and stays on the review endpoints", () => {
// After an operator Accept / Reject / Ignore / Unignore, the pagination
// and the orders table must re-load the summary via the same review
// endpoints that this surface exclusively consumes. No autopilot / dry-run /
// apply / policy-version / readiness-snapshot plumbing survives.
expect(xlvaskUsagePaginationSource).toContain("/modules/xlvask/services/usage/orders/summary");
expect(xlvaskUsagePaginationSource).toContain("xlvask-usage-order-updated");
expect(xlvaskUsagePaginationSource).not.toContain("RUN_POLL_INTERVAL_MS");
expect(xlvaskUsagePaginationSource).not.toContain("RUN_POLL_MAX_DURATION_MS");
expect(xlvaskUsagePaginationSource).not.toContain("recoverActiveAutopilotRun");
expect(xlvaskUsagePaginationSource).not.toContain("loadAutomationControlState");
expect(xlvaskUsagePaginationSource).not.toContain("buildExecutionReadinessSnapshot");
expect(xlvaskUsagePaginationSource).not.toContain("resumeAutopilotPolling");
expect(xlvaskUsagePaginationSource).not.toContain("canStartExecute");
expect(xlvaskUsageOrdersTableSource).toContain("/modules/xlvask/services/usage/orders/${object.id}/");
expect(xlvaskUsageOrdersTableSource).toContain("/modules/xlvask/services/usage/orders/${id}/");
expect(xlvaskUsageOrdersTableSource).not.toContain("/modules/xlvask/services/usage/automation/decisions/preview");
expect(xlvaskUsageOrdersTableSource).not.toContain("/modules/xlvask/services/usage/automation/decisions/apply");
expect(xlvaskUsageOrdersTableSource).not.toContain("if (!confirmation.isConfirmed)");
expect(xlvaskUsageOrdersTableSource).not.toContain("'apply'");
expect(xlvaskUsageOrdersTableSource).not.toContain("'preview'");
});
it("renders a friendly notice when the orders endpoint returns 404", () => {
// The pagination must distinguish a 404 ("API endpoint not implemented
// yet") from other failures and surface a friendly notice instead of
// the generic error popper every other paginated surface uses.
expect(xlvaskUsagePaginationSource).toContain("apiEndpointNotImplemented");
expect(xlvaskUsagePaginationSource).toContain("lastError");
expect(xlvaskUsagePaginationSource).toContain("404");
expect(xlvaskUsagePaginationSource).toContain("xlvask_review.errors.api_endpoint_not_implemented");
expect(xlvaskUsagePaginationSource).toContain("xlvask-api-not-implemented");
expect(xlvaskUsagePaginationSource).toContain('removeError("paginatedGetRequest")');
});
it("ships the API-not-implemented notice in every supported locale", () => {
// The friendly notice must be present in all five source locales so
// the operator reads a real translation rather than a raw key.
for (const locale of localeMessages) {
const notice = locale.messages?.invoicing_period?.xlvask_review?.errors?.api_endpoint_not_implemented;
expect(notice, `locale ${locale.locale} missing api_endpoint_not_implemented`).toBeTruthy();
}
});
it("keeps period subview navigation on valid keys", () => {
expect(periodViewInvoicePerOrderSource).toContain("view.functions.setCurrentView('vehicle_subscriptions')");
expect(periodViewSpecialArrangementsSource).toContain("view.functions.setCurrentView('vehicle_subscriptions')");
expect(periodViewInvoicePerOrderSource).not.toContain("wash_subscriptions");
expect(periodViewSpecialArrangementsSource).not.toContain("wash_subscriptions");
});
it("keeps e-conomic drafts out of completed selector counts and renders a yellow draft segment", () => {
expect(periodRightSource).toContain("const isCustomerDraftBlocked =");
expect(periodRightSource).toContain("const draft = entries.filter(entry => isCustomerDraftBlocked(entry)).length");
expect(periodRightSource).toContain("const completed = Math.max(0, entries.length - requires_action - draft)");
expect(periodRightSource).toContain("return `${type.displayName} (${typeCounts.completed}/${typeCounts.total})`;");
expect(periodRightSource).toContain("period-selector-progress__draft");
expect(periodRightSource).toContain("background: #f6c344");
});
it("renders draft-blocked customers with a warning tag matching the completed tag shape", () => {
expect(periodViewAllSource).toContain('class="tag is-warning is-light is-small"');
expect(periodViewAllSource).toContain('aria-disabled="true"');
expect(periodViewAllSource).toContain("fa-file-alt");
expect(periodViewAllSource).toContain(
':data-testid="`invoicing-period-customer-draft-${customer.customer_number}`"'
);
});
it("scopes customer flag indicators to flags visible in the current customer card", () => {
expect(periodViewAllSource).toContain("const isFlagInCustomerCardScope =");
expect(periodViewAllSource).toContain("const getCustomerScopedFlags =");
expect(periodViewAllSource).toContain("const getCustomerActiveFlagCounts =");
expect(periodViewAllSource).toContain("return getFlagCounts(scopedFlags);");
expect(periodViewAllSource).toContain(
'["order", "order_field", "order_item", "order_item_field"].includes(targetType)'
);
expect(periodViewAllSource).toContain(
"toPositiveIntegerSet(getInvoiceCollectionIdsForTransactionIds(customer, transactionIds)).has(invoiceCollectionId)"
);
expect(periodViewAllSource).toContain("const isOrderLineFlag =");
expect(periodViewAllSource).toContain("const isOrderItemLineFlag =");
expect(periodViewAllSource).toContain("const getCustomerCardFlags = (customer: any) =>");
expect(periodViewAllSource).toContain("!isOrderLineFlag(flag) && !isOrderItemLineFlag(flag)");
expect(periodViewAllSource).toContain(':flags="getCustomerCardFlags(customer)"');
expect(periodViewAllSource).not.toContain("getCustomerExpandedFlags");
expect(periodViewAllSource).toContain(':invoice-period-flags="getCustomerScopedFlags(selectedCustomer)"');
expect(periodViewAllSource).toContain('targetType === "customer"');
expect(periodViewAllSource).toContain('targetType === "collected_order_invoice"');
});
it("groups possible duplicates by vehicle plate and date for comparison", () => {
expect(periodViewAllSource).toContain("buildPossibleDuplicateGroups");
expect(periodViewAllSource).toContain("possibleDuplicateGroupsInCurrentView");
expect(periodViewAllSource).toContain('data-testid="`invoicing-period-duplicate-group-${duplicateGroup.testId}`"');
expect(periodViewAllSource).toContain("duplicate-comparison-row");
expect(periodViewAllSource).toContain(':group-invoice-collection="false"');
expect(periodViewAllSource).not.toContain(':hide-pagination="false"');
expect(periodRightSource).toContain("getCountEntriesForType");
expect(periodRightSource).toContain('typeName !== "possible_duplicates"');
expect(periodRightSource).toContain("buildPossibleDuplicateGroups(entries)");
});
it("uses the invoice period object tree for normal expanded customer rows", () => {
expect(periodViewAllSource).toContain(
'import InvoicingPeriodObjectTree from "@/views/dashboards/superUserDashboard/InvoicingBillingPeriod/components/InvoicingPeriodObjectTree.vue";'
);
expect(periodViewAllSource).toContain(" {
expect(buefyTreeSource).toContain("lazyChildrenCache");
expect(buefyTreeSource).toContain("loadErrorKeys");
expect(buefyTreeSource).toContain('selectionMode?: "none" | "single" | "multiple" | "checkbox"');
expect(buefyTreeSource).toContain("node?.selectable !== false");
expect(buefyTreeSource).toContain("node?.checkable === true");
expect(buefyTreeSource).toContain("ensureChildrenLoadedForCheck");
expect(buefyTreeSource).toContain("progressiveBatchSize");
expect(buefyTreeSource).toContain("visibleChildrenOf");
expect(buefyTreeSource).toContain("remainingChildrenCount");
expect(buefyTreeSource).toContain("const expandAll =");
expect(buefyTreeSource).toContain("EXPAND_ALL_CONCURRENCY = 4");
expect(buefyTreeSource).toContain("defineExpose");
expect(buefyTreeNodeSource).toContain(' tree.retryLoad(node)"');
expect(buefyTreeNodeSource).toContain("b-tree-load-more__button");
expect(periodObjectTreeSource).toContain('selection-mode="checkbox"');
expect(periodObjectTreeSource).toContain(':lazy="true"');
expect(periodObjectTreeSource).toContain(':progressive-batch-size="50"');
expect(periodObjectTreeSource).toContain("@load-error=");
expect(periodObjectTreeSource).toContain("InvoicingPeriodFlagBadge");
expect(periodObjectTreeSource).toContain("getNodeFlags");
expect(periodObjectTreeSource).toContain("getFieldFlags");
expect(periodObjectTreeSource).toContain("getCachedOrderItemRows");
expect(periodObjectTreeSource).toContain("getCachedAttachmentRows");
expect(periodObjectTreeSource).toContain("shouldShowWashCertificateCategory");
expect(periodObjectTreeSource).not.toContain("order?.attachments === undefined");
expect(periodTreeNodeServiceSource).toContain("getTreeAmount");
expect(periodTreeNodeServiceSource).toContain("hasWashCertificateOrderItem");
expect(periodObjectTreeSource).toContain("fetchAttachmentContent");
expect(periodObjectTreeSource).toContain('data-testid="invoice-period-tree-toolbar"');
expect(periodObjectTreeSource).toContain('data-testid="invoice-period-tree-toggle-all"');
expect(periodObjectTreeSource).toContain("`invoice-period-tree-actions-dropdown-${group.type}`");
});
it("keeps registration labels and values from overlapping in compact invoice rows", () => {
expect(periodObjectTreeSource).toContain('key: "registrations"');
expect(periodObjectTreeSource).toContain('class="invoice-period-tree-node-field__line-label"');
expect(periodObjectTreeSource).toContain(".invoice-period-tree-node-field.is-composite");
expect(periodObjectTreeSource).toContain("grid-template-rows: auto auto;");
expect(periodObjectTreeSource).toContain("grid-template-columns: minmax(3rem, max-content) minmax(0, 1fr);");
expect(periodObjectTreeSource).toContain("grid-column: 1 / -1 !important;");
expect(periodObjectTreeSource).toContain(".invoice-period-tree-node-field__line > span:last-child");
expect(periodObjectTreeSource).toContain("overflow-wrap: anywhere;");
});
it("switches narrow object-tree metadata to a consistent four-column grid", () => {
expect(periodObjectTreeSource).toContain("@container (max-width: 56rem)");
expect(periodObjectTreeSource).toContain("grid-template-columns: repeat(4, minmax(0, 1fr));");
expect(periodObjectTreeSource).toContain("`invoice-period-tree-node-field--${field.key}`");
expect(periodObjectTreeSource).toContain(".invoice-period-tree-node-field--total_net_amount");
expect(periodObjectTreeSource).toContain("grid-column: 4 !important;");
});
it("shows the order department in the object-tree metadata", () => {
expect(periodObjectTreeSource).toContain('key: "department"');
expect(periodObjectTreeSource).toContain('label: commonText("department", "Afdeling")');
expect(periodObjectTreeSource).toContain("const orderDepartmentLabel = (order: any) =>");
expect(periodObjectTreeSource).toContain("order?.department_name || order?.department?.name");
expect(periodObjectTreeSource).toContain("getDepartmentName(departmentId)");
expect(periodObjectTreeSource).not.toContain("object.cashier_name ||");
});
it("exposes object-specific lazy child categories and multi-select operations", () => {
[
"COLLECTION_ORDERS",
"COLLECTION_AGREEMENTS",
"COLLECTION_PAYMENTS",
"COLLECTION_ECONOMIC",
"ORDER_ATTACHMENTS_CERTIFICATES",
"ORDER_ATTACHMENTS_IMAGES",
"ORDER_ATTACHMENTS_OTHER",
"ORDER_BOOKINGS",
"ORDER_XLVASK",
"BOOKING_ITEMS",
"XLVASK_ITEMS",
].forEach((category) => {
expect(periodTreeNodeServiceSource).toContain(category);
});
expect(periodObjectTreeSource).toContain("buildOrderItemTableRows");
expect(periodObjectTreeSource).not.toContain("TREE_CATEGORY_TYPES.ORDER_ITEMS");
[
"runCollectionBulkAction",
"moveSelectedOrdersToInvoiceCollection",
"unlinkSelectedOrderBookings",
"unlinkSelectedOrderXlvask",
"deleteSelectedOrderItems",
"resendSelectedWashCertificates",
"resendSelectedBookingCompletionConfirmations",
"decideSelectedXlvaskAutomation",
].forEach((operation) => {
expect(periodObjectTreeSource).toContain(operation);
});
expect(periodObjectTreeSource).toContain("bulk_action_preview");
expect(periodObjectTreeSource).toContain("bulk_action_apply");
expect(periodObjectTreeSource).toContain("createInvoicingPeriodTreeSnapshotLoader");
expect(periodObjectTreeSource).toContain("period_tree_action_preview");
expect(periodObjectTreeSource).toContain("snapshot_revision: activeSnapshot.value?.snapshot_revision");
expect(periodTreeSnapshotSource).toContain('"/superuser/invoicing/period/tree"');
expect(periodTreeSnapshotSource).toContain("complete_total_net_amount");
expect(periodTreeSnapshotSource).toContain("period_total_net_amount");
expect(collectedOrderInvoicesObjectSource).toContain("period_tree_action_preview");
expect(collectedOrderInvoicesObjectSource).toContain("customer_number: parseInt(customer_number)");
expect(collectedOrderInvoicesObjectSource).toContain("snapshot_revision: String(snapshot_revision || '')");
expect(periodObjectTreeSource).toContain("chooseMergeTargetInvoiceCollection");
expect(periodObjectTreeSource).toContain("checkable: true");
expect(periodObjectTreeSource).toContain("uniqueNodesByKey");
expect(periodObjectTreeSource).toContain("const actionGroups = computed");
expect(periodObjectTreeSource).toContain("actionsForType");
expect(periodObjectTreeSource).toContain("runTreeAction");
expect(periodObjectTreeSource).toContain("activeTreeActionKey");
expect(periodObjectTreeSource).toContain("openActionGroupType");
expect(periodObjectTreeSource).toContain("affectedCount: number");
expect(periodObjectTreeSource).toContain("action.affectedCount === 0");
expect(periodObjectTreeSource).toContain("{{ action.affectedCount }}");
expect(periodObjectTreeSource).toContain(
"affectedCount: selectedCollectionCount.value > 1 ? selectedCollectionCount.value : 0"
);
expect(periodObjectTreeSource).toContain("disabled: selectedCollectionCount.value < 2");
expect(periodObjectTreeSource).toContain("affectedCount: selectedOrdersWithBookingCount.value");
expect(periodObjectTreeSource).toContain("affectedCount: selectedOrdersWithWashCount.value");
expect(periodObjectTreeSource).toContain("affectedCount: certificateAttachmentOrderIds.value.length");
expect(periodObjectTreeSource).toContain("affectedCount: actionableXlvaskNodes.value.length");
expect(periodObjectTreeSource).not.toContain("onlySelectedType");
expect(periodObjectTreeSource).not.toContain("selection.mixed_types");
});
it("defines mixed-selection action menu locale labels", () => {
localeMessages.forEach(({ messages }) => {
expect(messages.invoicing_period.object_tree.buttons.actions).toBeTruthy();
expect(messages.invoicing_period.object_tree.buttons.collapse_all).toBeTruthy();
expect(messages.invoicing_period.object_tree.buttons.expand_all).toBeTruthy();
expect(messages.invoicing_period.object_tree.selection.no_actions).toBeTruthy();
});
});
});
describe("Periode runtime view switching", () => {
it("keeps all selectable period views mapped in availableViews", () => {
const selectorViewMatches = [...periodRightSource.matchAll(/view:\s*'([^']+)'/g)].map((m) => m[1]);
const selectableKeys = Array.from(new Set(selectorViewMatches));
const expectedSelectableKeys = [
"all",
"invoice_per_order",
"fixed_pricing",
"tank_cleaning",
"special_arrangements",
"vehicle_subscriptions",
"possible_duplicates",
"self_wash",
];
expect(selectableKeys.sort()).toEqual(expectedSelectableKeys.sort());
selectableKeys.forEach((key) => {
expect(periodViewImportSource).toContain(`${key}:`);
});
expectedSelectableKeys
.filter((key) => key !== "self_wash")
.forEach((key) => {
expect(periodViewImportSource).toContain(`${key}: InvoicingBillingPeriodViewAll`);
});
expect(periodViewImportSource).toContain("self_wash: InvoicingBillingPeriodViewSelfWash");
});
it("keeps home view key available for initial period load", () => {
expect(periodViewImportSource).toContain("home: InvoicingBillingPeriodViewHome");
expect(periodViewImportSource).toContain('const currentView = ref("home")');
});
it("guards setCurrentView with available view existence checks", () => {
expect(periodViewImportSource).toContain("const setCurrentView = (view: keyof typeof availableViews) => {");
expect(periodViewImportSource).toContain("if (availableViews[view]) {");
expect(periodViewImportSource).toContain('console.warn(`View "${view}" does not exist in available views.`);');
});
});