Skip to content

Commit c195e76

Browse files
committed
3863 - add more Login tests and loginPage for cleaner code
1 parent d056c15 commit c195e76

File tree

2 files changed

+176
-26
lines changed

2 files changed

+176
-26
lines changed
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import {Locator, Page} from '@playwright/test';
2+
3+
export class LoginPage {
4+
readonly form: {
5+
emailInput: Locator;
6+
loginButton: Locator;
7+
passwordInput: Locator;
8+
rememberMeCheckbox: Locator;
9+
};
10+
11+
readonly passwordToggle: {
12+
hideButton: Locator;
13+
showButton: Locator;
14+
toggleButton: Locator;
15+
};
16+
17+
readonly links: {
18+
createAccount: Locator;
19+
forgotPassword: Locator;
20+
};
21+
22+
readonly validationErrors: {
23+
emailRequired: Locator;
24+
passwordRequired: Locator;
25+
};
26+
27+
private readonly page: Page;
28+
29+
constructor(page: Page) {
30+
this.page = page;
31+
32+
this.form = {
33+
emailInput: page.getByLabel('Email'),
34+
loginButton: page.getByRole('button', {name: /log in/i}),
35+
passwordInput: page.getByRole('textbox', {name: 'Password'}),
36+
rememberMeCheckbox: page.getByLabel('Stay logged in'),
37+
};
38+
39+
this.passwordToggle = {
40+
hideButton: page.getByRole('button', {name: /hide password/i}),
41+
showButton: page.getByRole('button', {name: /show password/i}),
42+
toggleButton: page.getByRole('button', {name: /show password|hide password/i}),
43+
};
44+
45+
this.links = {
46+
createAccount: page.getByRole('button', {name: /create account/i}),
47+
forgotPassword: page.getByText(/forgot your password/i),
48+
};
49+
50+
this.validationErrors = {
51+
emailRequired: page.getByText(/email is required/i),
52+
passwordRequired: page.getByText(/password is required/i),
53+
};
54+
}
55+
56+
async goto(): Promise<void> {
57+
await this.page.goto('/login');
58+
}
59+
}
Lines changed: 117 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,136 @@
11
import {expect, test} from '@playwright/test';
22

