test(backend): cover phase 5 and 6 migrations
This commit is contained in:
@@ -20,6 +20,7 @@ const ownerOne: DomainActor = { authUserId: "owner-1", role: "freelancer", clien
|
||||
const ownerTwo: DomainActor = { authUserId: "owner-2", role: "freelancer", clientId: null, disabled: false };
|
||||
const clientOne: DomainActor = { authUserId: "client-user-1", role: "client", clientId: "client-1", disabled: false };
|
||||
const clientTwo: DomainActor = { authUserId: "client-user-2", role: "client", clientId: "client-2", disabled: false };
|
||||
const spoofedClient: DomainActor = { authUserId: "client-user-2", role: "client", clientId: "client-1", disabled: false };
|
||||
|
||||
try {
|
||||
for (const actor of [ownerOne, ownerTwo, clientOne, clientTwo]) {
|
||||
@@ -58,6 +59,22 @@ try {
|
||||
});
|
||||
service.createProject(ownerOne, { id: "project-2", name: "Second Client", clientId: "client-2" });
|
||||
service.createProject(ownerTwo, { id: "project-other", name: "Other Project", clientId: "client-other" });
|
||||
assert.deepEqual(service.listProjects(clientOne).map((project) => project.id), ["project-1"]);
|
||||
assert.deepEqual(service.listProjects(spoofedClient), []);
|
||||
assertDomainError(() => service.getProject(spoofedClient, "project-1"), "NOT_FOUND");
|
||||
service.addClientActivity(ownerOne, {
|
||||
id: "activity-1",
|
||||
clientId: "client-1",
|
||||
type: "meeting",
|
||||
title: "Kickoff",
|
||||
activityDate: new Date("2026-07-15T09:00:00.000Z"),
|
||||
});
|
||||
assert.deepEqual(service.listClientActivities(ownerOne, "client-1").map((item) => item.id), ["activity-1"]);
|
||||
assert.deepEqual(service.listAllClientActivities(ownerOne).map((item) => item.id), ["activity-1"]);
|
||||
assertDomainError(() => service.listClientActivities(ownerTwo, "client-1"), "NOT_FOUND");
|
||||
service.updateClient(ownerOne, "client-1", { pipelineStage: "contacted" });
|
||||
service.updateClient(ownerOne, "client-1", { status: "paused" });
|
||||
assert.equal(service.getClient(ownerOne, "client-1").pipelineStage, "contacted");
|
||||
|
||||
service.createTask(ownerOne, {
|
||||
id: "task-public",
|
||||
@@ -78,11 +95,32 @@ try {
|
||||
assert.equal(service.getProject(ownerOne, "project-1").progress, 50, "Auto progress must aggregate active tasks");
|
||||
assert.deepEqual(service.listTasks(clientOne).map((task) => task.id), ["task-public"]);
|
||||
assertDomainError(() => service.getProject(clientOne, "project-2"), "NOT_FOUND");
|
||||
assertDomainError(() => service.listTasks(clientOne, "project-2"), "NOT_FOUND");
|
||||
assertDomainError(() => service.listTasks(spoofedClient), "NOT_FOUND");
|
||||
assertDomainError(() => service.listFinanceTransactions(clientOne), "FORBIDDEN");
|
||||
assertDomainError(() => service.updateTask(ownerTwo, "task-public", { status: "done" }), "NOT_FOUND");
|
||||
|
||||
service.updateTask(ownerOne, "task-private", { status: "done" });
|
||||
service.updateTask(ownerOne, "task-public", { description: "Patch without default resets" });
|
||||
assert.equal(service.listTasks(clientOne)[0]?.isPublicToClient, true);
|
||||
assert.equal(service.getProject(ownerOne, "project-1").progress, 100);
|
||||
service.updateProject(ownerOne, "project-1", { progress: 10 });
|
||||
assert.equal(service.getProject(ownerOne, "project-1").progress, 100, "Auto progress must ignore manual overwrite");
|
||||
|
||||
service.createCalendarEvent(ownerOne, {
|
||||
id: "calendar-1",
|
||||
clientId: "client-1",
|
||||
projectId: "project-1",
|
||||
taskId: "task-public",
|
||||
title: "Review",
|
||||
type: "meeting",
|
||||
startsAt: new Date("2026-07-16T10:00:00.000Z"),
|
||||
});
|
||||
assert.equal(service.listCalendarEvents(ownerOne)[0]?.title, "Review");
|
||||
service.updateCalendarEvent(ownerOne, "calendar-1", { title: "Final review" });
|
||||
assert.equal(service.listCalendarEvents(ownerOne)[0]?.title, "Final review");
|
||||
assert.equal(service.listCalendarEvents(ownerOne)[0]?.type, "meeting");
|
||||
assertDomainError(() => service.deleteCalendarEvent(ownerTwo, "calendar-1"), "NOT_FOUND");
|
||||
|
||||
service.addPlanningSection(ownerOne, {
|
||||
id: "planning-1",
|
||||
@@ -90,11 +128,26 @@ try {
|
||||
category: "overview",
|
||||
title: "Overview",
|
||||
content: "Visible project context",
|
||||
sortOrder: 3,
|
||||
});
|
||||
service.updatePlanningSection(ownerOne, "planning-1", { title: "Updated overview" });
|
||||
assert.equal(service.listPlanningSections(ownerOne, "project-1")[0]?.sortOrder, 3);
|
||||
assert.equal(service.listPlanningSections(clientOne, "project-1").length, 1);
|
||||
assertDomainError(() => service.listPlanningSections(clientTwo, "project-1"), "NOT_FOUND");
|
||||
|
||||
assert.deepEqual(service.getRevisionAllowance(clientOne, "project-1"), {
|
||||
quota: 1,
|
||||
used: 0,
|
||||
remaining: 1,
|
||||
canRequest: true,
|
||||
});
|
||||
assert.equal(service.requestRevision(clientOne, { id: "revision-1", projectId: "project-1", description: "Please revise" }).status, "pending");
|
||||
assert.deepEqual(service.getRevisionAllowance(clientOne, "project-1"), {
|
||||
quota: 1,
|
||||
used: 1,
|
||||
remaining: 0,
|
||||
canRequest: false,
|
||||
});
|
||||
assertDomainError(
|
||||
() => service.requestRevision(clientOne, { id: "revision-2", projectId: "project-1", description: "Quota overflow" }),
|
||||
"CONFLICT",
|
||||
@@ -103,8 +156,22 @@ try {
|
||||
() => service.requestRevision(clientTwo, { id: "revision-3", projectId: "project-1", description: "Wrong client" }),
|
||||
"NOT_FOUND",
|
||||
);
|
||||
assert.equal(service.updateRevisionStatus(ownerOne, "revision-1", "completed").status, "completed");
|
||||
assertDomainError(
|
||||
() => service.requestRevision(spoofedClient, { id: "revision-spoof", projectId: "project-1", description: "Spoofed link" }),
|
||||
"NOT_FOUND",
|
||||
);
|
||||
assertDomainError(
|
||||
() => service.requestRevision(clientTwo, { id: "revision-inactive", projectId: "project-2", description: "Inactive project" }),
|
||||
"INVARIANT_VIOLATION",
|
||||
);
|
||||
assertDomainError(
|
||||
() => service.updateRevisionStatus(ownerOne, "revision-1", "completed", "project-2"),
|
||||
"NOT_FOUND",
|
||||
);
|
||||
assert.equal(service.updateRevisionStatus(ownerOne, "revision-1", "completed", "project-1").status, "completed");
|
||||
assert.deepEqual(service.listRevisions(clientOne, "project-1").map((revision) => revision.id), ["revision-1"]);
|
||||
assert.deepEqual(service.listPortalRevisions(clientOne).map((revision) => revision.id), ["revision-1"]);
|
||||
assertDomainError(() => service.listRevisions(clientTwo, "project-1"), "NOT_FOUND");
|
||||
|
||||
service.createFinanceTransaction(ownerOne, {
|
||||
id: "income-1", type: "income", amountMinor: 150_00, currency: "try", transactionDate: "2026-07-16", paymentStatus: "paid",
|
||||
@@ -124,11 +191,33 @@ try {
|
||||
plannedMinor: 75_00,
|
||||
netMinor: 110_00,
|
||||
});
|
||||
service.createFinanceTransaction(ownerOne, {
|
||||
id: "project-income",
|
||||
clientId: "client-1",
|
||||
projectId: "project-1",
|
||||
type: "income",
|
||||
amountMinor: 10_00,
|
||||
currency: "TRY",
|
||||
transactionDate: "2026-07-16",
|
||||
paymentStatus: "paid",
|
||||
});
|
||||
service.updateFinanceTransaction(ownerOne, "project-income", { description: "Patched" });
|
||||
assert.equal(
|
||||
service.listFinanceTransactions(ownerOne).find((item) => item.id === "project-income")?.paymentStatus,
|
||||
"paid",
|
||||
);
|
||||
|
||||
service.saveJournalEntry(ownerOne, { id: "journal-1", entryDate: "2026-07-16", moodScore: 3, note: "First" });
|
||||
service.saveJournalEntry(ownerOne, { entryDate: "2026-07-16", moodScore: 5, note: "Updated" });
|
||||
assert.equal(service.listJournalEntries(ownerOne).length, 1, "Journal date must upsert per owner");
|
||||
assert.equal(service.listJournalEntries(ownerOne)[0]?.moodScore, 5);
|
||||
service.updateJournalEntry(ownerOne, "journal-1", {
|
||||
entryDate: "2026-07-16",
|
||||
moodScore: 4,
|
||||
energyScore: 3,
|
||||
note: "Edited",
|
||||
});
|
||||
assert.equal(service.listJournalEntries(ownerOne)[0]?.note, "Edited");
|
||||
assertDomainError(
|
||||
() => service.createTask(ownerTwo, { title: "Foreign journal", sourceJournalEntryId: "journal-1" }),
|
||||
"NOT_FOUND",
|
||||
@@ -143,6 +232,23 @@ try {
|
||||
service.createInvoice(ownerOne, { id: "invoice-1", clientId: "client-1", projectId: "project-1", invoiceNumber: "INV-001", amountMinor: 100_00, issueDate: "2026-07-16" });
|
||||
service.createSubscription(ownerOne, { id: "subscription-1", name: "Hosting", amountMinor: 500_00 });
|
||||
|
||||
const analyticsRange = {
|
||||
startDate: "2026-01-01",
|
||||
endDate: "2026-12-31",
|
||||
startAt: new Date("2026-01-01T00:00:00.000Z"),
|
||||
endAt: new Date("2026-12-31T23:59:59.999Z"),
|
||||
};
|
||||
const dashboard = service.getFreelancerDashboard(ownerOne, analyticsRange);
|
||||
assert.equal(dashboard.metrics.netProfit, 120);
|
||||
assert.equal(dashboard.metrics.avgMood, "4.0");
|
||||
assert.deepEqual(
|
||||
new Set(dashboard.projects.map((project) => project.id)),
|
||||
new Set(["project-1", "project-2"]),
|
||||
);
|
||||
const rangedAnalytics = service.getFreelancerAnalytics(ownerOne, analyticsRange);
|
||||
assert.deepEqual(rangedAnalytics.projectIncomeData, [{ name: "Client Project", value: 10 }]);
|
||||
assert.equal(rangedAnalytics.completedTasks, 2);
|
||||
|
||||
assert.throws(
|
||||
() => sqlite.prepare("insert into finance_transactions (id, owner_user_id, type, amount_minor, currency, transaction_date, payment_status) values (?, ?, ?, ?, ?, ?, ?)").run("invalid-finance", ownerOne.authUserId, "income", -1, "TRY", "2026-07-16", "paid"),
|
||||
/CHECK constraint failed/,
|
||||
|
||||
Reference in New Issue
Block a user