Skip to content

Commit 0b06b58

Browse files
committed
Select using aria-label for auth utilities
1 parent 9f2012b commit 0b06b58

File tree

2 files changed

+106
-29
lines changed

2 files changed

+106
-29
lines changed

typescript/packages/jumble/integration/basic-flow.test.ts

Lines changed: 43 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,22 @@ import {
1010
} from "@std/testing/bdd";
1111
import {
1212
addCharm,
13+
assertAndSnapshot,
1314
inspectCharm,
1415
login,
1516
sleep,
1617
waitForSelectorWithText,
1718
} from "./utils.ts";
19+
import { join } from "@std/path";
1820

1921
const TOOLSHED_API_URL = Deno.env.get("TOOLSHED_API_URL") ??
2022
"http://localhost:8000/";
2123
const FRONTEND_URL = Deno.env.get("FRONTEND_URL") ?? "http://localhost:5173/";
2224
const HEADLESS = true;
25+
const RECORD_SNAPSHOTS = false;
2326

27+
const SNAPSHOTS_DIR = join(Deno.cwd(), "test_snapshots");
28+
console.log("SNAPSHOTS_DIR=", SNAPSHOTS_DIR);
2429
console.log(`TOOLSHED_API_URL=${TOOLSHED_API_URL}`);
2530
console.log(`FRONTEND_URL=${FRONTEND_URL}`);
2631

@@ -48,57 +53,81 @@ describe("integration", () => {
4853
});
4954

5055
it("renders a new charm", async () => {
51-
assert(page);
52-
assert(testCharm);
53-
const anchor = await page.waitForSelector("nav a");
54-
assert(
55-
(await anchor.innerText()) === "common-knowledge",
56+
assertAndSnapshot(page, "Page should be defined");
57+
assertAndSnapshot(testCharm, "Test charm should be defined");
58+
59+
const anchor = await page!.waitForSelector("nav a");
60+
const innerText = await anchor.innerText();
61+
assertAndSnapshot(
62+
innerText === "common-knowledge",
5663
"Logged in and Common Knowledge title renders",
64+
page,
65+
"logged_in_state",
5766
);
5867

59-
await page.goto(`${FRONTEND_URL}${testCharm.space}/${testCharm.charmId}`);
68+
await page!.goto(
69+
`${FRONTEND_URL}${testCharm!.space}/${testCharm!.charmId}`,
70+
);
6071
console.log(`Waiting for charm to render`);
6172

6273
await waitForSelectorWithText(
63-
page,
74+
page!,
6475
"a[aria-current='charm-title']",
6576
"Simple Value: 1",
6677
);
6778
console.log("Charm rendered.");
79+
await assertAndSnapshot(
80+
true,
81+
"Charm rendered successfully",
82+
page,
83+
"charm_rendered",
84+
);
6885

6986
console.log("Clicking button");
7087
// Sometimes clicking this button throws:
7188
// https://jsr.io/@astral/astral/0.5.2/src/element_handle.ts#L192
7289
// As if the reference was invalidated by a spurious re-render between
7390
// getting an element handle, and clicking it.
7491
await sleep(1000);
75-
const button = await page.waitForSelector(
92+
const button = await page!.waitForSelector(
7693
"div[aria-label='charm-content'] button",
7794
);
7895
await button.click();
96+
await assertAndSnapshot(true, "Button clicked", page, "button_clicked");
7997

8098
console.log("Checking if title changed");
8199
await waitForSelectorWithText(
82-
page,
100+
page!,
83101
"a[aria-current='charm-title']",
84102
"Simple Value: 2",
85103
);
86104
console.log("Title changed");
105+
await assertAndSnapshot(
106+
true,
107+
"Title changed successfully",
108+
page,
109+
"title_changed",
110+
);
87111

88112
console.log("Inspecting charm to verify updates propagated from browser.");
89113
const charm = await inspectCharm(
90114
TOOLSHED_API_URL,
91-
testCharm.space,
92-
testCharm.charmId,
115+
testCharm!.space,
116+
testCharm!.charmId,
93117
);
94118
console.log("Charm:", charm);
95-
assert(charm.includes("Simple Value: 2"), "Charm updates propagated.");
119+
assertAndSnapshot(
120+
charm.includes("Simple Value: 2"),
121+
"Charm updates propagated.",
122+
page,
123+
"updates_propagated",
124+
);
96125
});
97126

98127
// Placeholder test ensuring browser can be used
99128
// across multiple tests (replace when we have more integration tests!)
100129
it("[placeholder]", () => {
101-
assert(page);
102-
assert(testCharm);
130+
assertAndSnapshot(page, "Page should be defined");
131+
assertAndSnapshot(testCharm, "Test charm should be defined");
103132
});
104133
});

