- Introduced `.prettierrc.json` to enforce consistent code formatting across the project. - Updated unit and e2e test files to address formatting issues, improve readability, and ensure alignment with the new Prettier configuration.
208 lines
12 KiB
JavaScript
208 lines
12 KiB
JavaScript
import { readFileSync } from "node:fs";
|
|
import { join } from "node:path";
|
|
import { describe, expect, it } from "vitest";
|
|
|
|
const root = process.cwd();
|
|
|
|
const routerSource = readFileSync(join(root, "src/router.js"), "utf8");
|
|
const invoicesViewSource = readFileSync(
|
|
join(root, "src/views/dashboards/superUserDashboard/CollectedOrderInvoices.vue"),
|
|
"utf8"
|
|
);
|
|
const distributionOverviewSource = readFileSync(
|
|
join(root, "src/views/dashboards/superUserDashboard/invoiceDistribution/InvoiceDistributionOverview.vue"),
|
|
"utf8"
|
|
);
|
|
const distributionMonthSource = readFileSync(
|
|
join(root, "src/views/dashboards/superUserDashboard/invoiceDistribution/InvoiceDistributionMonthView.vue"),
|
|
"utf8"
|
|
);
|
|
const distributionApiSource = readFileSync(
|
|
join(root, "src/views/dashboards/superUserDashboard/invoiceDistribution/imports/invoiceDistributionApi.js"),
|
|
"utf8"
|
|
);
|
|
const distributionChartSource = readFileSync(
|
|
join(
|
|
root,
|
|
"src/views/dashboards/superUserDashboard/invoiceDistribution/components/InvoiceDistributionTrendChart.vue"
|
|
),
|
|
"utf8"
|
|
);
|
|
const distributionSkeletonSource = readFileSync(
|
|
join(root, "src/views/dashboards/superUserDashboard/invoiceDistribution/components/InvoiceDistributionSkeleton.vue"),
|
|
"utf8"
|
|
);
|
|
|
|
describe("superuser invoice distribution routing", () => {
|
|
it("keeps monthly distribution routes and route contract unchanged", () => {
|
|
expect(routerSource).toContain("name: 'collectedorderinvoicesdistribution'");
|
|
expect(routerSource).toContain("path: '/superuser/invoices/distribution/:year/:month'");
|
|
expect(routerSource).toContain("name: 'collectedorderinvoicesdistributiontab'");
|
|
expect(routerSource).toContain("path: '/superuser/invoices/distribution/:year/:month/:tab'");
|
|
expect(routerSource).toContain("component: InvoiceDistributionMonthView");
|
|
});
|
|
});
|
|
|
|
describe("CollectedOrderInvoices distribution tab contract", () => {
|
|
it("keeps Distribution tab wired to overview component", () => {
|
|
expect(invoicesViewSource).toContain("slot: 'distribution'");
|
|
expect(invoicesViewSource).toContain("name: t('superuser_invoice_distribution.tab_label')");
|
|
expect(invoicesViewSource).toContain("case 'distribution':");
|
|
expect(invoicesViewSource).toContain("return InvoiceDistributionOverview;");
|
|
});
|
|
});
|
|
|
|
describe("Distribution overview contract", () => {
|
|
it("renders decision-first shell sections and executive scanning order", () => {
|
|
expect(distributionOverviewSource).toContain('class="overview-header hero-surface"');
|
|
expect(distributionOverviewSource).toContain('class="control-toolbar');
|
|
expect(distributionOverviewSource).toContain('class="kpi-strip"');
|
|
expect(distributionOverviewSource).toContain('class="chart-section"');
|
|
expect(distributionOverviewSource).toContain("distribution-table");
|
|
expect(distributionOverviewSource).toContain('class="insights-grid"');
|
|
});
|
|
|
|
it("supports month/total sorting and source composition cues", () => {
|
|
expect(distributionOverviewSource).toContain("const sortKey = ref('month')");
|
|
expect(distributionOverviewSource).toContain("const sortDirection = ref('desc')");
|
|
expect(distributionOverviewSource).toContain("setSort('month')");
|
|
expect(distributionOverviewSource).toContain("setSort('total')");
|
|
expect(distributionOverviewSource).toContain("sortMonthSummaries(filteredMonthSummaries.value");
|
|
expect(distributionOverviewSource).toContain("source-composition__segment--fixed");
|
|
expect(distributionOverviewSource).toContain("source-composition__segment--subscription");
|
|
expect(distributionOverviewSource).toContain("source-composition__segment--customer-prices");
|
|
expect(distributionOverviewSource).toContain("metrics.customer_prices");
|
|
});
|
|
|
|
it("keeps loading, error, and empty states with recovery actions", () => {
|
|
expect(distributionOverviewSource).toContain("InvoiceDistributionSkeleton");
|
|
expect(distributionOverviewSource).toContain("superuser_invoice_distribution.errors.overview_load_failed");
|
|
expect(distributionOverviewSource).toContain("superuser_invoice_distribution.actions.try_again");
|
|
expect(distributionOverviewSource).toContain("superuser_invoice_distribution.empty.no_months");
|
|
});
|
|
});
|
|
|
|
describe("Distribution monthly view contract", () => {
|
|
it("uses route params for tab selection and month navigation", () => {
|
|
expect(distributionMonthSource).toContain("const TABS = ['overview', 'departments', 'customers', 'compare']");
|
|
expect(distributionMonthSource).toContain("/superuser/invoices/distribution/${year}/${month}/${tab}");
|
|
expect(distributionMonthSource).toContain("() => route.params.tab");
|
|
expect(distributionMonthSource).toContain("watch(activeTab, async (tab) => {");
|
|
});
|
|
|
|
it("hydrates and syncs high-value controls through URL query state", () => {
|
|
expect(distributionMonthSource).toContain("const QUERY_KEYS = [");
|
|
expect(distributionMonthSource).toContain("'compareMonth'");
|
|
expect(distributionMonthSource).toContain("'compareMode'");
|
|
expect(distributionMonthSource).toContain("'compareVisibility'");
|
|
expect(distributionMonthSource).toContain("'customerSearch'");
|
|
expect(distributionMonthSource).toContain("'customerSource'");
|
|
expect(distributionMonthSource).toContain("'customerDepartment'");
|
|
expect(distributionMonthSource).toContain("'departmentSearch'");
|
|
expect(distributionMonthSource).toContain("normalizeDistributionQueryState(route.query)");
|
|
expect(distributionMonthSource).toContain("buildDistributionQueryState({");
|
|
expect(distributionMonthSource).toContain("router.replace({");
|
|
});
|
|
|
|
it("keeps workflow toolbar priority and summary ribbon", () => {
|
|
expect(distributionMonthSource).toContain('class="v3-toolbar-card');
|
|
expect(distributionMonthSource).toContain('class="v3-hero-card');
|
|
expect(distributionMonthSource).toContain("distribution-month-prev");
|
|
expect(distributionMonthSource).toContain("distribution-month-next");
|
|
expect(distributionMonthSource).toContain("distribution-compare-month-picker");
|
|
expect(distributionMonthSource).toContain("distribution-run-compare");
|
|
expect(distributionMonthSource).toContain('class="summary-ribbon');
|
|
});
|
|
|
|
it("renders upgraded tab content for overview/departments/customers/compare", () => {
|
|
expect(distributionMonthSource).toContain('value="overview"');
|
|
expect(distributionMonthSource).toContain('value="departments"');
|
|
expect(distributionMonthSource).toContain('value="customers"');
|
|
expect(distributionMonthSource).toContain('value="compare"');
|
|
expect(distributionMonthSource).toContain('class="v3-overview-grid');
|
|
expect(distributionMonthSource).toContain('class="v3-surface');
|
|
expect(distributionMonthSource).toContain("allocation-chips");
|
|
expect(distributionMonthSource).toContain("sortCompareRows(compareRows.value)");
|
|
expect(distributionMonthSource).toContain("selectedWarningInvoiceId");
|
|
expect(distributionMonthSource).toContain("warning-panel__header");
|
|
expect(distributionMonthSource).toContain('value="customer_prices"');
|
|
expect(distributionMonthSource).toContain("distribution-compare-visibility-picker");
|
|
expect(distributionMonthSource).toContain("monthFallback.usedLegacyDistribution");
|
|
expect(distributionMonthSource).toContain("monthFallback.usedSplitV2Distribution");
|
|
expect(distributionMonthSource).toContain("compareFallback.usedLegacyCompare");
|
|
expect(distributionMonthSource).toContain("compareFallback.usedSingleCompareFallback");
|
|
});
|
|
|
|
it("keeps department footer totals excluding customer prices from the total column", () => {
|
|
expect(distributionMonthSource).toContain("buildDepartmentAllocationFooterTotals");
|
|
expect(distributionMonthSource).toContain('class="department-table__footer"');
|
|
expect(distributionMonthSource).toContain("departmentFooterTotals.totalAmount");
|
|
expect(distributionMonthSource).toContain('has-text-grey">-</td>');
|
|
});
|
|
|
|
it("keeps compare mode values and progress visibility", () => {
|
|
expect(distributionMonthSource).toContain("const compareMode = ref('invoice_total')");
|
|
expect(distributionMonthSource).toContain("DISTRIBUTION_COMPARE_MODES");
|
|
expect(distributionMonthSource).toContain("line_by_line");
|
|
expect(distributionMonthSource).toContain("compareProgress");
|
|
expect(distributionMonthSource).toContain("compareCompletionPercent");
|
|
expect(distributionMonthSource).toContain("onRows:");
|
|
expect(distributionMonthSource).toContain("aggregateCompareRows(streamedRows)");
|
|
});
|
|
});
|
|
|
|
describe("Distribution accessibility contract", () => {
|
|
it("adds aria labels, table captions, and focus-visible styles", () => {
|
|
expect(distributionOverviewSource).toContain("aria-label");
|
|
expect(distributionOverviewSource).toContain("<caption>");
|
|
expect(distributionOverviewSource).toContain("focus-visible");
|
|
expect(distributionMonthSource).toContain("aria-label");
|
|
expect(distributionMonthSource).toContain("<caption>");
|
|
expect(distributionMonthSource).toContain("focus-visible");
|
|
});
|
|
});
|
|
|
|
describe("Distribution API adapter contract", () => {
|
|
it("uses period endpoint and supports v2 all/split distribution with legacy fallback", () => {
|
|
expect(distributionApiSource).toContain("'/superuser/invoicing/period'");
|
|
expect(distributionApiSource).toContain("'/superuser/invoicing/period/distribution/v2/all'");
|
|
expect(distributionApiSource).toContain("'/superuser/invoicing/period/distribution/v2/fixed-pricing'");
|
|
expect(distributionApiSource).toContain("'/superuser/invoicing/period/distribution/v2/wash-subscriptions'");
|
|
expect(distributionApiSource).toContain("'/superuser/invoicing/period/distribution/v2/customer-prices'");
|
|
expect(distributionApiSource).toContain("'/superuser/invoicing/period/distribution/fixed-pricing'");
|
|
expect(distributionApiSource).toContain("'/superuser/invoicing/period/distribution/wash-subscriptions'");
|
|
expect(distributionApiSource).toContain("usedLegacyDistribution");
|
|
expect(distributionApiSource).toContain("usedSplitV2Distribution");
|
|
expect(distributionApiSource).toContain("dateFrom");
|
|
expect(distributionApiSource).toContain("dateTo");
|
|
});
|
|
|
|
it("runs month compare against v2 bulk endpoint with single-v2 and legacy fallback paths", () => {
|
|
expect(distributionApiSource).toContain("compareCollectedInvoicesForMonth");
|
|
expect(distributionApiSource).toContain("'/collected-invoices/economic/v2/compare/bulk'");
|
|
expect(distributionApiSource).toContain("'/collected-invoices/economic/v2/compare'");
|
|
expect(distributionApiSource).toContain("'/collected-invoices/economic/compare'");
|
|
expect(distributionApiSource).toContain("usedLegacyCompare");
|
|
expect(distributionApiSource).toContain("usedSingleCompareFallback");
|
|
expect(distributionApiSource).toContain("normalizeCompareResult");
|
|
expect(distributionApiSource).toContain("aggregateCompareRows");
|
|
});
|
|
});
|
|
|
|
describe("Distribution visual components contract", () => {
|
|
it("uses chart.js line chart with four datasets and aria label support", () => {
|
|
expect(distributionChartSource).toContain("import { Line } from 'vue-chartjs'");
|
|
expect(distributionChartSource).toContain("label: props.labels.total");
|
|
expect(distributionChartSource).toContain("label: props.labels.booked");
|
|
expect(distributionChartSource).toContain("label: props.labels.distribution");
|
|
expect(distributionChartSource).toContain("label: props.labels.customerPrices");
|
|
expect(distributionChartSource).toContain("ariaLabel");
|
|
});
|
|
|
|
it("provides reusable skeleton shimmer component", () => {
|
|
expect(distributionSkeletonSource).toContain("loading-shimmer");
|
|
expect(distributionSkeletonSource).toContain('v-for="index in rows"');
|
|
expect(distributionSkeletonSource).toContain("skeleton-block");
|
|
});
|
|
});
|