1
0
Fork 0
polaris-task-force/tests/int/arma-catalog-import.int.spec.ts
Z8MB1E 64d92bf848 refactor(arma): extract catalog import logic into lib/arma-import
Move the record contract, planning, and upsert logic out of the CLI script
and into src/lib/arma-import/catalog.ts so it can be unit-tested and reused.
The CLI (importArmaLibrary.ts) becomes a thin wrapper. Records are upserted
into assets (keyed by className) and vehicles (by classname); thumbnails are
materialized from .paa inventory icons, and fuel config is resolved per
record type. Adds integration coverage for the catalog import path.
2026-10-01 10:04:38 -04:00

286 lines
9.7 KiB
TypeScript

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");
});
});
});