Merge remote-tracking branch 'gh/main' into wire2/j4qt

# Conflicts:
#	context/test-evidence/clients.md
This commit is contained in:
Edward Langley
2026-09-22 21:28:26 -07:00
31 changed files with 1715 additions and 572 deletions
+22 -1
View File
@@ -70,7 +70,7 @@ test.describe("every field the render model projects reaches the screen", () =>
await expect(page.locator("#categories")).toBeVisible();
await page.keyboard.press("Escape");
// `views`: empty unless open, so the page asks no question about the mode.
// `views`: `null` unless open, so the page asks no question about the mode.
await expect(page.locator("#views")).toBeHidden();
await page.keyboard.press("Shift+V");
await expect(page.locator("#views li")).toHaveCount(2);
@@ -356,6 +356,27 @@ test.describe("a pointer event reaches the client and its answer is painted", ()
});
});
test.describe("an open panel is drawn even when it has nothing in it", () => {
// improvise-df2w: `formulas` said "closed" by being empty, so a document with
// no formulas could open the panel and never see it. `tall.improv` has none.
test("the formula panel opens over a document with no formulas", async ({ page }) => {
await page.goto("/app/index.html?doc=df2w-empty.improv&seed=tall.improv");
await expect(page.locator("#grid table")).toBeVisible({ timeout: 20_000 });
await page.locator("#grid").focus();
await expect(page.locator("#formulas")).toBeHidden();
await page.keyboard.press("Shift+F");
await expect(page.locator("#mode")).toHaveText("FORMULAS");
await expect(page.locator("#formulas")).toBeVisible();
await expect(page.locator("#formulas li")).toHaveCount(0);
// And closed is still closed: the other direction, which a page that
// simply never hid the panel would fail.
await page.keyboard.press("Shift+F");
await expect(page.locator("#formulas")).toBeHidden();
});
});
test.describe("the selection is on screen", () => {
// improvise-jq8l: `web/app.js` called `scrollIntoView` NOWHERE, so a selection
// moved past the bottom of `#grid` simply stayed there, invisible, with no way
+9 -8
View File
@@ -36,12 +36,14 @@ async function anAggregateGrid(page) {
test.describe("drill is refused in the browser, not broken", () => {
// The honest half: `i`/`a` on an aggregate declines OUT LOUD, because
// `edit_or_drill` answers the `CellId::Aggregate` arm with a status.
test("editing an aggregate says drill needs the host", async ({ page }) => {
test("editing an aggregate says it is edited by drilling, and drill is missing", async ({
page,
}) => {
await anAggregateGrid(page);
await page.keyboard.press("i");
await expect(page.locator("#toast")).toContainText(
"drilling into an aggregate needs the host",
"an aggregate is edited by drilling in — drill is not available in the browser yet",
);
// And it really is a refusal: no editor opened, no mode change.
await expect(page.locator("#mode")).toHaveText("NORMAL");
@@ -63,16 +65,15 @@ test.describe("drill is refused in the browser, not broken", () => {
);
await expect(page.locator("#mode")).toHaveText("NORMAL");
// The two refusals have two SUBJECTS, and conflating them would be a
// true-sounding sentence about the wrong thing — worse than silence,
// because it stops the reader looking. `>` must not talk about aggregates.
// `>` is refused whatever the cell is, so it must not blame the cell.
await expect(page.locator("#toast")).not.toContainText("aggregate");
// And `i` still gives the OTHER refusal, which is what proves the two are
// distinct rather than one message reached by two keys.
// `i` reaches the SAME missing feature (in the TUI it drills), so it names
// it the same way and adds only why — improvise-s8h7, clients.md.
await page.keyboard.press("i");
await expect(page.locator("#toast")).toContainText("an aggregate is edited by drilling in");
await expect(page.locator("#toast")).toContainText(
"drilling into an aggregate needs the host",
"drill is not available in the browser yet",
);
});
});