61 lines
2.0 KiB
TypeScript
61 lines
2.0 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import { PendingSaveSyncRepository, SAVE_SYNC_RETRY_DELAYS_MS, SaveSyncRetryCoordinator } from "./saveSync";
|
|
|
|
function memoryStorage(initial = "[]") {
|
|
const values = new Map([["i-want-to-heal:saves:pending-sync:v1", initial]]);
|
|
return {
|
|
getItem: (key: string) => values.get(key) ?? null,
|
|
setItem: (key: string, value: string) => { values.set(key, value); },
|
|
};
|
|
}
|
|
|
|
describe("pending save sync", () => {
|
|
it("persists unique dirty slots and tolerates corrupt state", () => {
|
|
const storage = memoryStorage();
|
|
const pending = new PendingSaveSyncRepository(storage);
|
|
pending.mark(2);
|
|
pending.mark(2);
|
|
pending.mark(1);
|
|
expect(pending.list()).toEqual([2, 1]);
|
|
pending.clear(2);
|
|
expect(pending.list()).toEqual([1]);
|
|
expect(new PendingSaveSyncRepository(memoryStorage("not-json")).list()).toEqual([]);
|
|
});
|
|
|
|
it("waits offline and caps automatic retries", async () => {
|
|
const pending = new PendingSaveSyncRepository(memoryStorage());
|
|
pending.mark(1);
|
|
let online = false;
|
|
const uploads: number[] = [];
|
|
const tasks: Array<{ run: () => void; delay: number }> = [];
|
|
const coordinator = new SaveSyncRetryCoordinator(
|
|
pending,
|
|
async (slotId) => { uploads.push(slotId); return false; },
|
|
() => online,
|
|
(run, delay) => {
|
|
tasks.push({ run, delay });
|
|
return tasks.length as unknown as ReturnType<typeof setTimeout>;
|
|
},
|
|
() => undefined,
|
|
);
|
|
|
|
coordinator.flush();
|
|
expect(uploads).toEqual([]);
|
|
online = true;
|
|
coordinator.flush(true);
|
|
await Promise.resolve();
|
|
expect(uploads).toEqual([1]);
|
|
|
|
for (const delay of SAVE_SYNC_RETRY_DELAYS_MS) {
|
|
coordinator.failed(1);
|
|
expect(tasks[0]?.delay).toBe(delay);
|
|
tasks.shift()!.run();
|
|
await Promise.resolve();
|
|
}
|
|
coordinator.failed(1);
|
|
expect(tasks).toEqual([]);
|
|
expect(uploads).toHaveLength(1 + SAVE_SYNC_RETRY_DELAYS_MS.length);
|
|
coordinator.dispose();
|
|
});
|
|
});
|