typescript/packages/jumble/integration/utils.ts

Lines changed: 63 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
import { ElementHandle, Page } from "@astral/astral";
22
import * as path from "@std/path";
3+
import { assert } from "@std/assert";
4+
import { ensureDirSync } from "@std/fs";
5+
import { join } from "@std/path";
36

47
const COMMON_CLI_PATH = path.join(import.meta.dirname!, "../../common-cli");
58

@@ -8,9 +11,56 @@ export const decode = (() => {
811
return (buffer: Uint8Array): string => decoder.decode(buffer);
912
})();
1013

14+
const RECORD_SNAPSHOTS = true;
15+
const SNAPSHOTS_DIR = join(Deno.cwd(), "test_snapshots");
16+
console.log("SNAPSHOTS_DIR=", SNAPSHOTS_DIR);
17+
18+
// Helper function to assert, take screenshot and snapshot HTML
19+
export async function assertAndSnapshot(
20+
condition: unknown,
21+
message: string,
22+
page?: Page | void,
23+
snapshotName?: string,
24+
): Promise<void> {
25+
if (!condition) {
26+
throw new Error(message);
27+
}
28+
assert(condition, message);
29+
30+
if (RECORD_SNAPSHOTS && page && snapshotName) {
31+
ensureDirSync(SNAPSHOTS_DIR);
32+
const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
33+
const filePrefix = `${snapshotName}_${timestamp}`;
34+
35+
// Take screenshot
36+
const screenshot = await page.screenshot();
37+
Deno.writeFileSync(`${SNAPSHOTS_DIR}/${filePrefix}.png`, screenshot);
38+
39+
// Snapshot HTML
40+
const html = await page.content();
41+
Deno.writeTextFileSync(`${SNAPSHOTS_DIR}/${filePrefix}.html`, html);
42+
43+
console.log(`Snapshot saved: ${filePrefix}`);
44+
}
45+
}
46+
1147
export const sleep = (ms: number) =>
1248
new Promise((resolve) => setTimeout(resolve, ms));
1349

50+
export async function tryClick(
51+
el?: ElementHandle | null,
52+
page?: Page,
53+
): Promise<void> {
54+
await assertAndSnapshot(
55+
el !== null && el !== undefined,
56+
"Element does not exist or is not clickable",
57+
page,
58+
"try_click_element",
59+
);
60+
61+
await el!.click();
62+
}
63+
1464
export const login = async (page: Page) => {
1565
// Wait a second :(
1666
// See if #user-avatar is rendered
@@ -24,44 +74,42 @@ export const login = async (page: Page) => {
2474

2575
// If not logged in, see if any credential data is
2676
// persisting. If so, destroy local data.
27-
let buttons = await page.$$("button");
28-
for (const button of buttons) {
29-
if ((await button.innerText()) === "Clear Saved Credentials") {
30-
await button.click();
31-
}
77+
let button = await page.$("button[aria-label='clear-credentials']");
78+
if (button) {
79+
await tryClick(button, page);
3280
}
3381

3482
// Try log in
3583
console.log("Logging in");
3684

3785
// Click the first button, "register"
38-
let button = await page.$("button");
39-
await button!.click();
86+
button = await page.$("button[aria-label='register']");
87+
await tryClick(button, page);
4088

4189
// Click the first button, "register with passphrase"
42-
button = await page.$("button");
43-
await button!.click();
90+
button = await page.$("button[aria-label='register-with-passphrase']");
91+
await tryClick(button, page);
4492

4593
// Get the mnemonic from textarea.
46-
let input = await page.$("textarea");
94+
let input = await page.$("textarea[aria-label='mnemonic']");
4795
const mnemonic = await input!.evaluate((textarea: HTMLInputElement) =>
4896
textarea.value
4997
);
5098

5199
// Click the SECOND button, "continue to login"
52-
buttons = await page.$$("button");
53-
await buttons[1]!.click();
100+
button = await page.$("button[aria-label='continue-login']");
101+
await tryClick(button, page);
54102

55103
// Paste the mnemonic in the input.
56-
input = await page.$("input");
104+
input = await page.$("input[aria-label='enter-passphrase']");
57105
await input!.evaluate(
58106
(input: HTMLInputElement, mnemonic: string) => input.value = mnemonic,
59107
{ args: [mnemonic] },
60108
);
61109

62110
// Click the only button, "login"
63-
button = await page.$("button");
64-
await button!.click();
111+
button = await page.$("button[aria-label='login']");
112+
await tryClick(button, page);
65113
};
66114

67115
export const waitForSelectorWithText = async (

0 commit comments

Comments
 (0)