Skip to content
This repository was archived by the owner on Sep 11, 2024. It is now read-only.

Commit fbf72f6

Browse files
Migrate register.spec.ts from Cypress to Playwright (#11942)
* Install playwright Signed-off-by: Michael Telatynski <[email protected]> * Add foundations for writing tests under Playwright Signed-off-by: Michael Telatynski <[email protected]> * .gitignore juggling Signed-off-by: Michael Telatynski <[email protected]> * Add tsconfig and fix eslint rules Signed-off-by: Michael Telatynski <[email protected]> * Add docker & synapse plugins Signed-off-by: Michael Telatynski <[email protected]> * Add login.spec.ts Signed-off-by: Michael Telatynski <[email protected]> * Wire up fixture which sets up ElementAppPage & bakes config.json Signed-off-by: Michael Telatynski <[email protected]> * Remove launch test, it has served its purpose Signed-off-by: Michael Telatynski <[email protected]> * Remove test which has been ported to Playwright Signed-off-by: Michael Telatynski <[email protected]> * Fix test not cleaning up after itself Signed-off-by: Michael Telatynski <[email protected]> * Move registerUser to the Homeserver interface Signed-off-by: Michael Telatynski <[email protected]> * Remove unused fixture param Signed-off-by: Michael Telatynski <[email protected]> * Remove redundant launch test Signed-off-by: Michael Telatynski <[email protected]> * Add newline * Run both legacy & rust crypto tests in Playwright Signed-off-by: Michael Telatynski <[email protected]> * Remove redundant comment Signed-off-by: Michael Telatynski <[email protected]> * Create plugin for mail-hog * Move injectAxe into element-web-test.ts Signed-off-by: Michael Telatynski <[email protected]> * Switch out axe-playwright for @axe-core/playwright Signed-off-by: Michael Telatynski <[email protected]> * Migrate email.spec.ts from Cypress to Playwright Signed-off-by: Michael Telatynski <[email protected]> * prettier Signed-off-by: Michael Telatynski <[email protected]> * Use Playwright snapshot utility over Percy Signed-off-by: Michael Telatynski <[email protected]> * Remove commented our Percy badge as we're unlikely to want to go back Signed-off-by: Michael Telatynski <[email protected]> * Migrate user-onboarding-old.spec.ts Signed-off-by: Michael Telatynski <[email protected]> * Migrate user-onboarding-new.spec.ts Signed-off-by: Michael Telatynski <[email protected]> * Add screenshots Signed-off-by: Michael Telatynski <[email protected]> * Fix bad merge Signed-off-by: Michael Telatynski <[email protected]> * Fix test and re-enable Signed-off-by: Michael Telatynski <[email protected]> * Run linters on playwright Signed-off-by: Michael Telatynski <[email protected]> * Make typescript happier Signed-off-by: Michael Telatynski <[email protected]> * Fix types Signed-off-by: Michael Telatynski <[email protected]> * Update typescript Signed-off-by: Michael Telatynski <[email protected]> * Migrate register.spec.ts from Cypress to Playwright Signed-off-by: Michael Telatynski <[email protected]> * Add screenshots Signed-off-by: Michael Telatynski <[email protected]> * Update screenshots Signed-off-by: Michael Telatynski <[email protected]> * Update import Signed-off-by: Michael Telatynski <[email protected]> --------- Signed-off-by: Michael Telatynski <[email protected]> Co-authored-by: R Midhun Suresh <[email protected]>
1 parent beaffdb commit fbf72f6

File tree

10 files changed

+192
-158
lines changed

10 files changed

+192
-158
lines changed

cypress/e2e/register/register.spec.ts

Lines changed: 0 additions & 152 deletions
This file was deleted.

playwright.config.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,11 @@ export default defineConfig<TestOptions>({
3939
projects: [
4040
{
4141
name: "Legacy Crypto",
42-
use: { crypto: "legacy" },
42+
use: { cryptoBackend: "legacy" },
4343
},
4444
{
4545
name: "Rust Crypto",
46-
use: { crypto: "rust" },
46+
use: { cryptoBackend: "rust" },
4747
},
4848
],
4949
snapshotDir: "playwright/snapshots",
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
/*
2+
Copyright 2022 The Matrix.org Foundation C.I.C.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
import { test, expect } from "../../element-web-test";
18+
19+
test.describe("Registration", () => {
20+
test.use({ startHomeserverOpts: "consent" });
21+
22+
test.beforeEach(async ({ page }) => {
23+
await page.goto("/#/register");
24+
});
25+
26+
test("registers an account and lands on the home screen", async ({ homeserver, page, checkA11y, crypto }) => {
27+
await page.getByRole("button", { name: "Edit", exact: true }).click();
28+
await expect(page.getByRole("button", { name: "Continue", exact: true })).toBeVisible();
29+
30+
await expect(page.locator(".mx_Dialog")).toHaveScreenshot("server-picker.png");
31+
await checkA11y();
32+
33+
await page.getByRole("textbox", { name: "Other homeserver" }).fill(homeserver.config.baseUrl);
34+
await page.getByRole("button", { name: "Continue", exact: true }).click();
35+
// wait for the dialog to go away
36+
await expect(page.getByRole("dialog")).not.toBeVisible();
37+
38+
await expect(page.getByRole("textbox", { name: "Username", exact: true })).toBeVisible();
39+
// Hide the server text as it contains the randomly allocated Homeserver port
40+
const screenshotOptions = { mask: [page.locator(".mx_ServerPicker_server")] };
41+
await expect(page).toHaveScreenshot("registration.png", screenshotOptions);
42+
await checkA11y();
43+
44+
await page.getByRole("textbox", { name: "Username", exact: true }).fill("alice");
45+
await page.getByPlaceholder("Password", { exact: true }).fill("totally a great password");
46+
await page.getByPlaceholder("Confirm password", { exact: true }).fill("totally a great password");
47+
await page.getByRole("button", { name: "Register", exact: true }).click();
48+
49+
const dialog = page.getByRole("dialog");
50+
await expect(dialog).toBeVisible();
51+
await expect(page).toHaveScreenshot("email-prompt.png", screenshotOptions);
52+
await checkA11y();
53+
await dialog.getByRole("button", { name: "Continue", exact: true }).click();
54+
55+
await expect(page.locator(".mx_InteractiveAuthEntryComponents_termsPolicy")).toBeVisible();
56+
await expect(page).toHaveScreenshot("terms-prompt.png", screenshotOptions);
57+
await checkA11y();
58+
59+
const termsPolicy = page.locator(".mx_InteractiveAuthEntryComponents_termsPolicy");
60+
await termsPolicy.getByRole("checkbox").click(); // Click the checkbox before terms of service anchor link
61+
await expect(termsPolicy.getByLabel("Privacy Policy")).toBeVisible();
62+
63+
await page.getByRole("button", { name: "Accept", exact: true }).click();
64+
65+
await expect(page.locator(".mx_UseCaseSelection_skip")).toBeVisible();
66+
await expect(page).toHaveScreenshot("use-case-selection.png", screenshotOptions);
67+
await checkA11y();
68+
await page.getByRole("button", { name: "Skip", exact: true }).click();
69+
70+
await expect(page).toHaveURL(/\/#\/home$/);
71+
72+
/*
73+
* Cross-signing checks
74+
*/
75+
// check that the device considers itself verified
76+
await page.getByRole("button", { name: "User menu", exact: true }).click();
77+
await page.getByRole("menuitem", { name: "All settings", exact: true }).click();
78+
await page.getByRole("tab", { name: "Sessions", exact: true }).click();
79+
await expect(page.getByTestId("current-session-section").getByTestId("device-metadata-isVerified")).toHaveText(
80+
"Verified",
81+
);
82+
83+
// check that cross-signing keys have been uploaded.
84+
await crypto.assertDeviceIsCrossSigned();
85+
});
86+
87+
test("should require username to fulfil requirements and be available", async ({ homeserver, page }) => {
88+
await page.getByRole("button", { name: "Edit", exact: true }).click();
89+
await expect(page.getByRole("button", { name: "Continue", exact: true })).toBeVisible();
90+
await page.getByRole("textbox", { name: "Other homeserver" }).fill(homeserver.config.baseUrl);
91+
await page.getByRole("button", { name: "Continue", exact: true }).click();
92+
// wait for the dialog to go away
93+
await expect(page.getByRole("dialog")).not.toBeVisible();
94+
95+
await expect(page.getByRole("textbox", { name: "Username", exact: true })).toBeVisible();
96+
97+
await page.route("**/_matrix/client/*/register/available?username=_alice", async (route) => {
98+
await route.fulfill({
99+
status: 400,
100+
json: {
101+
errcode: "M_INVALID_USERNAME",
102+
error: "User ID may not begin with _",
103+
},
104+
});
105+
});
106+
await page.getByRole("textbox", { name: "Username", exact: true }).fill("_alice");
107+
await expect(page.getByRole("alert").filter({ hasText: "Some characters not allowed" })).toBeVisible();
108+
109+
await page.route("**/_matrix/client/*/register/available?username=bob", async (route) => {
110+
await route.fulfill({
111+
status: 400,
112+
json: {
113+
errcode: "M_USER_IN_USE",
114+
error: "The desired username is already taken",
115+
},
116+
});
117+
});
118+
await page.getByRole("textbox", { name: "Username", exact: true }).fill("bob");
119+
await expect(page.getByRole("alert").filter({ hasText: "Someone already has that username" })).toBeVisible();
120+
121+
await page.getByRole("textbox", { name: "Username", exact: true }).fill("foobar");
122+
await expect(page.getByRole("alert")).not.toBeVisible();
123+
});
124+
});

