import { getPayload, Payload } from "payload"; import config from "@/payload.config"; import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { ASSET_TYPES, planRecord, upsertPlan, type CatalogRecord, } from "@/lib/arma-import/catalog"; let payload: Payload; const RUN = `armacat-${Date.now().toString(36)}`; let fuelId: number; let createdFuel = false; const assetIds: number[] = []; const vehicleIds: number[] = []; describe("Arma catalog import", () => { beforeAll(async () => { const payloadConfig = await config; payload = await getPayload({ config: payloadConfig }); // Vehicles need a fuel resource for the fuel group; reuse one if a prior // fixture left it, otherwise create it (and only then clean it up). const existingFuel = await payload.find({ collection: "resources", where: { name: { equals: "Fuel" } }, limit: 1, depth: 0, overrideAccess: true, }); if (existingFuel.docs[0]) { fuelId = existingFuel.docs[0].id; } else { const fuel = await payload.create({ collection: "resources", data: { name: "Fuel", codeName: `res_fuel_${RUN}`, unitOfMeasure: "liter", approvalStatus: "in_progress", type: "fluid", baseValue: 1, rarity: "common", massPerUnit: 0, gridWidth: 1, gridHeight: 1, tradeable: false, }, depth: 0, overrideAccess: true, }); fuelId = fuel.id; createdFuel = true; } }); afterAll(async () => { for (const id of vehicleIds) { await payload.delete({ collection: "vehicles", id, overrideAccess: true }).catch(() => {}); } for (const id of assetIds) { await payload.delete({ collection: "assets", id, overrideAccess: true }).catch(() => {}); } if (createdFuel && fuelId) { await payload.delete({ collection: "resources", id: fuelId, overrideAccess: true }).catch(() => {}); } }); describe("planRecord classification", () => { it("trusts type for every contract asset type", () => { for (const t of ASSET_TYPES) { const rec: CatalogRecord = { classname: `PTF_Test_Thing_${t}`, type: t, displayName: "Thing", picture: "", mod: "CBA_3den", description: "", mass: 1, extra: "", }; const plan = planRecord(rec); expect(plan).toBeDefined(); expect(plan!.kind).toBe("asset"); expect(plan!.assetType).toBe(t); } }); it("routes vehicle records to the vehicles collection with transportMode from extra", () => { const air = planRecord({ classname: "B_Heli_Light_01_F", type: "vehicle", displayName: "Ghost Hawk", picture: "", mod: "Arma 3", description: "", mass: 3000, extra: "air", }); expect(air!.kind).toBe("vehicle"); expect(air!.transportMode).toBe("air"); const sea = planRecord({ classname: "C_Boat_Civil_01_F", type: "vehicle", extra: "sea" }); expect(sea!.transportMode).toBe("sea"); }); it("defaults transportMode to ground when extra is not a valid mode", () => { const plan = planRecord({ classname: "B_MRAP_01_F", type: "vehicle", extra: "submarine" }); expect(plan!.kind).toBe("vehicle"); expect(plan!.transportMode).toBe("ground"); }); it("falls back to heuristics for unknown types (miscellaneous, not item)", () => { const plan = planRecord({ classname: "PTF_Test_Odd_Gadget", type: "qrd_mysterious_device" }); expect(plan!.kind).toBe("asset"); expect(plan!.assetType).toBe("miscellaneous"); }); it("falls back to the legacy vehicle heuristic for unknown types", () => { const plan = planRecord({ classname: "B_Truck_01_transport_F", type: "who_knows" }); expect(plan!.kind).toBe("vehicle"); expect(plan!.transportMode).toBe("ground"); }); it("captures magazine round counts from extra", () => { const plan = planRecord({ classname: "30rnd_556x45_Mag", type: "magazine", extra: 30 }); expect(plan!.kind).toBe("asset"); expect(plan!.roundCapacity).toBe(30); expect(plan!.assetType).toBe("magazine"); }); it("ignores numeric extra for non-magazine assets", () => { const plan = planRecord({ classname: "PTF_Test_Rifle", type: "weapon", extra: 30 }); expect(plan!.assetType).toBe("weapon"); expect(plan!.roundCapacity).toBeUndefined(); }); it("supports legacy class/category/name aliases and icon-map overrides", () => { const plan = planRecord( { class: "Legacy_Thing", category: "optic", name: "Legacy Optic" }, { icons: { legacy_thing: "\\a3\\data\\ui\\icon.paa" } }, ); expect(plan!.className).toBe("Legacy_Thing"); expect(plan!.assetType).toBe("optic"); expect(plan!.displayName).toBe("Legacy Optic"); expect(plan!.pictureRef).toBe("\\a3\\data\\ui\\icon.paa"); }); it("defaults mod to Arma 3 and rejects records without a classname", () => { const plan = planRecord({ classname: "PTF_Test_Thing", type: "weapon" }); expect(plan).toBeDefined(); expect(plan!.mod).toBe("Arma 3"); expect(planRecord({ type: "weapon" })).toBeUndefined(); }); }); describe("upsertPlan assets", () => { const assetClassName = `${RUN}_asset_rifle`; it("creates an asset with correct className/assetType and Asset Metadata.mod", async () => { const plan = planRecord({ classname: assetClassName, type: "weapon", displayName: `${RUN} Rifle`, picture: "", mod: "PTF_Test_Mod", description: "An import test rifle.", mass: 2, extra: "", })!; const res = await upsertPlan(payload, plan); expect(res.action).toBe("created"); expect(res.collection).toBe("assets"); assetIds.push(res.id); const doc = await payload.findByID({ collection: "assets", id: res.id, depth: 0, overrideAccess: true }); expect(doc.className).toBe(assetClassName); expect(doc.assetType).toBe("weapon"); expect(doc.name).toBe(`${RUN} Rifle`); expect(doc["Asset Metadata"]?.mod).toBe("PTF_Test_Mod"); expect(doc["Asset Metadata"]?.gameDescription).toBe("An import test rifle."); expect(doc.approvalStatus).toBe("in_progress"); }); it("updates on re-run without duplicating and preserves approvalStatus and Virtual Data", async () => { const assetId = assetIds[0]; // Simulate human edits before the second import run. await payload.update({ collection: "assets", id: assetId, data: { approvalStatus: "approved", tradeable: true }, overrideAccess: true, }); const res = await upsertPlan( payload, planRecord({ classname: assetClassName, type: "weapon", displayName: `${RUN} Rifle MkII`, picture: "", mod: "PTF_Test_Mod_2", description: "Updated in-game description.", mass: 2, extra: "", })!, undefined, // assets never need fuel ); expect(res.action).toBe("updated"); expect(res.collection).toBe("assets"); expect(res.id).toBe(assetId); const count = await payload.count({ collection: "assets", where: { className: { equals: assetClassName } }, }); expect(count.totalDocs).toBe(1); const doc = await payload.findByID({ collection: "assets", id: assetId, depth: 0, overrideAccess: true }); expect(doc.name).toBe(`${RUN} Rifle MkII`); expect(doc["Asset Metadata"]?.mod).toBe("PTF_Test_Mod_2"); expect(doc["Asset Metadata"]?.gameDescription).toBe("Updated in-game description."); expect(doc.approvalStatus).toBe("approved"); // never reset by re-import expect(doc.tradeable).toBe(true); // Virtual Data untouched }); }); describe("upsertPlan vehicles", () => { const vehicleClassname = `${RUN}_heli_ghost`; it("creates a vehicle with classname and transportMode air", async () => { const plan = planRecord({ classname: vehicleClassname, type: "vehicle", displayName: `${RUN} Ghost Hawk`, picture: "", mod: "PTF_Test_Mod", description: "An import test helicopter.", mass: 3000, extra: "air", })!; const res = await upsertPlan(payload, plan, fuelId); expect(res.action).toBe("created"); expect(res.collection).toBe("vehicles"); vehicleIds.push(res.id); const doc = await payload.findByID({ collection: "vehicles", id: res.id, depth: 0, overrideAccess: true }); expect(doc.classname).toBe(vehicleClassname); expect(doc.name).toBe(`${RUN} Ghost Hawk`); expect(doc.transportMode).toBe("air"); expect(doc.fuel.fuelType).toBe(fuelId); expect(doc.fuel.fuelCapacity).toBe(100); expect(doc.approvalStatus).toBe("in_progress"); }); it("updates an existing vehicle without duplicating", async () => { const vehicleId = vehicleIds[0]; const res = await upsertPlan( payload, planRecord({ classname: vehicleClassname, type: "vehicle", displayName: `${RUN} Ghost Hawk II`, extra: "air", })!, fuelId, ); expect(res.action).toBe("updated"); expect(res.id).toBe(vehicleId); const count = await payload.count({ collection: "vehicles", where: { classname: { equals: vehicleClassname } }, }); expect(count.totalDocs).toBe(1); const doc = await payload.findByID({ collection: "vehicles", id: vehicleId, depth: 0, overrideAccess: true }); expect(doc.name).toBe(`${RUN} Ghost Hawk II`); expect(doc.transportMode).toBe("air"); }); }); });