Files
org_web/tests/resource-loader.test.js
gitea-actions b8bb1944dd
All checks were successful
Build Org Website / build (push) Successful in 38s
Add Resource Loader SPA and JS test harness
2026-08-19 15:03:41 +01:00

72 lines
3.4 KiB
JavaScript

const test = require("node:test");
const assert = require("node:assert/strict");
const Model = require("../assets/scripts/pages/resource-loader-model.js");
function resource(overrides = {}) {
return {
id: "resource-1", title: "A useful book", creators: ["Reader One"],
type: "book", format: "physical", status: "active", folderId: null,
tags: [], sessions: [], createdAt: "2026-01-01T00:00:00.000Z",
updatedAt: "2026-01-01T00:00:00.000Z", ...overrides,
};
}
function library(resources = []) {
return {
schemaVersion: 1,
vaults: [{
id: "vault-1", name: "Test vault", colour: "#123456",
folders: [{ id: "folder-1", name: "Research" }], resources,
createdAt: "2026-01-01T00:00:00.000Z", updatedAt: "2026-01-01T00:00:00.000Z",
}],
};
}
test("seed contains the two initial empty vaults", () => {
const seed = Model.createSeed();
assert.equal(Model.validateLibrary(seed), true);
assert.deepEqual(seed.vaults.map((vault) => vault.name), ["Work", "Personal Study"]);
assert.ok(seed.vaults.every((vault) => vault.resources.length === 0));
});
test("schema validation rejects unsupported and dangling records", () => {
assert.throws(() => Model.validateLibrary({ schemaVersion: 2, vaults: [] }), /schemaVersion/);
assert.throws(() => Model.validateLibrary(library([resource({ folderId: "missing" })])), /missing folder/);
});
test("merge replaces matching ids and keeps unrelated records", () => {
const current = library([resource(), resource({ id: "resource-2", title: "Keep me" })]);
const incoming = library([resource({ title: "Imported title", status: "completed" })]);
const merged = Model.mergeLibraries(current, incoming);
assert.equal(merged.vaults[0].resources.length, 2);
assert.equal(merged.vaults[0].resources.find((item) => item.id === "resource-1").title, "Imported title");
assert.ok(merged.vaults[0].resources.some((item) => item.id === "resource-2"));
});
test("vault and folder operations preserve records safely", () => {
let data = Model.addVault(library(), "Second", "#abcdef");
assert.equal(data.vaults.length, 2);
data = Model.renameVault(data, data.vaults[1].id, "Renamed");
assert.equal(data.vaults[1].name, "Renamed");
data = Model.deleteVault(data, data.vaults[1].id);
assert.equal(data.vaults.length, 1);
data.vaults[0].resources.push(resource({ folderId: "folder-1" }));
data = Model.deleteFolder(data, "vault-1", "folder-1");
assert.equal(data.vaults[0].folders.length, 0);
assert.equal(data.vaults[0].resources[0].folderId, null);
});
test("progress is derived for pages, minutes, and article percentages", () => {
assert.equal(Model.progressFor(resource({ pageCount: 200, sessions: [{ end: 80 }] })).percent, 40);
assert.equal(Model.progressFor(resource({ type: "video", format: "web", durationMinutes: 60, sessions: [{ end: 45 }] })).percent, 75);
assert.equal(Model.progressFor(resource({ type: "article", format: "web", sessions: [{ end: 35 }] })).percent, 35);
assert.equal(Model.progressFor(resource({ status: "completed" })).percent, 100);
});
test("serialization round-trips metadata and marks PDF reattachment", () => {
const parsed = JSON.parse(Model.serialise(library([resource({ format: "pdf", attachmentId: "blob-1" })])));
assert.equal(Model.validateLibrary(parsed), true);
assert.equal(parsed.vaults[0].resources[0].attachmentState, "reattach-required-after-import");
assert.ok(parsed.exportedAt);
});