playwright/element-web-test.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import { Dendrite, Pinecone } from "./plugins/homeserver/dendrite";
2626
import { Instance } from "./plugins/mailhog";
2727
import { ElementAppPage } from "./pages/ElementAppPage";
2828
import { OAuthServer } from "./plugins/oauth_server";
29+
import { Crypto } from "./pages/crypto";
2930
import { Toasts } from "./pages/toasts";
3031

3132
const CONFIG_JSON: Partial<IConfigOptions> = {
@@ -45,7 +46,7 @@ const CONFIG_JSON: Partial<IConfigOptions> = {
4546
};
4647

4748
export type TestOptions = {
48-
crypto: "legacy" | "rust";
49+
cryptoBackend: "legacy" | "rust";
4950
};
5051

5152
export const test = base.extend<
@@ -62,15 +63,16 @@ export const test = base.extend<
6263
displayName?: string;
6364
app: ElementAppPage;
6465
mailhog?: { api: mailhog.API; instance: Instance };
66+
crypto: Crypto;
6567
toasts: Toasts;
6668
}
6769
>({
68-
crypto: ["legacy", { option: true }],
70+
cryptoBackend: ["legacy", { option: true }],
6971
config: CONFIG_JSON,
70-
page: async ({ context, page, config, crypto }, use) => {
72+
page: async ({ context, page, config, cryptoBackend }, use) => {
7173
await context.route(`http://localhost:8080/config.json*`, async (route) => {
7274
const json = { ...CONFIG_JSON, ...config };
73-
if (crypto === "rust") {
75+
if (cryptoBackend === "rust") {
7476
json["features"] = {
7577
...json["features"],
7678
feature_rust_crypto: true,
@@ -163,6 +165,9 @@ export const test = base.extend<
163165
app: async ({ page }, use) => {
164166
await use(new ElementAppPage(page));
165167
},
168+
crypto: async ({ page, homeserver, request }, use) => {
169+
await use(new Crypto(page, homeserver, request));
170+
},
166171
toasts: async ({ page }, use) => {
167172
await use(new Toasts(page));
168173
},

playwright/pages/crypto.ts

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
Copyright 2023 The Matrix.org Foundation C.I.C.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
import { APIRequestContext, Page, expect } from "@playwright/test";
18+
19+
import { HomeserverInstance } from "../plugins/homeserver";
20+
21+
export class Crypto {
22+
public constructor(
23+
private page: Page,
24+
private homeserver: HomeserverInstance,
25+
private request: APIRequestContext,
26+
) {}
27+
28+
/**
29+
* Check that the user has published cross-signing keys, and that the user's device has been cross-signed.
30+
*/
31+
public async assertDeviceIsCrossSigned(): Promise<void> {
32+
const { userId, deviceId, accessToken } = await this.page.evaluate(() => ({
33+
userId: window.mxMatrixClientPeg.get().getUserId(),
34+
deviceId: window.mxMatrixClientPeg.get().getDeviceId(),
35+
accessToken: window.mxMatrixClientPeg.get().getAccessToken(),
36+
}));
37+
38+
const res = await this.request.post(`${this.homeserver.config.baseUrl}/_matrix/client/v3/keys/query`, {
39+
headers: { Authorization: `Bearer ${accessToken}` },
40+
data: { device_keys: { [userId]: [] } },
41+
});
42+
const json = await res.json();
43+
44+
// there should be three cross-signing keys
45+
expect(json.master_keys[userId]).toHaveProperty("keys");
46+
expect(json.self_signing_keys[userId]).toHaveProperty("keys");
47+
expect(json.user_signing_keys[userId]).toHaveProperty("keys");
48+
49+
// and the device should be signed by the self-signing key
50+
const selfSigningKeyId = Object.keys(json.self_signing_keys[userId].keys)[0];
51+
52+
expect(json.device_keys[userId][deviceId]).toBeDefined();
53+
54+
const myDeviceSignatures = json.device_keys[userId][deviceId].signatures[userId];
55+
expect(myDeviceSignatures[selfSigningKeyId]).toBeDefined();
56+
}
57+
}
1.07 MB
Loading
1.15 MB
Loading
25.4 KB
Loading
1.21 MB
Loading
563 KB
Loading

0 commit comments

Comments
 (0)