Files
nexarch/web/dms-upload/components/CameraCaptureManager.test.tsx
rootandClaude Sonnet 5 0097c8cf2b
CI / Web-Barrierefreiheitspruefung (axe, Tastatur, Reflow, Textabstaende) (pull_request) Canceled after 0s
CI / Web-Barrierefreiheitspruefung (axe, Tastatur, Reflow, Textabstaende) (push) Canceled after 0s
CI / Core-Modul (Build/Vet/Test) (push) Canceled after 0s
CI / DMS Security-Test-Gate (AC5, Merge-Gate) (push) Canceled after 0s
CI / DMS-Modul Supply-Chain-Scan (govulncheck) (push) Canceled after 0s
CI / Web (dms-browser) (push) Canceled after 0s
CI / Web (pdf-viewer) (push) Canceled after 0s
CI / Web (shl) (push) Canceled after 0s
Supply-Chain-Scan (Go) / govulncheck (push) Canceled after 0s
CI / Core-Modul (Build/Vet/Test) (pull_request) Canceled after 0s
CI / DMS Security-Test-Gate (AC5, Merge-Gate) (pull_request) Canceled after 0s
Supply-Chain-Scan (Go) / govulncheck (pull_request) Canceled after 0s
CI / DMS-Modul Supply-Chain-Scan (govulncheck) (pull_request) Canceled after 0s
CI / Web (dms-browser) (pull_request) Canceled after 0s
CI / Web (pdf-viewer) (pull_request) Canceled after 0s
CI / Web (shl) (pull_request) Canceled after 0s
Core-Schnittstellen-Vertragstests / contract-tests (pull_request) Canceled after 0s
Supply-Chain-Scan (npm) / npm-audit (pull_request) Canceled after 0s
Core-Pflichttest-Gate / pflichttest-gate (pull_request) Canceled after 0s
RBAC-Rollenhierarchie-Pflichtgate / rbac-policy-invariant (pull_request) Canceled after 0s
CI / DMS-Modul (Lint/Build/Test/Coverage/Artefakt) (push) Canceled after 0s
CI / DMS-Modul (Lint/Build/Test/Coverage/Artefakt) (pull_request) Canceled after 0s
INT-19: mobile erfassung mobilfreundliche weboberflaeche
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-26 12:06:19 +00:00

91 lines
3.5 KiB
TypeScript

import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { render, screen, waitFor } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { I18nProvider, ToastProvider } from "@nexarch/shl";
import { CameraCaptureManager } from "./CameraCaptureManager";
import type { CapturedPage } from "../lib/mobileCapture";
const ORIGINAL_ENV = process.env;
let capturedOnSubmit: ((pages: CapturedPage[]) => void) | undefined;
vi.mock("./CameraCapture", () => ({
CameraCapture: ({ onSubmit }: { onSubmit: (pages: CapturedPage[]) => void }) => {
capturedOnSubmit = onSubmit;
return null;
},
}));
function renderManager() {
return render(
<I18nProvider initialLocale="de">
<ToastProvider>
<CameraCaptureManager />
</ToastProvider>
</I18nProvider>,
);
}
function page(id: string): CapturedPage {
return { id, blob: new Blob([new Uint8Array(10)], { type: "image/jpeg" }), previewUrl: `blob:${id}` };
}
beforeEach(() => {
process.env = { ...ORIGINAL_ENV, NEXT_PUBLIC_UPLOAD_API_URL: "http://backend.test" };
});
afterEach(() => {
process.env = ORIGINAL_ENV;
vi.restoreAllMocks();
});
describe("CameraCaptureManager", () => {
// Akzeptanzkriterium 2: die Aufnahme laeuft ueber die bestehende DOC-01-Upload-API.
it("reicht jede gesammelte Seite ueber die bestehende Upload-API ein", async () => {
global.fetch = vi.fn(async (input: RequestInfo | URL) => {
const url = String(input);
if (url.endsWith("/uploads")) return new Response(JSON.stringify({ sessionId: `sess-${Math.random()}` }), { status: 201 });
if (url.includes("/chunk?offset=")) return new Response(JSON.stringify({ bytesReceived: 10 }), { status: 200 });
if (url.endsWith("/complete")) return new Response(JSON.stringify({ documentId: "doc-1", revisionId: "rev-1" }), { status: 200 });
throw new Error(`unerwarteter Aufruf: ${url}`);
}) as unknown as typeof fetch;
renderManager();
await waitFor(() => expect(capturedOnSubmit).toBeDefined());
capturedOnSubmit!([page("seite-1"), page("seite-2")]);
await waitFor(() => {
expect(screen.getAllByText(/Abgeschlossen/)).toHaveLength(2);
});
});
it("erlaubt Retry fuer eine fehlgeschlagene Seite", async () => {
let chunkCalls = 0;
global.fetch = vi.fn(async (input: RequestInfo | URL) => {
const url = String(input);
if (url.endsWith("/uploads")) return new Response(JSON.stringify({ sessionId: "sess-retry" }), { status: 201 });
if (url.includes("/chunk?offset=")) {
chunkCalls += 1;
if (chunkCalls === 1) return new Response("upload: fehler", { status: 500 });
return new Response(JSON.stringify({ bytesReceived: 10 }), { status: 200 });
}
if (url.endsWith("/uploads/sess-retry")) {
return new Response(
JSON.stringify({ sessionId: "sess-retry", filename: "kassenbeleg-1.jpg", totalSize: 10, bytesReceived: 0, status: "uploading" }),
{ status: 200 },
);
}
if (url.endsWith("/complete")) return new Response(JSON.stringify({ documentId: "doc-1", revisionId: "rev-1" }), { status: 200 });
throw new Error(`unerwarteter Aufruf: ${url}`);
}) as unknown as typeof fetch;
renderManager();
await waitFor(() => expect(capturedOnSubmit).toBeDefined());
capturedOnSubmit!([page("seite-1")]);
const retryButton = await screen.findByRole("button", { name: "Erneut versuchen" });
await userEvent.click(retryButton);
await waitFor(() => expect(screen.getByText(/Abgeschlossen/)).toBeInTheDocument());
});
});