Files
improvise/harness/tests/drill.spec.js
T
Edward Langley 334e218c7b s8h7: i on an aggregate names drill, in help and in the browser
In the TUI, EditOrDrill hands an aggregated cell to DrillIntoCell, so `i`
on an aggregate is drill by another door. The help page called it only
"Edit current cell", and the browser refused it in words unrelated to `>`'s,
so a user could not tell the two were one missing feature.

- help.rs: the edit-or-drill row says it drills into an aggregate.
- help.rs: Normal-mode Enter was captioned "Edit current cell (same as i)"
  but is bound to enter-advance alone, which only moves down; the row moves
  to Cursor movement and says so.
- resolve.rs: the Aggregate arm now reads "an aggregate is edited by
  drilling in — " + not_yet("drill"), the same sentence `>` uses.
- context/code/clients.md and the evidence entry reverse the recorded
  "different sentences on purpose" rationale, which was false about the TUI.
- harness/tests/drill.spec.js follows the new wording.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
2026-09-22 20:53:18 -07:00

80 lines
3.6 KiB
JavaScript

// Drill in the browser: what it does today, which is refuse. improvise-gd28
// says why, and context/test-evidence/clients.md records the layer it stops at.
import { test, expect } from "@playwright/test";
/// `web/demo.improv` has NO aggregate cell by construction — gotcha 46 puts
/// exactly one category on each visible axis so every cell is a Record, and
/// `tests/web_demo_model.rs` asserts it. So a drill test must MAKE one first.
async function anAggregateGrid(page) {
await page.goto("/app/index.html");
await expect(page.locator("#grid table")).toBeVisible({ timeout: 20_000 });
await page.locator("#grid").focus();
await expect(page.locator("#grid td.editable").first()).toBeVisible();
// Quarter is on Page; one cycle takes it to None, so every cell aggregates
// over the four quarters. The tile bar is how a user would do it.
await page.keyboard.press("Shift+T");
const tiles = page.locator("#tiles .tile");
const quarter = tiles.filter({ hasText: "Quarter" });
await expect(quarter).toHaveText("Quarter Page");
const names = await tiles.allTextContents();
for (let i = 0; i < names.findIndex((t) => t.startsWith("Quarter")); i++) {
await page.keyboard.press("ArrowRight");
}
await expect(quarter).toHaveClass(/selected/);
await page.keyboard.press("Enter");
await expect(quarter).toHaveText("Quarter None", { timeout: 10_000 });
await page.keyboard.press("Escape");
// The precondition, asserted rather than assumed: nothing is editable now,
// which is `CellId::Aggregate` reaching `render.rs::editable` (ADR 002).
await expect(page.locator("#grid td.editable")).toHaveCount(0);
await expect(page.locator("#grid tbody td").first()).toBeVisible();
}
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 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(
"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");
await expect(page.locator("#grid input")).toHaveCount(0);
});
// `>` is the key the hint line advertises as ":drill", and it used to be a
// name `resolve::step` did not handle — so `KeyOutcome::Upstream` ->
// `ClientFrame::Key` -> `Host::handle`'s empty vec, a black hole rather than
// a slow path (gotcha 47). It now answers. Interim until improvise-gd28.
test("the drill key says drill is unavailable, not something about aggregates", async ({
page,
}) => {
await anAggregateGrid(page);
await page.keyboard.press(">");
await expect(page.locator("#toast")).toContainText(
"drill is not available in the browser yet",
);
await expect(page.locator("#mode")).toHaveText("NORMAL");
// `>` is refused whatever the cell is, so it must not blame the cell.
await expect(page.locator("#toast")).not.toContainText("aggregate");
// `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(
"drill is not available in the browser yet",
);
});
});