Skip to content

Commit bf2f2a2

Browse files
committed
Client: E2E tests login - register
Added Shai hulud detector to cicd
1 parent 4862d60 commit bf2f2a2

7 files changed

Lines changed: 263 additions & 168 deletions

File tree

.github/workflows/auto-test-deploy.yml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,28 @@ on:
66
- "auto-testing-deploy"
77

88
jobs:
9+
10+
shai-hulud-detector:
11+
runs-on: ubuntu-latest
12+
steps:
13+
- name: Checkout seb-server-gui repo
14+
uses: actions/checkout@v6
15+
with:
16+
path: seb
17+
clean: false
18+
- name: Checkout Cobenian/shai-hulud-detect
19+
uses: actions/checkout@v6
20+
with:
21+
repository: Cobenian/shai-hulud-detect
22+
path: hulud
23+
clean: false
24+
- # Pipeline will automatically fail on exit codes 1 or 2
25+
name: Security Scan with Shai-Hulud Detector
26+
run: |
27+
chmod +x ./hulud/shai-hulud-detector.sh
28+
./hulud/shai-hulud-detector.sh ./seb
29+
30+
931
build-and-push-admin-auto-test:
1032
runs-on: ubuntu-latest
1133
strategy:
@@ -72,3 +94,5 @@ jobs:
7294
file: ./Dockerfile.storybook
7395
push: true
7496
tags: docker.io/${{ secrets.DOCKERHUB_ADMIN_USERNAME }}/storybook:${{ env.TAG_NAME }}
97+
98+
# Add tests deployed to separate image (simple node image and pasted e2e tests in there should do the trick)

client/package-lock.json

Lines changed: 5 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

client/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@
7272
"@testing-library/dom": "^10.4.1",
7373
"@testing-library/vue": "^8.1.0",
7474
"@types/luxon": "^3.4.2",
75-
"@types/node": "^20.19.24",
75+
"@types/node": "^20.19.27",
7676
"@types/webfontloader": "^1.6.38",
7777
"@vitejs/plugin-vue": "^5.2.4",
7878
"@vitest/browser-playwright": "^4.0.8",

