|
1 | | -import { test, expect, Page } from "@playwright/test"; |
| 1 | +import { expect, test } from "@playwright/test"; |
2 | 2 | import { loginAsServerAdmin } from "../utils/authenticate"; |
3 | | -import { |
4 | | - generateUniqueUsername, |
5 | | - navigateTo, |
6 | | - selectVuetifyOptionByName, |
7 | | - expectToHaveUrl, |
8 | | -} from "../utils/helpers"; |
| 3 | +import { generateUniqueUsername } from "../utils/helpers"; |
| 4 | +import { PlaywrightCreateUserAccountPage } from "../models/playwright-create-user-account-page"; |
| 5 | +import { PlaywrightUserAccountsPage } from "../models/playwright-user-accounts-page"; |
9 | 6 |
|
10 | | -async function setupCreateUserAccountPage(page: Page) { |
11 | | - await expect( |
12 | | - page.getByTestId("createUserAccount-form-container"), |
13 | | - ).toBeVisible(); |
14 | | - |
15 | | - //selects |
16 | | - const institutionSelectLocator = page.getByTestId( |
17 | | - "createUserAccount-institution-select", |
18 | | - ); |
19 | | - const roleSelectLocator = page.getByTestId("createUserAccount-role-select"); |
20 | | - |
21 | | - // fields |
22 | | - const usernameLocator = page.getByLabel(/username/i); |
23 | | - const nameLocator = page |
24 | | - .getByTestId("createUserAccount-name-input") |
25 | | - .getByRole("textbox"); |
26 | | - const surnameLocator = page |
27 | | - .getByTestId("createUserAccount-surname-input") |
28 | | - .getByRole("textbox"); |
29 | | - const emailLocator = page |
30 | | - .getByTestId("createUserAccount-email-input") |
31 | | - .getByRole("textbox"); |
32 | | - |
33 | | - const passwordLocator = page |
34 | | - .getByTestId("createUserAccount-password-input") |
35 | | - .getByRole("textbox"); |
36 | | - const confirmPasswordLocator = page |
37 | | - .getByTestId("createUserAccount-confirmPassword-input") |
38 | | - .getByRole("textbox"); |
39 | | - |
40 | | - // buttons |
41 | | - const saveButtonLocator = page.getByTestId("createUserAccount-save-button"); |
42 | | - const cancelButtonLocator = page.getByTestId( |
43 | | - "createUserAccount-cancel-button", |
44 | | - ); |
45 | | - |
46 | | - return { |
47 | | - institutionSelectLocator, |
48 | | - usernameLocator, |
49 | | - nameLocator, |
50 | | - surnameLocator, |
51 | | - emailLocator, |
52 | | - passwordLocator, |
53 | | - confirmPasswordLocator, |
54 | | - roleSelectLocator, |
55 | | - saveButtonLocator, |
56 | | - cancelButtonLocator, |
57 | | - }; |
58 | | -} |
59 | | - |
60 | | -//TODO this test was left with kinda big redundancies to explain to the apprentices in simple terms what is going on. Small refactor later |
61 | 7 | test.describe("1.1 User Accounts - CREATE Add", () => { |
| 8 | + let createUserAccountPage: PlaywrightCreateUserAccountPage; |
| 9 | + |
62 | 10 | test.beforeEach(async ({ page }) => { |
63 | 11 | await loginAsServerAdmin(page); |
64 | | - await navigateTo(page, "/user-accounts/create"); |
| 12 | + |
| 13 | + const userAccountsPage = new PlaywrightUserAccountsPage(page); |
| 14 | + await userAccountsPage.goto(); |
| 15 | + await userAccountsPage.expectVisible(); |
| 16 | + |
| 17 | + createUserAccountPage = |
| 18 | + await userAccountsPage.navigateToCreateUserAccount(); |
| 19 | + await createUserAccountPage.expectVisible(); |
65 | 20 | }); |
66 | 21 |
|
67 | 22 | test("A Success - creates a new INACTIVE user account", async ({ |
68 | 23 | page, |
69 | 24 | }) => { |
70 | | - const { |
71 | | - institutionSelectLocator, |
72 | | - usernameLocator, |
73 | | - nameLocator, |
74 | | - surnameLocator, |
75 | | - emailLocator, |
76 | | - passwordLocator, |
77 | | - confirmPasswordLocator, |
78 | | - roleSelectLocator, |
79 | | - saveButtonLocator, |
80 | | - } = await setupCreateUserAccountPage(page); |
| 25 | + expect(page.url()).toContain("/user-accounts/create"); |
81 | 26 |
|
82 | 27 | const uniqueValue = generateUniqueUsername("e2e-1.1.A-Success"); |
83 | 28 |
|
84 | | - //define values to be filled in |
85 | | - const username = uniqueValue; |
86 | | - const name = uniqueValue + "Name"; |
87 | | - const surname = uniqueValue + "LastName"; |
88 | | - const email = uniqueValue + "@email.com"; |
89 | | - const password = "StrongPass123!"; |
90 | | - |
91 | | - const institutionToSelect = "SEB Server"; |
92 | | - const roleToSelect = "Server Administrator"; |
93 | | - |
94 | | - // fill selects |
95 | | - await selectVuetifyOptionByName( |
96 | | - page, |
97 | | - institutionSelectLocator, |
98 | | - institutionToSelect, |
99 | | - ); |
100 | | - await selectVuetifyOptionByName(page, roleSelectLocator, roleToSelect); |
101 | | - |
102 | | - //fill fields |
103 | | - await usernameLocator.fill(username); |
104 | | - await nameLocator.fill(name); |
105 | | - await surnameLocator.fill(surname); |
106 | | - await emailLocator.fill(email); |
107 | | - await passwordLocator.fill(password); |
108 | | - await confirmPasswordLocator.fill(password); |
109 | | - |
110 | | - //create api interceptors befrre clicking save |
111 | | - const createRequestPromise = page.waitForRequest((req) => { |
112 | | - return ( |
113 | | - req.method() === "POST" && |
114 | | - /\/useraccount(?:\?|$)/i.test(req.url()) |
115 | | - ); |
| 29 | + await createUserAccountPage.fillForm({ |
| 30 | + institutionName: "SEB Server", |
| 31 | + roleName: "Server Administrator", |
| 32 | + username: `${uniqueValue}Username`, |
| 33 | + name: `${uniqueValue}Name`, |
| 34 | + surname: `${uniqueValue}LastName`, |
| 35 | + email: `${uniqueValue}@email.com`, |
| 36 | + pickFirstTimezone: true, |
| 37 | + password: "StrongPass123!", |
| 38 | + confirmPassword: "StrongPass123!", |
116 | 39 | }); |
117 | 40 |
|
118 | | - const createResponsePromise = page.waitForResponse((resp) => { |
119 | | - return ( |
120 | | - resp.request().method() === "POST" && |
121 | | - /\/useraccount(?:\?|$)/i.test(resp.url()) |
122 | | - ); |
| 41 | + await createUserAccountPage.expectCreateRequestSucceeded(async () => { |
| 42 | + await createUserAccountPage.submit(); |
123 | 43 | }); |
124 | 44 |
|
125 | | - // click save |
126 | | - await saveButtonLocator.click(); |
127 | | - |
128 | | - // capture req and resp |
129 | | - const createRequest = await createRequestPromise; |
130 | | - const createResponse = await createResponsePromise; |
131 | | - |
132 | | - // assert endpoint aand method, then status |
133 | | - expect(createRequest.method()).toBe("POST"); |
134 | | - expect(createRequest.url()).toMatch(/\/useraccount(?:\?|$)/i); |
135 | | - |
136 | | - expect(createResponse.status()).toBe(200); |
137 | | - expect(createResponse.ok()).toBeTruthy(); |
138 | | - |
139 | | - // assert payload |
140 | | - const actualPayload = createRequest.postDataJSON(); |
141 | | - |
142 | | - //this needs to match the fields we filled out above |
143 | | - const expectedPayload = { |
144 | | - institutionId: "11", //this matches SQL script for e2e testing!!! it corresponds to SEB Server institution |
145 | | - name: name, |
146 | | - surname: surname, |
147 | | - username: username, |
148 | | - newPassword: password, |
149 | | - confirmNewPassword: password, |
150 | | - language: "en", |
151 | | - email: email, |
152 | | - userRoles: ["SEB_SERVER_ADMIN"], |
153 | | - }; |
154 | | - |
155 | | - expect(actualPayload).toMatchObject(expectedPayload); |
156 | | - |
157 | | - await expectToHaveUrl(page, "user-accounts"); |
158 | | - |
159 | | - //note that this test does not test if the backend actually saves the data correctly. This could be done in 2 ways: |
160 | | - // 1: Navigate to User accounts, search for the username entered in the test, and look at the details - This however creates a dependency on get all, and get by id working. If one of those is broken, this test would fail too |
161 | | - // 2: Clean way, set up a database query to actually verify the data is entered correct in the tables - This would be the clean way |
| 45 | + await createUserAccountPage.expectRedirectToUserAccounts(); |
162 | 46 | }); |
163 | 47 |
|
164 | | - test("B Client Validation - checks all validations and that create button doesn't do API call", async ({ |
| 48 | + test("B Client Validation - shows validation messages and does NOT call create API", async ({ |
165 | 49 | page, |
166 | 50 | }) => { |
167 | | - const { passwordLocator, confirmPasswordLocator, saveButtonLocator } = |
168 | | - await setupCreateUserAccountPage(page); |
169 | | - |
170 | | - // mo post request allowed during this test (well none should get through) |
171 | | - await page.route(/\/useraccount(?:\?|$)/i, async (route, request) => { |
172 | | - if (request.method() === "POST") { |
173 | | - await route.abort(); |
174 | | - throw new Error( |
175 | | - "POST /useraccount was attempted during failed client validation test", |
176 | | - ); |
177 | | - } |
178 | | - await route.continue(); |
179 | | - }); |
180 | | - |
181 | | - page.on("request", (req) => { |
182 | | - if ( |
183 | | - req.method() === "POST" && |
184 | | - /\/useraccount(?:\?|$)/i.test(req.url()) |
185 | | - ) { |
186 | | - throw new Error( |
187 | | - `Validation test must not call POST /useraccount, but it did: ${req.url()}`, |
188 | | - ); |
189 | | - } |
190 | | - }); |
191 | | - |
192 | | - async function expectFieldError(testId: string, text: string) { |
193 | | - const field = page.getByTestId(testId); |
194 | | - await expect( |
195 | | - field.locator(".v-messages__message").filter({ hasText: text }), |
196 | | - ).toHaveCount(1, { timeout: 5000 }); |
197 | | - } |
| 51 | + expect(page.url()).toContain("/user-accounts/create"); |
198 | 52 |
|
199 | 53 | const REQUIRED = "This field is required"; |
200 | 54 | const PASSWORD_TOO_SHORT = "Password must be at least 8 characters"; |
201 | 55 | const PASSWORDS_MUST_MATCH = "Passwords must match"; |
202 | 56 |
|
203 | | - // 1. Click with all empty |
204 | | - await saveButtonLocator.click(); |
205 | | - |
206 | | - await expectFieldError( |
207 | | - "createUserAccount-institution-select", |
208 | | - REQUIRED, |
209 | | - ); |
210 | | - await expectFieldError("createUserAccount-username-input", REQUIRED); |
211 | | - await expectFieldError("createUserAccount-name-input", REQUIRED); |
212 | | - await expectFieldError("createUserAccount-surname-input", REQUIRED); |
213 | | - await expectFieldError("createUserAccount-password-input", REQUIRED); |
214 | | - await expectFieldError( |
215 | | - "createUserAccount-confirmPassword-input", |
216 | | - REQUIRED, |
217 | | - ); |
218 | | - await expectFieldError("createUserAccount-role-select", REQUIRED); |
219 | | - |
220 | | - // 2. Too short password |
221 | | - await passwordLocator.fill("Abc1"); // < 8 |
222 | | - await saveButtonLocator.click(); |
| 57 | + await createUserAccountPage.expectNoCreateRequest(async () => { |
| 58 | + await createUserAccountPage.submit(); |
| 59 | + }); |
223 | 60 |
|
224 | | - await expectFieldError( |
225 | | - "createUserAccount-password-input", |
226 | | - PASSWORD_TOO_SHORT, |
227 | | - ); |
| 61 | + await createUserAccountPage.expectRequiredFieldErrors({ |
| 62 | + institution: REQUIRED, |
| 63 | + username: REQUIRED, |
| 64 | + name: REQUIRED, |
| 65 | + surname: REQUIRED, |
| 66 | + password: REQUIRED, |
| 67 | + confirmPassword: REQUIRED, |
| 68 | + role: REQUIRED, |
| 69 | + }); |
228 | 70 |
|
229 | | - // 3. missmatch passwords |
230 | | - await passwordLocator.fill("Abcdefg1"); |
231 | | - await confirmPasswordLocator.fill("Abcdefg2"); |
232 | | - await saveButtonLocator.click(); |
| 71 | + await createUserAccountPage.fillPassword("Abc1"); |
| 72 | + await createUserAccountPage.expectNoCreateRequest(async () => { |
| 73 | + await createUserAccountPage.submit(); |
| 74 | + }); |
| 75 | + await createUserAccountPage.expectPasswordTooShort(PASSWORD_TOO_SHORT); |
233 | 76 |
|
234 | | - await expectFieldError( |
235 | | - "createUserAccount-confirmPassword-input", |
| 77 | + await createUserAccountPage.fillPassword("Abcdefg1"); |
| 78 | + await createUserAccountPage.fillConfirmPassword("Abcdefg2"); |
| 79 | + await createUserAccountPage.expectNoCreateRequest(async () => { |
| 80 | + await createUserAccountPage.submit(); |
| 81 | + }); |
| 82 | + await createUserAccountPage.expectPasswordsMustMatch( |
236 | 83 | PASSWORDS_MUST_MATCH, |
237 | 84 | ); |
238 | 85 |
|
239 | | - // expected to not change URL |
240 | | - await expectToHaveUrl(page, "user-accounts/create"); |
| 86 | + await createUserAccountPage.expectStillOnCreatePage(); |
241 | 87 | }); |
242 | 88 |
|
243 | | - test("C Server Error - user account already exists (duplicate username)", async ({ |
| 89 | + test("C Server Error - duplicate username shows toast", async ({ |
244 | 90 | page, |
245 | 91 | }) => { |
246 | | - const { |
247 | | - institutionSelectLocator, |
248 | | - usernameLocator, |
249 | | - nameLocator, |
250 | | - surnameLocator, |
251 | | - emailLocator, |
252 | | - passwordLocator, |
253 | | - confirmPasswordLocator, |
254 | | - roleSelectLocator, |
255 | | - saveButtonLocator, |
256 | | - } = await setupCreateUserAccountPage(page); |
| 92 | + expect(page.url()).toContain("/user-accounts/create"); |
257 | 93 |
|
258 | 94 | const uniqueValue = generateUniqueUsername("e2e-1.1.C-Server-Error"); |
259 | 95 |
|
260 | | - const username = "createtests"; // SQL Script includes a user with this username!!! |
261 | | - const name = uniqueValue + "Name"; |
262 | | - const surname = uniqueValue + "LastName"; |
263 | | - const email = uniqueValue + "@email.com"; |
264 | | - const password = "StrongPass123!"; |
265 | | - |
266 | | - const institutionToSelect = "SEB Server"; |
267 | | - const roleToSelect = "Server Administrator"; |
268 | | - |
269 | | - // fill selects |
270 | | - await selectVuetifyOptionByName( |
271 | | - page, |
272 | | - institutionSelectLocator, |
273 | | - institutionToSelect, |
274 | | - ); |
275 | | - await selectVuetifyOptionByName(page, roleSelectLocator, roleToSelect); |
276 | | - |
277 | | - //fill fields |
278 | | - await usernameLocator.fill(username); |
279 | | - await nameLocator.fill(name); |
280 | | - await surnameLocator.fill(surname); |
281 | | - await emailLocator.fill(email); |
282 | | - await passwordLocator.fill(password); |
283 | | - await confirmPasswordLocator.fill(password); |
284 | | - |
285 | | - const createRequestPromise = page.waitForRequest((req) => { |
286 | | - return ( |
287 | | - req.method() === "POST" && |
288 | | - /\/useraccount(?:\?|$)/i.test(req.url()) |
289 | | - ); |
| 96 | + await createUserAccountPage.fillForm({ |
| 97 | + institutionName: "SEB Server", |
| 98 | + roleName: "Server Administrator", |
| 99 | + username: "createtests", //there should be a db entry with username createtests |
| 100 | + name: `${uniqueValue}Name`, |
| 101 | + surname: `${uniqueValue}LastName`, |
| 102 | + email: `${uniqueValue}@email.com`, |
| 103 | + password: "StrongPass123!", |
| 104 | + confirmPassword: "StrongPass123!", |
290 | 105 | }); |
291 | 106 |
|
292 | | - const createResponsePromise = page.waitForResponse((resp) => { |
293 | | - return ( |
294 | | - resp.request().method() === "POST" && |
295 | | - /\/useraccount(?:\?|$)/i.test(resp.url()) |
296 | | - ); |
297 | | - }); |
298 | | - |
299 | | - await saveButtonLocator.click(); |
300 | | - |
301 | | - const createRequest = await createRequestPromise; |
302 | | - const createResponse = await createResponsePromise; |
303 | | - |
304 | | - expect(createRequest.method()).toBe("POST"); |
305 | | - expect(createRequest.url()).toMatch(/\/useraccount(?:\?|$)/i); |
306 | | - |
307 | | - expect(createResponse.status()).toBe(400); |
308 | | - expect(createResponse.ok()).toBeFalsy(); |
309 | | - |
310 | | - await expectToHaveUrl(page, "user-accounts/create"); |
311 | | - //check toast |
312 | | - const toast = page.locator(".toast-item[role='alert']"); |
| 107 | + const resp = await createUserAccountPage.captureCreateResponse( |
| 108 | + async () => { |
| 109 | + await createUserAccountPage.submit(); |
| 110 | + }, |
| 111 | + ); |
313 | 112 |
|
314 | | - await expect(toast).toBeVisible(); |
| 113 | + expect(resp.status()).toBe(400); |
| 114 | + expect(resp.ok()).toBeFalsy(); |
315 | 115 |
|
316 | | - await expect(toast.locator(".toast-text")).toContainText( |
| 116 | + await createUserAccountPage.expectStillOnCreatePage(); |
| 117 | + await createUserAccountPage.expectErrorToast([ |
317 | 118 | "Field validation error", |
318 | | - ); |
319 | | - await expect(toast.locator(".toast-text")).toContainText( |
320 | 119 | "Username is already being used.", |
321 | | - ); |
| 120 | + ]); |
322 | 121 | }); |
323 | 122 | }); |
0 commit comments