import { assert } from "chai"; import { describe, it, beforeEach, afterEach } from "node:test"; import * as m from "../index"; import * as config from "./config"; import mockModule from "./mock"; describe("DataSharingAgreement", function() { let models: m.BackendModels, mongoose: m.MongooseModule; let testItem: ReturnType["dataSharingAgreement"]; beforeEach(async function() { const c = await m.connect(config.url); models = c.models; mongoose = c.mongoose; testItem = mockModule({ mongoose }).dataSharingAgreement; await models.DataSharingAgreement.deleteMany({}); }); afterEach(async function() { await models.DataSharingAgreement.deleteMany({}); await mongoose.disconnect(); }); it("is saved and reads back every field", async function() { const sut = await new models.DataSharingAgreement(testItem).save(); assert.isNotNull(sut._id); assert.equal(sut.id, sut._id.toHexString()); assert.isString(sut.uuid); assert.isTrue(sut.uuid !== ""); assert.equal(sut.departmentId, testItem.departmentId); assert.equal(sut.departmentName, testItem.departmentName); assert.equal(sut.agencyId?.toHexString(), testItem.agencyId.toHexString()); assert.equal(sut.agencyName, testItem.agencyName); assert.equal(sut.userId, testItem.userId); assert.equal(sut.email, testItem.email); assert.equal(sut.signerName, testItem.signerName); assert.equal(sut.agreementTitle, testItem.agreementTitle); assert.equal(sut.agreementVersion, testItem.agreementVersion); assert.equal(sut.agreementText, testItem.agreementText); assert.equal(sut.action, "signed"); assert.equal(sut.consents.length, 2); assert.equal(sut.consents[0]?.key, "shareAVL"); assert.equal(sut.consents[0]?.label, testItem.consents[0]?.label); assert.isTrue(sut.consents[0]?.checked); assert.equal(sut.consents[1]?.key, "intterra"); assert.isFalse(sut.consents[1]?.checked); assert.equal(sut.remoteAddress, testItem.remoteAddress); assert.equal(sut.userAgent, testItem.userAgent); assert.equal(sut.appVersion, testItem.appVersion); assert.equal(sut.createdAt.toISOString(), testItem.createdAt.toISOString()); assert.instanceOf(sut.modified, Date); }); it("defaults optional fields", async function() { const sut = await new models.DataSharingAgreement({ departmentId: "d1", userId: "u1", email: "u1@example.com", agreementTitle: "Data Sharing Addendum", agreementVersion: "2026-08-1", agreementText: "text", action: "revoked", }).save(); assert.isString(sut.uuid); assert.isTrue(sut.uuid !== ""); assert.equal(sut.departmentName, ""); assert.isNull(sut.agencyId); assert.equal(sut.agencyName, ""); assert.equal(sut.signerName, ""); assert.deepEqual(sut.consents, []); assert.equal(sut.remoteAddress, ""); assert.equal(sut.userAgent, ""); assert.equal(sut.appVersion, ""); assert.instanceOf(sut.createdAt, Date); assert.instanceOf(sut.modified, Date); }); it("defaults consent label and checked", async function() { const sut = await new models.DataSharingAgreement({ ...testItem, consents: [{ key: "firstArriving" }], }).save(); assert.equal(sut.consents.length, 1); assert.equal(sut.consents[0]?.key, "firstArriving"); assert.equal(sut.consents[0]?.label, ""); assert.isFalse(sut.consents[0]?.checked); }); it("requires the legal-record fields", async function() { const required = [ "departmentId", "userId", "email", "agreementTitle", "agreementVersion", "agreementText", "action", ]; for (const field of required) { const item: Record = { ...testItem }; delete item[field]; try { await new models.DataSharingAgreement(item).save(); assert.isFalse(true, `Expecting missing ${field} to fail validation.`); } catch (error) { assert.match((error as Error).message, new RegExp(`${field}.*required`, "i")); } } }); it("rejects a consent without a key", async function() { try { await new models.DataSharingAgreement({ ...testItem, consents: [{ label: "No key", checked: true }], }).save(); assert.isFalse(true, "Expecting consent without key to fail validation."); } catch (error) { assert.match((error as Error).message, /key.*required/i); } }); it("only accepts known actions", async function() { for (const action of m.DataSharingAgreementActions) { const sut = await new models.DataSharingAgreement({ ...testItem, action }).save(); assert.equal(sut.action, action); } try { await new models.DataSharingAgreement({ ...testItem, action: "deleted" }).save(); assert.isFalse(true, "Expecting unknown action to fail validation."); } catch (error) { assert.match((error as Error).message, /action/); assert.match((error as Error).message, /enum/i); } }); it("does not change record fields on a re-save", async function() { const saved = await new models.DataSharingAgreement(testItem).save(); const loaded = await models.DataSharingAgreement.findById(saved._id); assert.isNotNull(loaded); if (!loaded) { return; } loaded.set({ departmentId: "other-department", action: "revoked", agreementText: "tampered", agreementVersion: "9999-01-1", consents: [], remoteAddress: "10.0.0.1", createdAt: new Date("2000-01-01T00:00:00.000Z"), }); await loaded.save(); const reloaded = await models.DataSharingAgreement.findById(saved._id); assert.isNotNull(reloaded); assert.equal(reloaded?.departmentId, testItem.departmentId); assert.equal(reloaded?.action, "signed"); assert.equal(reloaded?.agreementText, testItem.agreementText); assert.equal(reloaded?.agreementVersion, testItem.agreementVersion); assert.equal(reloaded?.consents.length, 2); assert.equal(reloaded?.remoteAddress, testItem.remoteAddress); assert.equal(reloaded?.createdAt.toISOString(), testItem.createdAt.toISOString()); }); it("keeps every record as history, newest first", async function() { const signed = await new models.DataSharingAgreement({ ...testItem, action: "signed", createdAt: new Date("2026-08-20T17:30:00.000Z"), }).save(); const updated = await new models.DataSharingAgreement({ ...testItem, action: "updated", consents: [ { key: "shareAVL", label: "AVL Sharing (CAL FIRE Op Area)", checked: true }, { key: "intterra", label: "Intterra", checked: true }, ], createdAt: new Date("2026-08-21T09:00:00.000Z"), }).save(); const revoked = await new models.DataSharingAgreement({ ...testItem, action: "revoked", consents: [ { key: "shareAVL", label: "AVL Sharing (CAL FIRE Op Area)", checked: false }, { key: "intterra", label: "Intterra", checked: false }, ], createdAt: new Date("2026-08-22T09:00:00.000Z"), }).save(); // Another department must not leak into the history await new models.DataSharingAgreement({ ...testItem, departmentId: "other-department", }).save(); const history = await models.DataSharingAgreement.find({ departmentId: testItem.departmentId, }).sort({ createdAt: -1 }); assert.equal(history.length, 3); assert.equal(history[0]?.id, revoked.id); assert.equal(history[1]?.id, updated.id); assert.equal(history[2]?.id, signed.id); assert.isFalse(history[0]?.consents.every((c) => c.checked)); assert.isTrue(history[1]?.consents.every((c) => c.checked)); }); it("declares only the history index and no TTL index", async function() { await models.DataSharingAgreement.syncIndexes(); const indexes = await models.DataSharingAgreement.collection.indexes(); const names = indexes.map((i) => i.name).sort(); assert.deepEqual(names, ["_id_", "departmentId_1_createdAt_-1__id_-1"]); const history = indexes.find((i) => i.name === "departmentId_1_createdAt_-1__id_-1"); assert.deepEqual(history?.key, { departmentId: 1, createdAt: -1, _id: -1 }); for (const index of indexes) { assert.isUndefined(index.expireAfterSeconds, `Unexpected TTL on ${index.name}`); } }); it("serializes with id and without version key", async function() { const sut = await new models.DataSharingAgreement(testItem).save(); const json = sut.toJSON() as Record; assert.equal(json.id, sut._id.toHexString()); assert.isUndefined(json.__v); assert.equal(json.agreementText, testItem.agreementText); }); });