client/playwright.config.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,7 @@ export default defineConfig({
99
reporter: process.env.CI ? "line" : "html",
1010
use: {
1111
baseURL: process.env.BASE_URL || "http://localhost:8082",
12-
trace: "on-first-retry",
13-
launchOptions: {
14-
slowMo: 500,
15-
},
12+
trace: "on",
1613
contextOptions: {
1714
javaScriptEnabled: true,
1815
},
Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
import { test, expect, Page, Locator } from "@playwright/test";
2+
3+
// create an unique username based on current datetime -> So that there is absolutely no way this test fails because of a duplicate username
4+
// todo, maybe extreact into a separate method to add current date time to whatever variable
5+
function uniqueUsername(prefix = "e2e") {
6+
const d = new Date();
7+
const pad = (n: number) => String(n).padStart(2, "0");
8+
const ts = [
9+
d.getUTCFullYear(),
10+
pad(d.getUTCMonth() + 1),
11+
pad(d.getUTCDate()),
12+
"-",
13+
pad(d.getUTCHours()),
14+
pad(d.getUTCMinutes()),
15+
pad(d.getUTCSeconds()),
16+
"-",
17+
d.getUTCMilliseconds(),
18+
].join("");
19+
return `${prefix}-${ts}`;
20+
}
21+
22+
// Setup Method for page
23+
async function setupRegisterPage(page: Page) {
24+
await page.addInitScript(() => {
25+
localStorage.clear();
26+
sessionStorage.clear();
27+
});
28+
29+
await page.goto("/register");
30+
await expect(page.getByTestId("register-page-container")).toBeVisible();
31+
32+
const institutionSelect = page.getByTestId("register-institution-select");
33+
const username = page
34+
.getByTestId("register-username-input")
35+
.getByRole("textbox");
36+
const name = page.getByTestId("register-name-input").getByRole("textbox");
37+
const surname = page
38+
.getByTestId("register-surname-input")
39+
.getByRole("textbox");
40+
const email = page.getByTestId("register-email-input").getByRole("textbox");
41+
const timezoneSelect = page.getByTestId("register-timezone-select");
42+
const password = page
43+
.getByTestId("register-password-input")
44+
.getByRole("textbox");
45+
const confirmPassword = page
46+
.getByTestId("register-confirmPassword-input")
47+
.getByRole("textbox");
48+
49+
const submitButton = page.getByTestId("register-submit-btn");
50+
const successAlert = page.getByTestId("register-success-alert");
51+
const errorAlert = page.getByTestId("register-error-alert");
52+
53+
return {
54+
institutionSelect,
55+
username,
56+
name,
57+
surname,
58+
email,
59+
timezoneSelect,
60+
password,
61+
confirmPassword,
62+
submitButton,
63+
successAlert,
64+
errorAlert,
65+
};
66+
}
67+
68+
// select option by text from selector (for institution)
69+
async function selectVuetifyOptionByName(
70+
page: Page,
71+
selectRoot: Locator,
72+
optionName: string,
73+
) {
74+
const input = selectRoot.locator(".v-field__input").first();
75+
await input.click();
76+
77+
const option = page.getByRole("option", { name: optionName });
78+
await option.click();
79+
80+
await page.keyboard.press("Escape").catch(() => {});
81+
}
82+
83+
// select first option from selector (for timezone)
84+
// todo Consider exporting to utils file
85+
async function selectVuetifyFirstOption(page: Page, selectRoot: Locator) {
86+
const input = selectRoot.locator(".v-field__input").first();
87+
await input.click();
88+
89+
await expect(page.getByRole("option").first()).toBeVisible({
90+
timeout: 10000,
91+
});
92+
93+
await page.keyboard.press("ArrowDown");
94+
await page.keyboard.press("Enter");
95+
await page.keyboard.press("Escape").catch(() => {});
96+
}
97+
98+
//tests
99+
test.describe("1.1.2 User Accounts - CREATE Register", () => {
100+
test("A Success", async ({ page }) => {
101+
const {
102+
institutionSelect,
103+
username,
104+
name,
105+
surname,
106+
email,
107+
timezoneSelect,
108+
password,
109+
confirmPassword,
110+
submitButton,
111+
successAlert,
112+
} = await setupRegisterPage(page);
113+
114+
const uname = uniqueUsername("e2e-user");
115+
116+
await selectVuetifyOptionByName(page, institutionSelect, "ETH Zürich");
117+
118+
await username.fill(uname);
119+
await name.fill("Andrei");
120+
await surname.fill("Mititelu");
121+
await email.fill(`${uname}@example.com`);
122+
123+
await selectVuetifyFirstOption(page, timezoneSelect);
124+
await password.fill("StrongPass123!");
125+
await confirmPassword.fill("StrongPass123!");
126+
127+
await submitButton.click();
128+
129+
await successAlert.waitFor({ state: "attached", timeout: 10000 });
130+
await expect(successAlert).toBeVisible();
131+
await expect(page.getByTestId("register-error-alert")).toHaveCount(0);
132+
});
133+
134+
test("B Failed validation (client-side form validation)", async ({
135+
page,
136+
}) => {
137+
const {
138+
username,
139+
name,
140+
surname,
141+
email,
142+
password,
143+
confirmPassword,
144+
submitButton,
145+
} = await setupRegisterPage(page);
146+
147+
const uname = uniqueUsername("e2e-invalid");
148+
149+
await username.fill(uname);
150+
await name.fill("Test");
151+
await surname.fill("User");
152+
await email.fill(`${uname}@example.com`);
153+
154+
// too short (<8)
155+
await password.fill("Abc1");
156+
await confirmPassword.fill("Abc1");
157+
158+
await submitButton.click();
159+
160+
await expect(page.getByTestId("register-success-alert")).toHaveCount(0);
161+
await expect(page.getByTestId("register-error-alert")).toHaveCount(0);
162+
163+
const anyValidationMessage = page.locator(
164+
".v-messages .v-messages__message",
165+
);
166+
await expect(anyValidationMessage.first()).toBeVisible();
167+
});
168+
169+
test("C Server error on register (simulated)", async ({ page }) => {
170+
await page.route("**/useraccount/register", async (route) => {
171+
const req = route.request();
172+
if (req.method() !== "POST") return route.fallback();
173+
174+
return route.fulfill({
175+
status: 500,
176+
body: JSON.stringify({ message: "Internal Server Error" }),
177+
headers: { "Content-Type": "application/json" },
178+
});
179+
});
180+
181+
const {
182+
institutionSelect,
183+
username,
184+
name,
185+
surname,
186+
email,
187+
timezoneSelect,
188+
password,
189+
confirmPassword,
190+
submitButton,
191+
successAlert,
192+
errorAlert,
193+
} = await setupRegisterPage(page);
194+
195+
await selectVuetifyOptionByName(page, institutionSelect, "ETH Zürich");
196+
197+
const uname = `playwright-error-${Date.now()}`;
198+
await username.fill(uname);
199+
await name.fill("Server");
200+
await surname.fill("Error");
201+
await email.fill(`error+${Date.now()}@example.com`);
202+
203+
await selectVuetifyFirstOption(page, timezoneSelect);
204+
205+
await password.fill("ValidPass123!");
206+
await confirmPassword.fill("ValidPass123!");
207+
208+
await submitButton.click();
209+
210+
await expect(errorAlert).toBeVisible();
211+
await expect(successAlert).toHaveCount(0);
212+
213+
await expect(page).toHaveURL(/\/register(?:$|[?#])/i);
214+
});
215+
});

client/tests/e2e/1-user-account/2.1-read-login.spec.ts

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
import { test, expect, Page } from "@playwright/test";
22

3-
const USER = "playwright";
4-
const PASS = "playwright";
3+
//TODO change to whatever we chose to add in DB script via FLYWAY
4+
const correctUser = "playwright";
5+
const correctPass = "playwright";
6+
const wrongUser = "invalid@example.cdasdpef";
7+
const wrongPass = "wrong-passworddddddddddddddd";
58

9+
// Setup method for page (this, unlike register test, does NOT use test id's)
610
async function setupLoginPage(page: Page) {
711
await page.addInitScript(() => {
812
localStorage.clear();
@@ -17,12 +21,19 @@ async function setupLoginPage(page: Page) {
1721
return { username, password };
1822
}
1923

24+
//this triggers video recording for the worker
25+
test.use({
26+
video: {
27+
mode: "on",
28+
},
29+
});
30+
2031
test.describe("1.2.1 User Accounts - READ Log in", () => {
2132
test("A Successful login", async ({ page }) => {
2233
const { username, password } = await setupLoginPage(page);
2334

24-
await username.fill(USER);
25-
await password.fill(PASS);
35+
await username.fill(correctUser);
36+
await password.fill(correctPass);
2637
await page.keyboard.press("Enter");
2738

2839
await expect(page).toHaveURL(/\/home(?:$|[?#])/i, { timeout: 5000 });
@@ -31,8 +42,8 @@ test.describe("1.2.1 User Accounts - READ Log in", () => {
3142
test("B Failed login, bad credentials", async ({ page }) => {
3243
const { username, password } = await setupLoginPage(page);
3344

34-
await username.fill("invalid@example.com");
35-
await password.fill("wrong-password");
45+
await username.fill(wrongUser);
46+
await password.fill(wrongPass);
3647
await page.keyboard.press("Enter");
3748

3849
const alert = page.getByTestId("login-error-alert");

0 commit comments

Comments
 (0)