import { describe, expect, it } from "vitest"; import { MAX_BULK_DOWNLOAD_PROPERTIES, buildBulkDownloadRecord, buildSelectionConfig, bulkDownloadRefetchInterval, parseDelivery, } from "./model"; describe("buildSelectionConfig — UI selection → stored config", () => { const portfolioId = 814; it("one project + include all → project_codes", () => { const r = buildSelectionConfig({ scope: { kind: "project", projectCode: "ABRI-2024-01" }, includeAll: true, landlordPropertyIds: [], portfolioId, }); expect(r).toEqual({ ok: true, config: { project_codes: ["ABRI-2024-01"], portfolio_id: 814 }, }); }); it("one project + ticked subset → landlord_property_ids (scope ignored)", () => { const r = buildSelectionConfig({ scope: { kind: "project", projectCode: "ABRI-2024-01" }, includeAll: false, landlordPropertyIds: ["LP1023", "LP1044"], portfolioId, }); expect(r).toEqual({ ok: true, config: { landlord_property_ids: ["LP1023", "LP1044"], portfolio_id: 814 }, }); }); it("all projects + include all → every project code", () => { const r = buildSelectionConfig({ scope: { kind: "all-projects", projectCodes: ["A-1", "B-2"] }, includeAll: true, landlordPropertyIds: [], portfolioId, }); expect(r).toEqual({ ok: true, config: { project_codes: ["A-1", "B-2"], portfolio_id: 814 }, }); }); it("all projects + ticked subset → landlord_property_ids", () => { const r = buildSelectionConfig({ scope: { kind: "all-projects", projectCodes: ["A-1", "B-2"] }, includeAll: false, landlordPropertyIds: ["LP1"], portfolioId, }); expect(r).toEqual({ ok: true, config: { landlord_property_ids: ["LP1"], portfolio_id: 814 }, }); }); it("de-duplicates ids and codes", () => { expect( buildSelectionConfig({ scope: { kind: "all-projects", projectCodes: ["A-1", "A-1"] }, includeAll: true, landlordPropertyIds: [], portfolioId, }), ).toEqual({ ok: true, config: { project_codes: ["A-1"], portfolio_id: 814 } }); expect( buildSelectionConfig({ scope: { kind: "project", projectCode: "A-1" }, includeAll: false, landlordPropertyIds: ["LP1", "LP1", " LP1 "], portfolioId, }), ).toEqual({ ok: true, config: { landlord_property_ids: ["LP1"], portfolio_id: 814 }, }); }); it("rejects an empty subset", () => { const r = buildSelectionConfig({ scope: { kind: "project", projectCode: "A-1" }, includeAll: false, landlordPropertyIds: [], portfolioId, }); expect(r.ok).toBe(false); }); it("rejects include-all with no usable codes", () => { const r = buildSelectionConfig({ scope: { kind: "all-projects", projectCodes: ["", " "] }, includeAll: true, landlordPropertyIds: [], portfolioId, }); expect(r.ok).toBe(false); }); it("rejects a subset over the 500 cap with the detail message", () => { const ids = Array.from({ length: 501 }, (_, i) => `LP${i}`); const r = buildSelectionConfig({ scope: { kind: "project", projectCode: "A-1" }, includeAll: false, landlordPropertyIds: ids, portfolioId, }); expect(r.ok).toBe(false); if (!r.ok) { expect(r.error).toContain(`over the ${MAX_BULK_DOWNLOAD_PROPERTIES} limit`); expect(r.error).toContain("501 properties"); } }); }); describe("buildBulkDownloadRecord", () => { it("writes the app-owned task marker and the config as JSON inputs", () => { const record = buildBulkDownloadRecord({ portfolioId: "814", config: { project_codes: ["A-1"], portfolio_id: 814 }, }); expect(record.taskSource).toBe("app:bulk_document_download"); expect(record.source).toBe("portfolio_id"); expect(record.sourceId).toBe("814"); expect(record.status).toBe("waiting"); expect(JSON.parse(record.inputs)).toEqual({ project_codes: ["A-1"], portfolio_id: 814, }); }); }); describe("parseDelivery", () => { it("reads a finished delivery", () => { const d = parseDelivery( JSON.stringify({ presigned_url: "https://x", package_s3_key: "k", included: 137, skipped: [{ landlord_property_id: "LP9", s3_key: "k", reason: "unreadable" }], }), ); expect(d).toEqual({ presignedUrl: "https://x", packageS3Key: "k", included: 137, skipped: [{ landlord_property_id: "LP9", s3_key: "k", reason: "unreadable" }], }); }); it("tolerates link-key naming variants", () => { expect(parseDelivery(JSON.stringify({ presignedUrl: "https://a" }))?.presignedUrl).toBe( "https://a", ); expect(parseDelivery(JSON.stringify({ download_url: "https://b" }))?.presignedUrl).toBe( "https://b", ); expect(parseDelivery(JSON.stringify({ url: "https://c", s3_key: "k" }))).toMatchObject({ presignedUrl: "https://c", packageS3Key: "k", }); }); it("returns null for in-flight or malformed outputs", () => { expect(parseDelivery(null)).toBeNull(); expect(parseDelivery("")).toBeNull(); expect(parseDelivery("{not json")).toBeNull(); expect(parseDelivery(JSON.stringify({ included: 0 }))).toBeNull(); }); }); describe("bulkDownloadRefetchInterval", () => { it("polls while preparing, stops once resolved", () => { expect(bulkDownloadRefetchInterval(undefined)).toBe(8_000); expect(bulkDownloadRefetchInterval({ state: "preparing", delivery: null })).toBe(8_000); expect( bulkDownloadRefetchInterval({ state: "ready", delivery: { presignedUrl: "x", packageS3Key: null, included: 1, skipped: [] }, }), ).toBe(false); expect(bulkDownloadRefetchInterval({ state: "failed", delivery: null })).toBe(false); }); });