Add Resource Loader SPA and JS test harness
All checks were successful
Build Org Website / build (push) Successful in 38s
All checks were successful
Build Org Website / build (push) Successful in 38s
This commit is contained in:
71
tests/resource-loader.test.js
Normal file
71
tests/resource-loader.test.js
Normal file
@@ -0,0 +1,71 @@
|
||||
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);
|
||||
});
|
||||
Reference in New Issue
Block a user