test(data): pin each restore's notification after the DB lock

ADR 0022 wants a transactional write to notify once `withTransaction`
has returned, never from its callback. Only the categorization test
checked the lock; the restore tests checked that the notification
followed the COMMIT, which a notification sent from inside the callback
also satisfies. Each restore mode now asserts the lock was released.

Review of #396 (PR #402).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
le king fu 2026-10-08 21:05:14 -04:00
parent 696b83fb10
commit ec3b5d5185

View file

@ -31,7 +31,7 @@ vi.mock("./db", () => {
};
});
import { getDb } from "./db";
import { getDb, withTransaction } from "./db";
import {
getExportImportSources,
getExportImportTemplates,
@ -803,6 +803,46 @@ describe("a committed restore is announced on the data channel (#396)", () => {
expect(seen[0][seen[0].length - 1]).toBe("COMMIT");
});
// ADR 0022: a write notifies once `withTransaction` has returned, never from
// its callback, where the DB lock is still held.
it.each([
[
"transactions with categories",
() =>
importTransactionsWithCategories(
envelopeData({ transactions: [transactionFixture(1)] }),
"backup.json"
),
],
[
"transactions only",
() => importTransactionsOnly(envelopeData({ transactions: [transactionFixture(1)] }), "backup.json"),
],
[
"categories only",
() => importCategoriesOnly({ categories: CATEGORY_FIXTURES, suppliers: [], keywords: [] }),
],
] as const)("%s: notifies once the DB lock is released", async (_name, restore) => {
let inLock = false;
const locks: boolean[] = [];
const stop = subscribeDataChanged(() => locks.push(inLock));
vi.mocked(withTransaction).mockImplementation(async (fn) => {
inLock = true;
try {
return await fn((await getDb()) as never);
} finally {
inLock = false;
}
});
try {
await restore();
} finally {
stop();
vi.mocked(withTransaction).mockImplementation(async (fn) => fn((await getDb()) as never));
}
expect(locks).toEqual([false]);
});
it("a restore rolled back announces nothing", async () => {
let txInserts = 0;
wire(