72 lines
3.4 KiB
JavaScript
Executable File
72 lines
3.4 KiB
JavaScript
Executable File
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);
|
|
});
|