Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
50 lines
3.3 KiB
TypeScript
50 lines
3.3 KiB
TypeScript
import { randomUUID } from "node:crypto";
|
|
import { tmpdir } from "node:os";
|
|
import { join } from "node:path";
|
|
import { DatabaseSync } from "node:sqlite";
|
|
import { describe, expect, test } from "vitest";
|
|
import { DatabaseConnection } from "../../src/main/database/connection";
|
|
import { OrganizationService } from "../../src/main/services/organization-service";
|
|
import { DocumentService } from "../../src/main/services/document-service";
|
|
import { documentVersionsSchema } from "../../src/main/database/migrations/065-document-versions";
|
|
|
|
describe("document versions", () => {
|
|
test("every update is a new version; earlier versions stay intact, even after deletion", () => {
|
|
const connection = new DatabaseConnection(join(tmpdir(), `ac-docver-${randomUUID()}.db`));
|
|
let orgId = "";
|
|
connection.transaction(() => {
|
|
orgId = new OrganizationService(connection.db).createOrganization({ organizationName: "V", employeeName: "Y", mission: "m", goal: "g" });
|
|
});
|
|
const documents = new DocumentService(connection.db);
|
|
const employeeId = (connection.db.prepare("select id from employees where org_id = ?").get(orgId) as { id: string }).id;
|
|
const id = documents.create({ orgId, title: "Spec", docType: "spec", content: "v1 body", authorAgentId: null, reviewerAgentId: null, projectId: null, goalId: null, taskId: null });
|
|
expect(documents.update({ orgId, documentId: id, title: "Spec", content: "v2 body", status: "review", reason: "Added API", changedByType: "employee", changedById: employeeId })).toBe(2);
|
|
expect(() => documents.update({ orgId, documentId: id, title: "Spec", content: "v3", status: "review", reason: " ", changedByType: "employee", changedById: employeeId }))
|
|
.toThrow("A document update needs a reason.");
|
|
expect(documents.versions(orgId, id).map((v) => [v.version, v.content, v.status, v.reason])).toEqual([
|
|
[1, "v1 body", "draft", "created"],
|
|
[2, "v2 body", "review", "Added API"],
|
|
]);
|
|
expect(connection.db.prepare("select version, content from documents where id = ?").get(id)).toEqual({ version: 2, content: "v2 body" });
|
|
documents.delete({ orgId, documentId: id, deletedByEmployeeId: employeeId });
|
|
expect(documents.versions(orgId, id)).toHaveLength(2);
|
|
connection.close();
|
|
});
|
|
|
|
test("the migration records each existing document as version 1", () => {
|
|
const db = new DatabaseSync(join(tmpdir(), `ac-docmig-${randomUUID()}.db`));
|
|
db.exec(`
|
|
create table organizations(id text primary key);
|
|
create table schema_migrations(version integer primary key, name text not null, applied_at text not null);
|
|
create table documents(id text primary key, org_id text, title text, content text, status text, author_agent_id text, created_at text);
|
|
insert into organizations values ('org_1');
|
|
insert into documents values ('doc_1', 'org_1', 'T', 'C', 'approved', 'agt_1', '2026-01-01T00:00:00.000Z');
|
|
`);
|
|
db.exec(documentVersionsSchema);
|
|
expect(db.prepare("select document_id, version, content, status, changed_by_type, changed_by_id, reason from document_versions").all())
|
|
.toEqual([{ document_id: "doc_1", version: 1, content: "C", status: "approved", changed_by_type: "agent", changed_by_id: "agt_1", reason: "created" }]);
|
|
expect(db.prepare("select version from documents").get()).toEqual({ version: 1 });
|
|
db.close();
|
|
});
|
|
});
|