Files
HealthLog/src/lib/export/__tests__/restore-target-models.test.ts
T
Marc-André Bombeck 9baeb95bab feat(backup): say whether an account can take an erased account's copy
A restore replaces the account's records and has no merge, so the copy
of an account that no longer exists may only go into an account that
holds none of the records a backup carries. The check reads every
backed-up model by its userId, reaches the owner-less children through
their parent, and is held to the schema so a new model cannot be read
as empty. Managed profiles and accounts pending deletion are refused as
well. The admin console asks GET /api/admin/backups/targets/{userId}
before it sends a file again, so a refusal costs no upload.
2026-10-29 20:11:08 +01:00

46 lines
1.7 KiB
TypeScript

/**
* The emptiness check behind restoring an erased account's copy into another
* account reads every backed-up model by its `userId`, except the children
* that have none, which it reaches through their parent. Both halves are held
* to `prisma/schema.prisma` here, so a backed-up model added later is either
* checked or fails this file; it cannot be skipped and read as empty.
*
* Mutation check: drop a model from `BACKED_UP_CHILD_MODELS` and the first
* case names it (no `userId`); add an owned model to it and the second does.
*/
import { describe, expect, it } from "vitest";
import { parseWipeSchema } from "@/__tests__/helpers/wipe-schema-shape";
import { BACKED_UP_MODELS } from "@/lib/export/backup-plan";
import {
BACKED_UP_CHILD_MODELS,
RESTORE_TARGET_OWNED_MODELS,
} from "@/lib/export/restore-target";
const models = parseWipeSchema();
describe("restore target models", () => {
it("reads every owned backed-up model by its userId", () => {
const missing = RESTORE_TARGET_OWNED_MODELS.filter(
(model) => !models.get(model)?.scalars.includes("userId"),
);
expect(missing).toEqual([]);
expect(RESTORE_TARGET_OWNED_MODELS.length).toBeGreaterThan(60);
});
it("reaches each child through a required cascade to an owned parent", () => {
for (const [child, parent] of Object.entries(BACKED_UP_CHILD_MODELS)) {
expect(BACKED_UP_MODELS, child).toContain(child);
const shape = models.get(child);
expect(shape?.scalars, child).not.toContain("userId");
expect(
shape?.relations.some(
(r) => r.target === parent && r.cascade && !r.optional,
),
`${child} -> ${parent}`,
).toBe(true);
expect(RESTORE_TARGET_OWNED_MODELS, parent).toContain(parent);
}
});
});