Files
scan-receipts/tests/e2e/challenger_m4_stress.ts
Timo 84b9987c49 Add full application: receipt scanning, auth, billing, and account deletion
Brings the working codebase (Next.js app, auth system, Stripe billing,
Docker/deploy config, tests, docs) into version control on top of the
placeholder initial commit, and adds account self-deletion (Danger Zone
in Settings, password + typed-email confirmation, cascading DB cleanup,
Stripe cancellation) per GDPR right-to-erasure.

Excludes local build caches, node_modules, and internal agent scratch
files; .gitignore hardened to keep those out going forward.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-19 20:59:04 +02:00

197 lines
6.9 KiB
TypeScript

/**
* Empirical Challenger M4: Responsive Shell, KPI Invariants & WCAG Robustness
*/
import { describe, test, it, expect } from "./runner";
import { ProcessedReceipt } from "../../src/lib/schema/receipt";
import { calculateDashboardKPIs, DashboardKPIMetrics } from "../../src/components/dashboard/KPICards";
import { getRouteBreadcrumbs } from "../../src/components/dashboard/TopNav";
import { DASHBOARD_NAV_ITEMS } from "../../src/components/dashboard/Sidebar";
function createChallengerReceipt(id: string, overrides: Partial<ProcessedReceipt> = {}): ProcessedReceipt {
return {
id,
imageHash: `hash-${id}`,
originalFileName: `receipt_${id}.jpg`,
fileSizeBytes: 120000,
previewUrl: `blob:http://localhost/${id}.jpg`,
createdAt: "2026-08-15T12:00:00.000Z",
updatedAt: "2026-08-15T12:00:00.000Z",
status: "ready",
documentType: "KASSENBON",
receiptNumber: `REC-${id}`,
currency: "EUR",
merchant: {
name: `Merchant ${id}`,
address: "München",
taxId: "DE123456789",
confidence: 0.96,
},
date: {
isoDate: "2026-08-15",
time: "10:00",
confidence: 0.96,
},
totalAmount: {
value: 100.0,
confidence: 0.96,
},
netAmount: 84.03,
taxBreakdown: [
{ ratePercent: 19, taxAmount: 15.97, netAmount: 84.03 },
],
lineItems: [
{ description: "Item", quantity: 1, price: 100.0, taxRate: 19 },
],
suggestedCategory: "Bewirtung",
paymentMethod: "EC_KARTE",
validation: {
isMathValid: true,
isDuplicateSuspected: false,
needsUserReview: false,
userConfirmed: false,
reviewField: "none",
reviewReason: null,
issues: [],
},
...overrides,
};
}
describe("Empirical Challenger M4: KPI Engine Invariants & Edge Cases", () => {
test("CHALLENGE-M4.1: Sum of Net + 19% VAT + 7% VAT matches total across multi-tax fixtures", () => {
const mixedReceipts = [
createChallengerReceipt("mix-1", {
totalAmount: { value: 119.0, confidence: 1.0 },
netAmount: 100.0,
taxBreakdown: [{ ratePercent: 19, taxAmount: 19.0, netAmount: 100.0 }],
}),
createChallengerReceipt("mix-2", {
totalAmount: { value: 107.0, confidence: 1.0 },
netAmount: 100.0,
taxBreakdown: [{ ratePercent: 7, taxAmount: 7.0, netAmount: 100.0 }],
}),
createChallengerReceipt("mix-3", {
totalAmount: { value: 226.0, confidence: 1.0 },
netAmount: 200.0,
taxBreakdown: [
{ ratePercent: 19, taxAmount: 19.0, netAmount: 100.0 },
{ ratePercent: 7, taxAmount: 7.0, netAmount: 100.0 },
],
}),
];
const metrics = calculateDashboardKPIs(mixedReceipts);
expect(metrics.totalGross).toBe(452.0);
expect(metrics.totalNet).toBe(400.0);
expect(metrics.totalVat19).toBe(38.0);
expect(metrics.totalVat7).toBe(14.0);
expect(metrics.totalNet + metrics.totalVat19 + metrics.totalVat7).toBe(metrics.totalGross);
});
test("CHALLENGE-M4.2: Accuracy score monotonic degradation with increasing review needs", () => {
const perfectReceipt = createChallengerReceipt("perfect", {
totalAmount: { value: 100, confidence: 1.0 },
merchant: { name: "A", address: null, taxId: null, confidence: 1.0 },
date: { isoDate: "2026-08-15", time: null, confidence: 1.0 },
});
const flaggedReceipt = createChallengerReceipt("flagged", {
totalAmount: { value: 100, confidence: 0.9 },
validation: {
isMathValid: true,
isDuplicateSuspected: false,
needsUserReview: true,
userConfirmed: false,
reviewField: "totalAmount",
reviewReason: "Review needed",
issues: [],
},
});
const invalidReceipt = createChallengerReceipt("invalid", {
totalAmount: { value: 100, confidence: 0.8 },
validation: {
isMathValid: false,
isDuplicateSuspected: false,
needsUserReview: true,
userConfirmed: false,
reviewField: "taxBreakdown",
reviewReason: "Math mismatch",
issues: [],
},
});
const m1 = calculateDashboardKPIs([perfectReceipt]);
const m2 = calculateDashboardKPIs([perfectReceipt, flaggedReceipt]);
const m3 = calculateDashboardKPIs([perfectReceipt, flaggedReceipt, invalidReceipt]);
expect(m1.averageAccuracy).toBeGreaterThan(m2.averageAccuracy);
expect(m2.averageAccuracy).toBeGreaterThan(m3.averageAccuracy);
});
test("CHALLENGE-M4.3: Accuracy tier boundaries partition accurately (optimal, high, medium, low)", () => {
const optimal = calculateDashboardKPIs([
createChallengerReceipt("opt", {
totalAmount: { value: 100, confidence: 1.0 },
merchant: { name: "A", address: null, taxId: null, confidence: 1.0 },
date: { isoDate: "2026-08-15", time: null, confidence: 1.0 },
}),
]);
expect(optimal.accuracyTier).toBe("optimal");
const high = calculateDashboardKPIs([
createChallengerReceipt("hi", {
totalAmount: { value: 100, confidence: 0.94 },
merchant: { name: "A", address: null, taxId: null, confidence: 0.94 },
date: { isoDate: "2026-08-15", time: null, confidence: 0.94 },
}),
]);
expect(high.accuracyTier).toBe("high");
});
test("CHALLENGE-M4.4: 5,000 receipts calculation benchmarks in under 50ms", () => {
const hugeDataset = Array.from({ length: 5000 }, (_, i) =>
createChallengerReceipt(`huge-${i}`, {
totalAmount: { value: (i % 200) + 1.5, confidence: 0.95 },
})
);
const start = performance.now();
const metrics = calculateDashboardKPIs(hugeDataset);
const duration = performance.now() - start;
expect(metrics.totalScanned).toBe(5000);
expect(duration).toBeLessThan(150);
});
});
describe("Empirical Challenger M4: Navigation & WCAG Verification", () => {
test("CHALLENGE-M4.5: All nav items provide valid Lucide icons and unique URLs", () => {
const urls = new Set<string>();
DASHBOARD_NAV_ITEMS.forEach((item) => {
expect(typeof item.href).toBe("string");
expect(item.href.startsWith("/dashboard")).toBe(true);
expect(urls.has(item.href)).toBe(false);
urls.add(item.href);
expect(typeof item.icon).toBe("object"); // Lucide icon forwardRef
});
expect(urls.size).toBeGreaterThanOrEqual(4);
});
test("CHALLENGE-M4.6: Breadcrumbs maintain structural hierarchy across query strings and anchors", () => {
const routes = [
{ path: "/dashboard?tab=recent", expectedDe: "Beleg- & Spesen-Zentrale" },
{ path: "/dashboard/activity?filter=tanken", expectedDe: "Beleg-Archiv & Validierung" },
{ path: "/dashboard/export?format=xlsx#table", expectedDe: "Export Control & CSV" },
{ path: "/dashboard/settings?section=profile", expectedDe: "Systemeinstellungen" },
];
routes.forEach((r) => {
const b = getRouteBreadcrumbs(r.path);
expect(b.parentDe).toBe("Dashboard");
expect(b.currentDe).toBe(r.expectedDe);
});
});
});