import assert from "node:assert/strict"; import { readFileSync } from "node:fs"; import vm from "node:vm"; const read = (path) => readFileSync(new URL(path, import.meta.url), "utf8"); const page = read("../src/features/files/FilesPage.tsx"); const menu = read("../src/features/files/components/FileManagerComponents.tsx"); const api = read("../src/api/files.ts"); const translations = read("../src/i18n/generatedTranslations.ts"); assert.match(page, /selectedFiles\.length === 1 && selectedFolderPaths\.size === 0 && ARCHIVE_FILENAME_PATTERN/); assert.match(page, /function openManagedArchive[\s\S]*?!canUpload \|\| !canDownload[\s\S]*?setManagedArchiveFile\(file\)/); assert.match(page, /disabledReason=\{unpackBlocker\}/); assert.match(menu, /onClick=\{onUnpackArchive\} disabled=\{!canUnpackArchive\}/); assert.match(page, /file: File \| ManagedFile/); assert.match(page, /previewManagedArchive\(settings, file\.id,[\s\S]*?source_version_id: file\.version_id/); assert.match(page, /confirmManagedArchive\(settings, managedArchiveFile\.id,[\s\S]*?source_version_id: managedArchiveFile\.version_id/); assert.match(page, /archivePreview && \(archiveFile \|\| managedArchiveFile\)/); assert.match(page, /loadArchivePreview\(\(managedArchiveFile \|\| archiveFile\)!/); assert.match(page, /if \(managedArchiveFile\) \{ setArchivePreview\(null\); setSelectedArchivePaths/); assert.match(page, /onClose=\{\(\) => \{ if \(!busy\) closeDialog\(\); \}\}/); assert.match(page, //); assert.match(page, /onArchiveProgress: \(progress: ArchiveOperationProgress\)/); assert.match(page, /archiveProgress\?\.status === "complete" \? 100/); assert.match(page, /archiveProgress.phase !== "finalizing"[\s\S]*?serverProgressRatio < 1/); assert.match(menu, /closeDisabled=\{busy\}[\s\S]*?closeOnBackdrop=\{!busy\}/); const feedback = page.slice(page.indexOf(" const selectedArchiveBytes ="), page.indexOf(" const connectorLocationLabel =")); function operationFeedback(archiveProgress, uploadPhase = "unpacking", uploadProgress = null) { const context = { archiveProgress, uploadPhase, uploadProgress, selectedArchivePaths: new Set(["one.txt", "empty.txt"]), archivePreview: { entries: [{ path: "one.txt", kind: "file", size_bytes: 3 }, { path: "empty.txt", kind: "file", size_bytes: 0 }] }, formatBytes: (value) => `${value} B`, i18nMessage: (key, values) => ({ key, values }) }; vm.runInNewContext(`${feedback}\nglobalThis.result = { value: operationProgressValue, label: operationProgressLabel, phase: operationBusyLabel };`, context); return context.result; } const measured = { phase: "extracting", status: "running", completed_files: 1, total_files: 2, completed_bytes: 3, total_bytes: 6 }; assert.equal(operationFeedback(measured).value, 50); assert.equal(operationFeedback({ ...measured, phase: "finalizing", completed_files: 2, completed_bytes: 6 }).value, null, "finalization does not fabricate completion"); assert.equal(operationFeedback({ ...measured, completed_files: 2, completed_bytes: 6 }).value, null, "processed bytes alone do not mean commit success"); assert.equal(operationFeedback({ ...measured, phase: "complete", status: "complete" }).value, 100); assert.equal(operationFeedback({ ...measured, total_bytes: 0, completed_bytes: 0 }).value, 50, "empty members use actual file counts"); assert.equal(operationFeedback(null).value, null, "no measured result remains indeterminate"); assert.equal(operationFeedback(null).label.values.total, 2, "selected totals remain available before polling responds"); assert.equal(operationFeedback(null).label.values.bytes, "3 B"); assert.equal(operationFeedback(null, "uploading", 24).value, 24); assert.equal(operationFeedback(null, "uploading", 100).value, null, "completed transfer is not completed extraction"); assert.equal(page.split('event.dataTransfer.effectAllowed = "copyMove";').length - 1, 2); assert.doesNotMatch(page, /effectAllowed = "i18n:/, "browser drag/drop enums must not be translated"); for (const name of ["previewManagedArchive", "confirmManagedArchive"]) { const body = api.slice(api.indexOf(`export function ${name}`)).split("\n}\n", 1)[0]; assert.match(body, /encodeURIComponent\(fileId\)/); assert.match(body, /body: JSON\.stringify\(/); assert.doesNotMatch(body, /FormData|downloadFile|Blob|createObjectURL/); } assert.match(page, /function resetArchiveUploadState\(\) \{\s*void releaseArchivePreview\(settings, archiveFile\)/, "reset/cancel releases any temporary archive before forgetting it"); assert.match(page, /archiveFile && archiveFile !== file\) void releaseArchivePreview/, "replacing a selected archive releases its previous temporary upload"); for (const key of ["unpack", "preview", "select_one", "source", "expires", "extracting", "change_destination"]) { assert.equal(translations.split(`"i18n:govoplan-files.managed_archive.${key}":`).length - 1, 2, `${key} must have EN and DE text`); } console.log("Managed archive actions reuse the preview dialog and send source-bound JSON without browser re-upload.");