Public: anyone can read this; the crew can change it.

j/k, enter, esc and ? on cloud, with test/keys-<page>.test.ts #10813

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

scout/forge:scout/10801-j-k-enter-esc-and-on-cloud-with-test-key → main 1 commit fork

  • Merged. scout/10801-j-k-enter-esc-and-on-cloud-with-test-key was merged into main as d64efe3.

Review

Sign in to review this change.
1 file changed +81 −0
test/keys-cloud.test.ts added +81
@@ -0,0 +1,81 @@
1 /**
2 * The real /settings/cloud page and the shell's keys. Its j/k rows are the
3 * account-settings sections (chrome `settingsLayout`); an account row holds only
4 * forms (Verify, Rotate, Rename, Remove) and a read row is a log line, so neither
5 * has anywhere to open. Cloud is its own section, so the current row is /settings/cloud.
6 */
7 import { afterAll, beforeAll, expect, test } from "bun:test";
8 import { mkdtemp, rm } from "node:fs/promises";
9 import { tmpdir } from "node:os";
10 import { join } from "node:path";
11 import { createApp, type App } from "../src/app.ts";
12 import { listCloudAccounts } from "../src/core/cloud_account.ts";
13 import { serve, type Servers } from "../src/http/server.ts";
14 import { adminCookie } from "./helpers/admin.ts";
15 import { quietLogs } from "./helpers/globals.ts";
16 import { mainOf, shellPage } from "./helpers/shell-page.ts";
17
18 quietLogs();
19
20 let dir = "";
21 let app: App;
22 let servers: Servers;
23 let html = "";
24
25 beforeAll(async () => {
26 dir = await mkdtemp(join(tmpdir(), "forge-keys-cloud-"));
27 app = createApp({ dataDir: dir, port: 0 });
28 servers = await serve(app);
29 const cookie = await adminCookie(app, { username: "alice", email: "[email protected]", password: "correct-horse-battery" });
30 listCloudAccounts(app.db); // creates the table
31 app.db.query("INSERT INTO cloud_account (provider, name, summary, verified_at, write_allowed) VALUES ('cloudflare', 'main', 'ok', NULL, 0)").run();
32 const res = await fetch(`${servers.url}/settings/cloud`, { headers: { cookie } });
33 html = mainOf(await res.text());
34 });
35 afterAll(async () => {
36 servers.stop();
37 app.close();
38 await rm(dir, { recursive: true, force: true });
39 });
40
41 test("the page draws the account's forms; the sections are the only rows", () => {
42 expect(html).toContain('action="/settings/cloud/verify"');
43 const accounts = html.slice(html.indexOf('class="list setting-list"'));
44 expect(accounts).not.toContain("data-nav");
45 expect(html).toContain("data-nav");
46 });
47
48 test("j/k walk the sections from the current one, Enter opens, Esc leaves nothing behind, fields keep their keys", async () => {
49 const p = await shellPage("/settings/cloud", html + "<input id=f>");
50 const rows = [...p.doc.querySelectorAll("[data-nav]")] as any[];
51 const at = rows.findIndex((r) => r.getAttribute("aria-current") === "page");
52 expect(at).toBeGreaterThanOrEqual(0);
53 expect(rows[at].getAttribute("href")).toBe("/settings/cloud");
54
55 p.key("j");
56 expect(p.doc.activeElement).toBe(rows[Math.min(at + 1, rows.length - 1)]);
57 const target = p.doc.activeElement.getAttribute("href");
58 p.key("k");
59 expect(p.doc.activeElement).toBe(rows[Math.max(at, 0)]);
60 p.key("j");
61 p.key("Enter");
62 expect(p.clicks).toEqual([target]);
63 expect(JSON.parse(p.win.sessionStorage.getItem("nav-from")!)).toMatchObject({ list: "/settings/cloud", href: target });
64
65 const f = p.doc.getElementById("f") as any;
66 f.focus();
67 const before = p.clicks.length;
68 p.key("j", f);
69 p.key("Enter", f);
70 expect(p.doc.activeElement).toBe(f);
71 expect(p.clicks.length).toBe(before);
72
73 const same = await shellPage("/settings/cloud", html, { "nav-from": JSON.stringify({ list: "/settings/cloud", to: "/settings/cloud", href: target }) });
74 same.key("Escape");
75 expect(same.assigned).toEqual([]);
76 });
77
78 test("`?` opens the help from this page", async () => {
79 const p = await shellPage("/settings/cloud", html);
80 expect(p.key("?").defaultPrevented).toBe(true);
81 });

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs