WIP red: mouse editor stale seed and touched (improvise-ugj4, improvise-jibp)

This commit is contained in:
Edward Langley
2026-09-23 08:26:36 -07:00
parent 194d8f529c
commit c4877456a4
+83
View File
@@ -9,6 +9,19 @@ import { test, expect } from "@playwright/test";
// the same with the handshake window).
import { NOTICE_KEY } from "../../web/shell.js";
/** Every string the page posts to its worker, kept on `window.__posted`. */
function recordPosts() {
window.__posted = [];
const post = Worker.prototype.postMessage;
Worker.prototype.postMessage = function (message, ...rest) {
window.__posted.push(String(message));
return post.call(this, message, ...rest);
};
}
const setCells = (page) =>
page.evaluate(() => window.__posted.filter((m) => m.includes("SetCell")).length);
async function openApp(page) {
await page.goto("/app/index.html");
await expect(page.locator("#grid table")).toBeVisible({ timeout: 20_000 });
@@ -320,6 +333,76 @@ test.describe("a pointer event reaches the client and its answer is painted", ()
await expect.poll(writes).toBe(1);
});
// improvise-jibp. The page reports its first edit, so retyping the seed over
// the selection is a write, not an untouched editor.
test("a mouse editor typed back to its own seed still writes", async ({ page }) => {
await page.addInitScript(recordPosts);
await openApp(page);
const cells = page.locator("#grid tbody td");
await cells.nth(4).click();
const input = cells.nth(4).locator("input");
await expect(input).toHaveCount(1);
const seed = await input.inputValue();
expect(seed, "the fixture cell has no seed to retype").not.toBe("");
await page.keyboard.type(seed);
await expect(input).toHaveValue(seed);
await page.keyboard.press("Enter");
await expect.poll(() => setCells(page)).toBe(1);
});
// improvise-ugj4. A frame that lands while an editor is open changes the
// cache but not the paint; the next editor must open on what it captured.
test("an editor opened after an unpainted write shows and commits what it captured", async ({
page,
}) => {
await page.addInitScript(recordPosts);
await page.addInitScript(() => {
window.__frames = [];
const add = Worker.prototype.addEventListener;
Worker.prototype.addEventListener = function (type, listener, ...rest) {
if (type !== "message") return add.call(this, type, listener, ...rest);
window.__deliver = (data) => listener.call(this, new MessageEvent("message", { data }));
const recorded = (event) => {
if (typeof event.data === "string") window.__frames.push(event.data);
return listener.call(this, event);
};
return add.call(this, type, recorded, ...rest);
};
});
await openApp(page);
const cells = page.locator("#grid tbody td");
const target = cells.nth(4);
const where = await target.evaluate((td) => [Number(td.dataset.row), Number(td.dataset.col)]);
await cells.nth(0).click();
await expect(cells.nth(0).locator("input")).toHaveCount(1);
// Another client's write to cell 4, delivered while cell 0's editor is open.
await page.evaluate(([row, col]) => {
let latest = null;
const walk = (node) => {
if (Array.isArray(node)) node.forEach(walk);
else if (node && typeof node === "object") {
for (const [key, value] of Object.entries(node)) {
if (key === "Cells" && Array.isArray(value)) {
for (const [[r, c], cell] of value) if (r === row && c === col) latest = cell;
} else walk(value);
}
}
};
window.__frames.forEach((f) => walk(JSON.parse(f)));
const moved = { ...latest, text: "777", edit_text: "777", value: { Number: 777 } };
window.__deliver(JSON.stringify({ Commands: [{ Project: { Grid: { Cells: [[[row, col], moved]] } } }] }));
}, where);
await target.click();
const input = target.locator("input");
await expect(input).toHaveCount(1);
await expect(input, "the editor opened on the stale paint").toHaveValue("777");
await page.keyboard.press("Enter");
await page.waitForTimeout(300);
expect(await setCells(page), "an untouched editor wrote the stale text").toBe(0);
});
// improvise-b8ot moved these five surfaces onto one handler per stable root.
// The three tests below are the properties a naive delegation loses, each of
// which is silent: the page still paints, and only the pointer stops working.