← full-stack-fastapi-template  /  frontend/tests/admin.spec.ts

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
})
206