Deck/homework writes sync themselves when sync is on
Sync was push-on-demand only: a deck frozen on the laptop stayed in dirty
until someone opened Settings and pressed Sync now. The two stores whose
writes mean "the user just made something" now schedule one debounced
background syncNow("auto") through lib/sync-auto: debounced 2.5s so a burst
of writes is one push, one run at a time, silent on failure (the data stays
dirty and Settings still offers the manual sync), retried on the browser's
online event, and imported dynamically so the sync code stays out of the
first load with no import cycle.
markSyncDirty() now reports whether it actually marked, which keeps pull and
backup-import paths quiet while a real import pushes like any other local
change. Answers and chat keep the existing manual behaviour on purpose —
they change every few seconds while studying.
Tests: phase-1 (a deck write pushes itself, then Sync now is a no-op — 50
checks) and phase-3 (a check run pushes the new homework record — 30 checks).
README: decision 59. SW -> freezmo-v46.
This commit is contained in:
parent
d559865a09
commit
abacfb6018
8 changed files with 173 additions and 11 deletions
|
|
@ -181,7 +181,7 @@ async function openSettings(page) {
|
|||
!envelope.body.includes("Photosynthesis") && !envelope.body.includes("test-key") && !envelope.body.includes("apiKey"),
|
||||
);
|
||||
|
||||
// a real UI write marks dirty, then push
|
||||
// a real UI write marks dirty, then pushes itself (no Sync now press)
|
||||
await page.keyboard.press("Escape");
|
||||
await page.waitForTimeout(500);
|
||||
await page.getByRole("button", { name: "Deck actions" }).first().click();
|
||||
|
|
@ -191,10 +191,34 @@ async function openSettings(page) {
|
|||
const dirty = await page.evaluate(() => JSON.parse(localStorage.getItem("freezmo.sync.v1")).dirtyAt);
|
||||
check("sync: local change marks dirty", typeof dirty === "number");
|
||||
const remainingTitle = await page.evaluate(() => JSON.parse(localStorage.getItem("freezmo.decks.v1"))[0].title);
|
||||
const serverBlob = () =>
|
||||
page.evaluate(async () => {
|
||||
const record = JSON.parse(localStorage.getItem("freezmo.sync.v1"));
|
||||
const response = await fetch(`/api/sync?id=${record.id}`, { headers: { "x-ollama-key": "test-key" } });
|
||||
const body = response.ok ? await response.json() : null;
|
||||
return {
|
||||
dirtyAt: record.dirtyAt,
|
||||
lastSyncedAt: record.lastSyncedAt,
|
||||
status: response.status,
|
||||
updatedAt: body?.updatedAt ?? null,
|
||||
};
|
||||
});
|
||||
// Deck writes push on their own within a few seconds (lib/sync-auto).
|
||||
await page.waitForTimeout(4200);
|
||||
const auto = await serverBlob();
|
||||
check(
|
||||
"sync: a deck write pushes itself",
|
||||
auto.status === 200 &&
|
||||
auto.dirtyAt === null &&
|
||||
typeof auto.updatedAt === "number" &&
|
||||
typeof auto.lastSyncedAt === "number",
|
||||
JSON.stringify(auto),
|
||||
);
|
||||
// The manual button stays: after the auto-push there is nothing left to do.
|
||||
await openSettings(page);
|
||||
await page.getByRole("button", { name: "Sync now" }).click();
|
||||
await page.waitForTimeout(2500);
|
||||
check("sync: push reports uploaded", await page.getByText("Uploaded from this device.").isVisible());
|
||||
await page.waitForTimeout(2200);
|
||||
check("sync: Sync now finds nothing left to push", await page.getByText("Up to date.").isVisible());
|
||||
const id = syncRecord.id;
|
||||
await context.close();
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue