fix(studio): drain pending edits before reload (#2989)

* fix(studio): drain pending edits before reload

* fix(studio): address drain review feedback (#2989)

- prioritize conflicts and clear recovered DOM queue errors
- cover delayed blur effects and missing drain branches
- document stacked consumers and extend write-token retention

* test(studio): satisfy drain audit gate (#2989)

- share the editor-save hook harness across drain regressions
- extract settled failure inspection from the drain loop
This commit is contained in:
Miguel Ángel
2026-08-04 20:58:19 +00:00
committed by GitHub
parent 552419c52d
commit 4713138544
9 changed files with 513 additions and 48 deletions
@@ -1,5 +1,11 @@
import { describe, expect, it } from "vitest";
import { studioExpectedFileVersion, studioFileContentVersion } from "./studioFileVersion";
import {
consumeStudioWriteToken,
markStudioWriteToken,
resetStudioWriteTokens,
studioExpectedFileVersion,
studioFileContentVersion,
} from "./studioFileVersion";
describe("studioFileContentVersion", () => {
it("matches the strong SHA-256 ETag format used by studio-server", async () => {
@@ -34,3 +40,24 @@ describe("studioFileContentVersion", () => {
expect(await studioExpectedFileVersion(versions, "untracked.html")).toBeUndefined();
});
});
describe("studio write-token echo identity", () => {
it("suppresses exactly one matching API write receipt without hiding path-only external writes", () => {
resetStudioWriteTokens();
markStudioWriteToken("studio-write-1");
expect(consumeStudioWriteToken("studio-write-1")).toBe(true);
expect(consumeStudioWriteToken("studio-write-1")).toBe(false);
expect(consumeStudioWriteToken(null)).toBe(false);
});
it("keeps a token through a slow write and expires abandoned identity state", () => {
resetStudioWriteTokens();
markStudioWriteToken("slow-studio-write", 1_000);
expect(consumeStudioWriteToken("slow-studio-write", 61_000)).toBe(true);
markStudioWriteToken("abandoned-studio-write", 1_000);
expect(consumeStudioWriteToken("abandoned-studio-write", 301_000)).toBe(false);
});
});