import { describe, it, expect, beforeEach, afterEach } from "vitest"; import fs from "fs"; import os from "os"; import path from "path"; import { NasFileManager } from "../services/nas-file-manager"; /** * Folder auto-creation primitive used by both the manual project-create path * (projects.service createProject) and the order→project paths (orders.service * createOrder / createOrderFromQuotation). Uses an isolated temp dir via the * constructor seam so it is deterministic and passes even where the real NAS * (Z:) is not mounted. */ describe("NasFileManager.createProjectFolder", () => { let tmpBase: string; let nas: NasFileManager; beforeEach(() => { tmpBase = fs.mkdtempSync(path.join(os.tmpdir(), "nas-proj-")); nas = new NasFileManager(tmpBase); }); afterEach(() => { fs.rmSync(tmpBase, { recursive: true, force: true }); }); it("creates a _ folder for a new project", () => { const ok = nas.createProjectFolder("26710001", "Rekonstrukce haly"); expect(ok).toBe(true); expect( fs.existsSync(path.join(tmpBase, "26710001_Rekonstrukce_haly")), ).toBe(true); }); it("is idempotent — a second call does not create a duplicate", () => { expect(nas.createProjectFolder("26710002", "Hala")).toBe(true); expect(nas.createProjectFolder("26710002", "Hala")).toBe(true); const matches = fs .readdirSync(tmpBase) .filter((e) => e.startsWith("26710002_")); expect(matches).toEqual(["26710002_Hala"]); }); it("preserves Czech diacritics (no transliteration)", () => { expect(nas.createProjectFolder("26710003", "Měření haly")).toBe(true); expect(fs.existsSync(path.join(tmpBase, "26710003_Měření_haly"))).toBe( true, ); }); it("strips illegal characters and collapses spaces", () => { expect(nas.createProjectFolder("26710004", "A / B: C")).toBe(true); expect(fs.existsSync(path.join(tmpBase, "26710004_A_B_C"))).toBe(true); }); it("handles an empty name without crashing (trailing underscore)", () => { expect(nas.createProjectFolder("26710005", "")).toBe(true); expect(fs.existsSync(path.join(tmpBase, "26710005_"))).toBe(true); }); it("returns false and creates nothing when the NAS base is not mounted", () => { const missing = new NasFileManager( path.join(tmpBase, "does-not-exist-subdir"), ); expect(missing.createProjectFolder("26710006", "X")).toBe(false); expect(fs.existsSync(path.join(tmpBase, "does-not-exist-subdir"))).toBe( false, ); }); }); /** * Folder deletion primitive used by the "delete folder" checkbox on both the * order delete (orders.service deleteOrder) and project delete (projects.service * deleteProject) paths. Matches the project by number prefix. */ describe("NasFileManager.deleteProjectFolder", () => { let tmpBase: string; let nas: NasFileManager; beforeEach(() => { tmpBase = fs.mkdtempSync(path.join(os.tmpdir(), "nas-del-")); nas = new NasFileManager(tmpBase); }); afterEach(() => { fs.rmSync(tmpBase, { recursive: true, force: true }); }); it("removes an existing project folder (matched by number prefix)", async () => { nas.createProjectFolder("26710010", "Hala"); expect(fs.existsSync(path.join(tmpBase, "26710010_Hala"))).toBe(true); const ok = await nas.deleteProjectFolder("26710010"); expect(ok).toBe(true); expect(fs.existsSync(path.join(tmpBase, "26710010_Hala"))).toBe(false); }); it("is a no-op (returns true) when no folder exists for the number", async () => { expect(await nas.deleteProjectFolder("26710011")).toBe(true); }); it("returns false when the NAS base is not mounted", async () => { const missing = new NasFileManager(path.join(tmpBase, "nope")); expect(await missing.deleteProjectFolder("26710012")).toBe(false); }); });