3-
test('should load the home page', async ({page}) => {
4-
await test.step('Navigate to home page', async () => {
5-
await page.goto('/');
6-
});
3+
import {LoginPage} from '../../pages/loginPage';
74

8-
await test.step('Wait for page to load', async () => {
9-
await page.waitForLoadState('networkidle');
10-
});
5+
test.describe('Login Page', () => {
6+
let loginPage: LoginPage;
7+
8+
test.beforeEach(async ({page}) => {
9+
loginPage = new LoginPage(page);
1110

12-
await test.step('Verify page title', async () => {
13-
await expect(page).toHaveTitle(/ByteChef/i);
11+
await loginPage.goto();
1412
});
15-
});
1613

17-
test('should navigate to login page', async ({page}) => {
18-
await test.step('Navigate to login page', async () => {
19-
await page.goto('/login');
14+
test('should display login form elements', async () => {
15+
await expect(loginPage.form.emailInput).toBeVisible();
16+
17+
await expect(loginPage.form.passwordInput).toBeVisible();
18+
19+
await expect(loginPage.form.loginButton).toBeVisible();
2020
});
2121

22-
await test.step('Verify login form elements are visible', async () => {
23-
await expect(page.getByLabel('Email')).toBeVisible();
22+
test.describe('Form Validation', () => {
23+
test('should show validation errors on empty login form submission', async () => {
24+
await loginPage.form.loginButton.click();
25+
26+
await expect(loginPage.validationErrors.emailRequired).toBeVisible();
27+
28+
await expect(loginPage.validationErrors.passwordRequired).toBeVisible();
29+
});
30+
31+
test('should prevent form submission with invalid email format', async ({page}) => {
32+
await loginPage.form.emailInput.fill('invalidemail');
33+
34+
await loginPage.form.passwordInput.fill('password123');
2435

25-
await expect(page.getByLabel('Password')).toBeVisible();
36+
await loginPage.form.loginButton.click();
2637

27-
await expect(page.getByRole('button', {name: /log in/i})).toBeVisible();
38+
await expect(page).toHaveURL(/\/login/);
39+
40+
await expect(loginPage.form.emailInput).toHaveValue('invalidemail');
41+
});
42+
43+
test('should show validation error for password shorter than 4 characters', async () => {
44+
await loginPage.form.emailInput.fill('test@example.com');
45+
await loginPage.form.passwordInput.fill('123');
46+
await loginPage.form.loginButton.click();
47+
48+
await expect(loginPage.validationErrors.passwordRequired).toBeVisible();
49+
});
50+
51+
test('should accept valid email and password lengths', async () => {
52+
await loginPage.form.emailInput.fill('test@example.com');
53+
await loginPage.form.passwordInput.fill('password123');
54+
55+
await expect(loginPage.validationErrors.emailRequired).not.toBeVisible();
56+
await expect(loginPage.validationErrors.passwordRequired).not.toBeVisible();
57+
});
2858
});
29-
});
3059

31-
test('should show validation errors on empty login form submission', async ({page}) => {
32-
await test.step('Navigate to login page', async () => {
33-
await page.goto('/login');
60+
test.describe('User Interactions', () => {
61+
test('should toggle password visibility when clicking eye icon', async () => {
62+
await test.step('assert password input field and toggle button are visible', async () => {
63+
await loginPage.form.passwordInput.fill('mypassword123');
64+
65+
await expect(loginPage.passwordToggle.showButton).toBeVisible();
66+
67+
await expect(loginPage.form.passwordInput).toHaveAttribute('type', 'password');
68+
69+
await loginPage.passwordToggle.showButton.click();
70+
});
71+
72+
await test.step('click the toggle button', async () => {
73+
await expect(loginPage.form.passwordInput).toHaveAttribute('type', 'text');
74+
await expect(loginPage.passwordToggle.hideButton).toBeVisible();
75+
76+
await loginPage.passwordToggle.hideButton.click();
77+
});
78+
79+
await expect(loginPage.form.passwordInput).toHaveAttribute('type', 'password');
80+
81+
await expect(loginPage.passwordToggle.showButton).toBeVisible();
82+
});
83+
84+
test('should not show password toggle when password field is empty', async () => {
85+
await expect(loginPage.passwordToggle.toggleButton).not.toBeVisible();
86+
87+
await loginPage.form.passwordInput.fill('test');
88+
89+
await expect(loginPage.passwordToggle.showButton).toBeVisible();
90+
91+
await loginPage.form.passwordInput.clear();
92+
93+
await expect(loginPage.passwordToggle.toggleButton).not.toBeVisible();
94+
});
95+
96+
test('should toggle remember me checkbox', async () => {
97+
await expect(loginPage.form.rememberMeCheckbox).not.toBeChecked();
98+
99+
await loginPage.form.rememberMeCheckbox.check();
100+
101+
await expect(loginPage.form.rememberMeCheckbox).toBeChecked();
102+
103+
await loginPage.form.rememberMeCheckbox.uncheck();
104+
105+
await expect(loginPage.form.rememberMeCheckbox).not.toBeChecked();
106+
});
34107
});
35108

36-
await test.step('Submit empty login form', async () => {
37-
await page.getByRole('button', {name: /log in/i}).click();
109+
test.describe('Navigation', () => {
110+
test('should navigate to password reset page when clicking forgot password link', async ({page}) => {
111+
await loginPage.links.forgotPassword.click();
112+
113+
await expect(page).toHaveURL(/\/password-reset\/init/);
114+
});
115+
116+
test('should navigate to register page when clicking create account link', async ({page}) => {
117+
await loginPage.links.createAccount.click();
118+
119+
await expect(page).toHaveURL(/\/register/);
120+
});
38121
});
39122

40-
await test.step('Verify validation errors are displayed', async () => {
41-
await expect(page.getByText(/email is required/i)).toBeVisible();
123+
test.describe('Authentication', () => {
124+
test('should successfully login and navigate to projects page', async ({page}) => {
125+
await loginPage.form.emailInput.fill('admin@localhost.com');
126+
await loginPage.form.passwordInput.fill('admin');
127+
await loginPage.form.loginButton.click();
128+
129+
await page.waitForURL(/\/automation\/projects/, {timeout: 10000});
130+
131+
await expect(page).toHaveURL(/\/automation\/projects/);
42132

43-
await expect(page.getByText(/password is required/i)).toBeVisible();
133+
await expect(page.locator('div').filter({hasText: /^projects$/i})).toBeVisible();
134+
});
44135
});
45136
});

0 commit comments

Comments
 (0)