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

test/snapshot-destination.test.ts passes: a failed test-connection is one sentence and the backups page shows a snapshot in progress without a refresh #11065

Merged opened this

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

Merged

scout/forge:scout/11050-test-snapshot-destination-test-ts-passes → main 2 commits fork 1 thread · 1 unresolved

  • Merged. scout/11050-test-snapshot-destination-test-ts-passes was merged into main as 86b1dff.

Review

Sign in to review this change.
3 files changed +13 −4
src/snapshot/destination.ts +2 −1
@@ -98,7 +98,8 @@ export function scrubReason(target: S3Target | undefined, error: unknown): strin
9898 let reason = error instanceof Error ? error.message : String(error);
9999 for (const secret of target ? [target.accessKeyId, target.secretAccessKey] : [])
100100 if (secret) reason = reason.split(secret).join("…");
101 return reason.slice(0, 200);
101 // One line: a store's message may end in a newline or carry an empty name between spaces.
102 return reason.replace(/\s+/g, " ").trim().slice(0, 200);
102103 }
103104
104105 /** Does this target answer? One sentence either way, never a key in it. */
src/web/pages/backups.ts +1 −1
@@ -346,7 +346,7 @@ async function movingPart(
346346 ${when(
347347 svc.progress(),
348348 (p) =>
349 html`<p class="break">
349 html`<p class="break" role="status" aria-live="polite">

Next step, not blocking: render the role=status wrapper always and put the sentence inside when running, so screen readers announce the change.

350350 ${badge("Running", { icon: "clock", variant: "secondary" })} A snapshot is being taken: ${p.objects} objects,
351351 ${fileSize(p.bytes)} so far, ${Math.round(p.elapsedMs / 1000)} s
352352 in.
test/snapshot-destination.test.ts +10 −2
@@ -133,6 +133,8 @@ describe("the snapshot destination", () => {
133133 const sentence = said.ok ? said.value : "";
134134 expect(sentence).toStartWith("Could not list 127.0.0.1:1/my-bucket: ");
135135 expect(sentence).not.toContain("\n");
136 expect(sentence).not.toContain(" ");
137 expect(sentence).toBe(sentence.trim());
136138 expect(sentence).not.toContain(input.secretKey);
137139 expect(sentence).not.toContain(input.accessKey);
138140 });
@@ -166,12 +168,18 @@ describe("the snapshot destination", () => {
166168 expect(await page()).not.toContain("http-equiv=\"refresh\"");
167169 const taking = svc.now();
168170 let html = "";
169 for (let i = 0; i < 100 && !html.includes("A snapshot is being taken"); i++) {
171 // Until an object has landed: the first poll can come before any has.
172 for (let i = 0; i < 100 && !/A snapshot is being taken: [1-9]\d* objects/.test(html); i++) {
170173 await Bun.sleep(50);
171174 html = await page();
172175 }
173176 expect(html).toContain("A snapshot is being taken");
174 expect(html).toContain("http-equiv=\"refresh\"");
177 const words = html.indexOf("A snapshot is being taken");
178 const paragraph = html.slice(html.lastIndexOf("<p", words), words);
179 expect(paragraph).toContain('role="status"');
180 expect(paragraph).toContain('aria-live="polite"');
181 expect(html).toContain('data-live-src="/settings/backups/live"');
182 expect(html).not.toContain("http-equiv=\"refresh\"");
175183 expect(html).toMatch(/[1-9]\d* objects/);
176184 await taking;
177185 expect(await page()).not.toContain("A snapshot is being taken");

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs