Skip to content

Commit 43fac49

Browse files
✅ Add items and admin tests, and refactor existing ones (#2146)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
1 parent 64eac12 commit 43fac49

File tree

6 files changed

+403
-94
lines changed

6 files changed

+403
-94
lines changed

frontend/tests/admin.spec.ts

Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
import { expect, test } from "@playwright/test"
2+
import { firstSuperuser, firstSuperuserPassword } from "./config.ts"
3+
import { createUser } from "./utils/privateApi"
4+
import { randomEmail, randomPassword } from "./utils/random"
5+
import { logInUser } from "./utils/user"
6+
7+
test("Admin page is accessible and shows correct title", async ({ page }) => {
8+
await page.goto("/admin")
9+
await expect(page.getByRole("heading", { name: "Users" })).toBeVisible()
10+
await expect(
11+
page.getByText("Manage user accounts and permissions"),
12+
).toBeVisible()
13+
})
14+
15+
test("Add User button is visible", async ({ page }) => {
16+
await page.goto("/admin")
17+
await expect(page.getByRole("button", { name: "Add User" })).toBeVisible()
18+
})
19+
20+
test.describe("Admin user management", () => {
21+
test("Create a new user successfully", async ({ page }) => {
22+
await page.goto("/admin")
23+
24+
const email = randomEmail()
25+
const password = randomPassword()
26+
const fullName = "Test User Admin"
27+
28+
await page.getByRole("button", { name: "Add User" }).click()
29+
30+
await page.getByPlaceholder("Email").fill(email)
31+
await page.getByPlaceholder("Full name").fill(fullName)
32+
await page.getByPlaceholder("Password").first().fill(password)
33+
await page.getByPlaceholder("Password").last().fill(password)
34+
35+
await page.getByRole("button", { name: "Save" }).click()
36+
37+
await expect(page.getByText("User created successfully")).toBeVisible()
38+
39+
await expect(page.getByRole("dialog")).not.toBeVisible()
40+
41+
const userRow = page.getByRole("row").filter({ hasText: email })
42+
await expect(userRow).toBeVisible()
43+
})
44+
45+
test("Create a superuser", async ({ page }) => {
46+
await page.goto("/admin")
47+
48+
const email = randomEmail()
49+
const password = randomPassword()
50+
51+
await page.getByRole("button", { name: "Add User" }).click()
52+
53+
await page.getByPlaceholder("Email").fill(email)
54+
await page.getByPlaceholder("Password").first().fill(password)
55+
await page.getByPlaceholder("Password").last().fill(password)
56+
await page.getByLabel("Is superuser?").check()
57+
await page.getByLabel("Is active?").check()
58+
59+
await page.getByRole("button", { name: "Save" }).click()
60+
61+
await expect(page.getByText("User created successfully")).toBeVisible()
62+
63+
await expect(page.getByRole("dialog")).not.toBeVisible()
64+
65+
const userRow = page.getByRole("row").filter({ hasText: email })
66+
await expect(userRow.getByText("Superuser")).toBeVisible()
67+
})
68+
69+
test("Edit a user successfully", async ({ page }) => {
70+
await page.goto("/admin")
71+
72+
const email = randomEmail()
73+
const password = randomPassword()
74+
const originalName = "Original Name"
75+
const updatedName = "Updated Name"
76+
77+
await page.getByRole("button", { name: "Add User" }).click()
78+
await page.getByPlaceholder("Email").fill(email)
79+
await page.getByPlaceholder("Full name").fill(originalName)
80+
await page.getByPlaceholder("Password").first().fill(password)
81+
await page.getByPlaceholder("Password").last().fill(password)
82+
await page.getByRole("button", { name: "Save" }).click()
83+
84+
await expect(page.getByText("User created successfully")).toBeVisible()
85+
await expect(page.getByRole("dialog")).not.toBeVisible()
86+
87+
const userRow = page.getByRole("row").filter({ hasText: email })
88+
await userRow.getByRole("button").click()
89+
90+
await page.getByRole("menuitem", { name: "Edit User" }).click()
91+
92+
await page.getByPlaceholder("Full name").fill(updatedName)
93+
await page.getByRole("button", { name: "Save" }).click()
94+
95+
await expect(page.getByText("User updated successfully")).toBeVisible()
96+
await expect(page.getByText(updatedName)).toBeVisible()
97+
})
98+
99+
test("Delete a user successfully", async ({ page }) => {
100+
await page.goto("/admin")
101+
102+
const email = randomEmail()
103+
const password = randomPassword()
104+
105+
await page.getByRole("button", { name: "Add User" }).click()
106+
await page.getByPlaceholder("Email").fill(email)
107+
await page.getByPlaceholder("Password").first().fill(password)
108+
await page.getByPlaceholder("Password").last().fill(password)
109+
await page.getByRole("button", { name: "Save" }).click()
110+
111+
await expect(page.getByText("User created successfully")).toBeVisible()
112+
113+
await expect(page.getByRole("dialog")).not.toBeVisible()
114+
115+
const userRow = page.getByRole("row").filter({ hasText: email })
116+
await userRow.getByRole("button").click()
117+
118+
await page.getByRole("menuitem", { name: "Delete User" }).click()
119+
120+
await page.getByRole("button", { name: "Delete" }).click()
121+
122+
await expect(
123+
page.getByText("The user was deleted successfully"),
124+
).toBeVisible()
125+
126+
await expect(
127+
page.getByRole("row").filter({ hasText: email }),
128+
).not.toBeVisible()
129+
})
130+
131+
test("Cancel user creation", async ({ page }) => {
132+
await page.goto("/admin")
133+
134+
await page.getByRole("button", { name: "Add User" }).click()
135+
await page.getByPlaceholder("Email").fill("test@example.com")
136+
137+
await page.getByRole("button", { name: "Cancel" }).click()
138+
139+
await expect(page.getByRole("dialog")).not.toBeVisible()
140+
})
141+
142+
test("Email is required and must be valid", async ({ page }) => {
143+
await page.goto("/admin")
144+
145+
await page.getByRole("button", { name: "Add User" }).click()
146+
147+
await page.getByPlaceholder("Email").fill("invalid-email")
148+
await page.getByPlaceholder("Email").blur()
149+
150+
await expect(page.getByText("Invalid email address")).toBeVisible()
151+
})
152+
153+
test("Password must be at least 8 characters", async ({ page }) => {
154+
await page.goto("/admin")
155+
156+
await page.getByRole("button", { name: "Add User" }).click()
157+
158+
await page.getByPlaceholder("Email").fill(randomEmail())
159+
await page.getByPlaceholder("Password").first().fill("short")
160+
await page.getByPlaceholder("Password").last().fill("short")
161+
await page.getByRole("button", { name: "Save" }).click()
162+
163+
await expect(
164+
page.getByText("Password must be at least 8 characters"),
165+
).toBeVisible()
166+
})
167+
168+
test("Passwords must match", async ({ page }) => {
169+
await page.goto("/admin")
170+
171+
await page.getByRole("button", { name: "Add User" }).click()
172+
173+
await page.getByPlaceholder("Email").fill(randomEmail())
174+
await page.getByPlaceholder("Password").first().fill(randomPassword())
175+
await page.getByPlaceholder("Password").last().fill("different12345")
176+
await page.getByPlaceholder("Password").last().blur()
177+
178+
await expect(page.getByText("The passwords don't match")).toBeVisible()
179+
})
180+
})
181+
182+
test.describe("Admin page access control", () => {
183+
test.use({ storageState: { cookies: [], origins: [] } })
184+
185+
test("Non-superuser cannot access admin page", async ({ page }) => {
186+
const email = randomEmail()
187+
const password = randomPassword()
188+
189+
await createUser({ email, password })
190+
await logInUser(page, email, password)
191+
192+
await page.goto("/admin")
193+
194+
await expect(page.getByRole("heading", { name: "Users" })).not.toBeVisible()
195+
await expect(page).not.toHaveURL(/\/admin/)
196+
})
197+
198+
test("Superuser can access admin page", async ({ page }) => {
199+
await logInUser(page, firstSuperuser, firstSuperuserPassword)
200+
201+
await page.goto("/admin")
202+
203+
await expect(page.getByRole("heading", { name: "Users" })).toBeVisible()
204+
})
205+
})

frontend/tests/items.spec.ts

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
import { expect, test } from "@playwright/test"
2+
import { createUser } from "./utils/privateApi"
3+
import {
4+
randomEmail,
5+
randomItemDescription,
6+
randomItemTitle,
7+
randomPassword,
8+
} from "./utils/random"
9+
import { logInUser } from "./utils/user"
10+
11+
test("Items page is accessible and shows correct title", async ({ page }) => {
12+
await page.goto("/items")
13+
await expect(page.getByRole("heading", { name: "Items" })).toBeVisible()
14+
await expect(page.getByText("Create and manage your items")).toBeVisible()
15+
})
16+
17+
test("Add Item button is visible", async ({ page }) => {
18+
await page.goto("/items")
19+
await expect(page.getByRole("button", { name: "Add Item" })).toBeVisible()
20+
})
21+
22+
test.describe("Items management", () => {
23+
test.use({ storageState: { cookies: [], origins: [] } })
24+
let email: string
25+
const password = randomPassword()
26+
27+
test.beforeAll(async () => {
28+
email = randomEmail()
29+
await createUser({ email, password })
30+
})
31+
32+
test.beforeEach(async ({ page }) => {
33+
await logInUser(page, email, password)
34+
await page.goto("/items")
35+
})
36+
37+
test("Create a new item successfully", async ({ page }) => {
38+
const title = randomItemTitle()
39+
const description = randomItemDescription()
40+
41+
await page.getByRole("button", { name: "Add Item" }).click()
42+
await page.getByLabel("Title").fill(title)
43+
await page.getByLabel("Description").fill(description)
44+
await page.getByRole("button", { name: "Save" }).click()
45+
46+
await expect(page.getByText("Item created successfully")).toBeVisible()
47+
await expect(page.getByText(title)).toBeVisible()
48+
})
49+
50+
test("Create item with only required fields", async ({ page }) => {
51+
const title = randomItemTitle()
52+
53+
await page.getByRole("button", { name: "Add Item" }).click()
54+
await page.getByLabel("Title").fill(title)
55+
await page.getByRole("button", { name: "Save" }).click()
56+
57+
await expect(page.getByText("Item created successfully")).toBeVisible()
58+
await expect(page.getByText(title)).toBeVisible()
59+
})
60+
61+
test("Cancel item creation", async ({ page }) => {
62+
await page.getByRole("button", { name: "Add Item" }).click()
63+
await page.getByLabel("Title").fill("Test Item")
64+
await page.getByRole("button", { name: "Cancel" }).click()
65+
66+
await expect(page.getByRole("dialog")).not.toBeVisible()
67+
})
68+
69+
test("Title is required", async ({ page }) => {
70+
await page.getByRole("button", { name: "Add Item" }).click()
71+
await page.getByLabel("Title").fill("")
72+
await page.getByLabel("Title").blur()
73+
74+
await expect(page.getByText("Title is required")).toBeVisible()
75+
})
76+
77+
test.describe("Edit and Delete", () => {
78+
let itemTitle: string
79+
80+
test.beforeEach(async ({ page }) => {
81+
itemTitle = randomItemTitle()
82+
83+
await page.getByRole("button", { name: "Add Item" }).click()
84+
await page.getByLabel("Title").fill(itemTitle)
85+
await page.getByRole("button", { name: "Save" }).click()
86+
await expect(page.getByText("Item created successfully")).toBeVisible()
87+
await expect(page.getByRole("dialog")).not.toBeVisible()
88+
})
89+
90+
test("Edit an item successfully", async ({ page }) => {
91+
const itemRow = page.getByRole("row").filter({ hasText: itemTitle })
92+
await itemRow.getByRole("button").last().click()
93+
await page.getByRole("menuitem", { name: "Edit Item" }).click()
94+
95+
const updatedTitle = randomItemTitle()
96+
await page.getByLabel("Title").fill(updatedTitle)
97+
await page.getByRole("button", { name: "Save" }).click()
98+
99+
await expect(page.getByText("Item updated successfully")).toBeVisible()
100+
await expect(page.getByText(updatedTitle)).toBeVisible()
101+
})
102+
103+
test("Delete an item successfully", async ({ page }) => {
104+
const itemRow = page.getByRole("row").filter({ hasText: itemTitle })
105+
await itemRow.getByRole("button").last().click()
106+
await page.getByRole("menuitem", { name: "Delete Item" }).click()
107+
108+
await page.getByRole("button", { name: "Delete" }).click()
109+
110+
await expect(
111+
page.getByText("The item was deleted successfully"),
112+
).toBeVisible()
113+
await expect(page.getByText(itemTitle)).not.toBeVisible()
114+
})
115+
})
116+
})
117+
118+
test.describe("Items empty state", () => {
119+
test.use({ storageState: { cookies: [], origins: [] } })
120+
121+
test("Shows empty state message when no items exist", async ({ page }) => {
122+
const email = randomEmail()
123+
const password = randomPassword()
124+
await createUser({ email, password })
125+
await logInUser(page, email, password)
126+
127+
await page.goto("/items")
128+
129+
await expect(page.getByText("You don't have any items yet")).toBeVisible()
130+
await expect(page.getByText("Add a new item to get started")).toBeVisible()
131+
})
132+
})

frontend/tests/login.spec.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,6 @@ test("Log in with invalid password", async ({ page }) => {
6969
await expect(page.getByText("Incorrect email or password")).toBeVisible()
7070
})
7171

72-
// Log out
73-
7472
test("Successful log out", async ({ page }) => {
7573
await page.goto("/login")
7674

frontend/tests/sign-up.spec.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,13 +75,11 @@ test("Sign up with existing email", async ({ page }) => {
7575
const email = randomEmail()
7676
const password = randomPassword()
7777

78-
// Sign up with an email
7978
await page.goto("/signup")
8079

8180
await fillForm(page, fullName, email, password, password)
8281
await page.getByRole("button", { name: "Sign Up" }).click()
8382

84-
// Sign up again with the same email
8583
await page.goto("/signup")
8684

8785
await fillForm(page, fullName, email, password, password)

0 commit comments

Comments
 (0)