Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 21 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,15 @@ npm test

```
example-case/
├── server.js # Express login server
├── server.js # Express server (login, logout, registration)
├── public/
│ ├── login.html # Login page
│ ├── register.html # Registration page
│ └── dashboard.html # Post-login dashboard
├── tests/
│ └── login.spec.js # Playwright E2E tests
│ ├── login.spec.js # Login E2E tests
│ ├── logout.spec.js # Logout E2E tests
│ └── registration.spec.js # Registration E2E tests
├── playwright.config.js # Playwright configuration
├── .github/workflows/
│ └── playwright.yml # GitHub Actions CI
Expand All @@ -33,13 +36,28 @@ example-case/

## Test Scenarios

### Login
| Test | Flow | Expected |
|------|------|----------|
| Valid login | `testuser` / `Test123!` | Redirect to dashboard |
| Invalid login | Wrong credentials | Error message |
| Empty credentials | Submit empty form | Validation |
| Locked account | `locked` / `Locked123!` | Account locked message |

### Logout
| Test | Flow | Expected |
|------|------|----------|
| Sign out | Click Sign out from dashboard | Redirect to login |
| Re-login | Logout then login again | Success |

### Registration
| Test | Flow | Expected |
|------|------|----------|
| Valid registration | New username, email, password | Redirect to login |
| Duplicate username | Use existing username | Error message |
| Passwords mismatch | Different password/confirm | Error message |
| Short password | < 6 characters | Error message |

## CI Pipeline

The workflow runs on **pull requests** to `main` or `master`:
Expand All @@ -63,3 +81,4 @@ npm start # Start server only (for manual testing)
<!-- Small comment: Safe for PR review, just updating docs. -->
We are just updating to test the CI
## Update
## Again
1 change: 1 addition & 0 deletions public/login.html
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ <h1>Login</h1>
<button type="submit" id="submitBtn">Sign In</button>
</form>
<div id="message" class="message" role="alert"></div>
<p style="margin-top: 16px; text-align: center;">Don't have an account? <a href="/register">Register</a></p>

<script>
document.getElementById('loginForm').addEventListener('submit', async (e) => {
Expand Down
104 changes: 104 additions & 0 deletions public/register.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Register - Demo App</title>
<style>
* { box-sizing: border-box; }
body { font-family: system-ui, sans-serif; max-width: 400px; margin: 80px auto; padding: 20px; }
h1 { margin-bottom: 24px; }
.form-group { margin-bottom: 16px; }
label { display: block; margin-bottom: 6px; font-weight: 500; }
input { width: 100%; padding: 10px; font-size: 16px; border: 1px solid #ccc; border-radius: 6px; }
button { width: 100%; padding: 12px; font-size: 16px; background: #28a745; color: white; border: none; border-radius: 6px; cursor: pointer; }
button:hover { background: #218838; }
.message { margin-top: 16px; padding: 12px; border-radius: 6px; display: none; }
.message.error { background: #f8d7da; color: #721c24; }
.message.success { background: #d4edda; color: #155724; }
.link { margin-top: 16px; text-align: center; }
.link a { color: #007bff; }
</style>
</head>
<body>
<h1>Register</h1>
<form id="registerForm">
<div class="form-group">
<label for="username">Username</label>
<input type="text" id="username" name="username" required autocomplete="username" placeholder="Choose username">
</div>
<div class="form-group">
<label for="email">Email</label>
<input type="email" id="email" name="email" required autocomplete="email" placeholder="Enter email">
</div>
<div class="form-group">
<label for="password">Password</label>
<input type="password" id="password" name="password" required autocomplete="new-password" placeholder="Choose password" minlength="6">
</div>
<div class="form-group">
<label for="confirmPassword">Confirm Password</label>
<input type="password" id="confirmPassword" name="confirmPassword" required autocomplete="new-password" placeholder="Confirm password">
</div>
<button type="submit" id="submitBtn">Create Account</button>
</form>
<div id="message" class="message" role="alert"></div>
<p class="link">Already have an account? <a href="/login">Sign in</a></p>

<script>
document.getElementById('registerForm').addEventListener('submit', async (e) => {
e.preventDefault();
const username = document.getElementById('username').value.trim();
const email = document.getElementById('email').value.trim();
const password = document.getElementById('password').value;
const confirmPassword = document.getElementById('confirmPassword').value;
const messageEl = document.getElementById('message');
const submitBtn = document.getElementById('submitBtn');

messageEl.style.display = 'none';
messageEl.className = 'message';
submitBtn.disabled = true;

if (password !== confirmPassword) {
messageEl.style.display = 'block';
messageEl.className = 'message error';
messageEl.textContent = 'Passwords do not match';
submitBtn.disabled = false;
return;
}

if (password.length < 6) {
messageEl.style.display = 'block';
messageEl.className = 'message error';
messageEl.textContent = 'Password must be at least 6 characters';
submitBtn.disabled = false;
return;
}

try {
const res = await fetch('/register', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username, email, password })
});
const data = await res.json();

messageEl.style.display = 'block';
if (data.success) {
messageEl.className = 'message success';
messageEl.textContent = data.message;
setTimeout(() => { window.location.href = data.redirectUrl || '/login'; }, 500);
} else {
messageEl.className = 'message error';
messageEl.textContent = data.message;
submitBtn.disabled = false;
}
} catch (err) {
messageEl.style.display = 'block';
messageEl.className = 'message error';
messageEl.textContent = 'Network error. Please try again.';
submitBtn.disabled = false;
}
});
</script>
</body>
</html>
55 changes: 52 additions & 3 deletions server.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,15 @@ app.use(express.urlencoded({ extended: true }));
app.use(express.json());
app.use(express.static('public'));

// Demo credentials (for testing only - never use in production!)
// Demo credentials and in-memory users (for testing only - never use in production!)
const VALID_USER = { username: 'testuser', password: 'Test123!' };
const LOCKED_USER = { username: 'locked', password: 'Locked123!' };

const users = new Map([
[VALID_USER.username, { ...VALID_USER, email: 'test@example.com' }],
[LOCKED_USER.username, { ...LOCKED_USER, email: 'locked@example.com' }],
]);

app.get('/', (req, res) => {
res.redirect('/login');
});
Expand All @@ -30,14 +35,15 @@ app.post('/login', (req, res) => {
});
}

if (username === LOCKED_USER.username) {
if (username.trim() === LOCKED_USER.username) {
return res.status(423).json({
success: false,
message: 'Account is locked. Please contact support.'
});
}

if (username === VALID_USER.username && password === VALID_USER.password) {
const user = users.get(username.trim());
if (user && user.password === password) {
return res.json({
success: true,
message: 'Login successful',
Expand All @@ -55,6 +61,49 @@ app.get('/dashboard', (req, res) => {
res.sendFile(path.join(__dirname, 'public', 'dashboard.html'));
});

app.get('/register', (req, res) => {
res.sendFile(path.join(__dirname, 'public', 'register.html'));
});

app.post('/register', (req, res) => {
const { username, email, password } = req.body;

if (!username || !email || !password) {
return res.status(400).json({
success: false,
message: 'Username, email and password are required'
});
}

if (username.trim().length === 0 || email.trim().length === 0) {
return res.status(400).json({
success: false,
message: 'Username and email cannot be empty'
});
}

if (password.length < 6) {
return res.status(400).json({
success: false,
message: 'Password must be at least 6 characters'
});
}

if (users.has(username.trim())) {
return res.status(409).json({
success: false,
message: 'Username already exists'
});
}

users.set(username.trim(), { username: username.trim(), email: email.trim(), password });
return res.status(201).json({
success: true,
message: 'Registration successful. You can now sign in.',
redirectUrl: '/login'
});
});

app.listen(PORT, () => {
console.log(`Server running at http://localhost:${PORT}`);
});
43 changes: 43 additions & 0 deletions tests/logout.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// @ts-check
const { test, expect } = require('@playwright/test');

const VALID_CREDENTIALS = { username: 'testuser', password: 'Test123!' };

test.describe('Logout - E2E Tests', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/login');
await page.getByLabel('Username').fill(VALID_CREDENTIALS.username);
await page.getByLabel('Password').fill(VALID_CREDENTIALS.password);
await page.getByRole('button', { name: 'Sign In' }).click();
await expect(page).toHaveURL(/\/dashboard/);
});

test('should redirect to login page when clicking Sign out', async ({ page }) => {
await page.getByRole('link', { name: 'Sign out' }).click();

await expect(page).toHaveURL(/\/login/);
await expect(page.getByRole('heading', { name: 'Login' })).toBeVisible();
await expect(page.getByRole('button', { name: 'Sign In' })).toBeVisible();
});

test('should display login form after logout', async ({ page }) => {
await page.getByRole('link', { name: 'Sign out' }).click();

await expect(page.getByLabel('Username')).toBeVisible();
await expect(page.getByLabel('Password')).toBeVisible();
await expect(page.getByLabel('Username')).toHaveValue('');
await expect(page.getByLabel('Password')).toHaveValue('');
});

test('should allow login again after logout', async ({ page }) => {
await page.getByRole('link', { name: 'Sign out' }).click();
await expect(page).toHaveURL(/\/login/);

await page.getByLabel('Username').fill(VALID_CREDENTIALS.username);
await page.getByLabel('Password').fill(VALID_CREDENTIALS.password);
await page.getByRole('button', { name: 'Sign In' }).click();

await expect(page).toHaveURL(/\/dashboard/);
await expect(page.getByRole('heading', { name: 'Dashboard' })).toBeVisible();
});
});
88 changes: 88 additions & 0 deletions tests/registration.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
// @ts-check
const { test, expect } = require('@playwright/test');

const VALID_CREDENTIALS = { username: 'testuser', password: 'Test123!' };

test.describe('Registration - E2E Tests', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/register');
});

test('should display registration form with required fields', async ({ page }) => {
await expect(page.getByRole('heading', { name: 'Register' })).toBeVisible();
await expect(page.getByLabel('Username')).toBeVisible();
await expect(page.getByLabel('Email')).toBeVisible();
await expect(page.getByLabel('Password')).toBeVisible();

Check failure on line 15 in tests/registration.spec.js

View workflow job for this annotation

GitHub Actions / Run Playwright Tests

[chromium] › tests/registration.spec.js:11:3 › Registration - E2E Tests › should display registration form with required fields

1) [chromium] › tests/registration.spec.js:11:3 › Registration - E2E Tests › should display registration form with required fields Retry #2 ─────────────────────────────────────────────────────────────────────────────────────── Error: expect(locator).toBeVisible() failed Locator: getByLabel('Password') Expected: visible Error: strict mode violation: getByLabel('Password') resolved to 2 elements: 1) <input required="" id="password" minlength="6" type="password" name="password" autocomplete="new-password" placeholder="Choose password"/> aka getByRole('textbox', { name: 'Password', exact: true }) 2) <input required="" type="password" id="confirmPassword" name="confirmPassword" autocomplete="new-password" placeholder="Confirm password"/> aka getByRole('textbox', { name: 'Confirm Password' }) Call log: - Expect "toBeVisible" with timeout 5000ms - waiting for getByLabel('Password') 13 | await expect(page.getByLabel('Username')).toBeVisible(); 14 | await expect(page.getByLabel('Email')).toBeVisible(); > 15 | await expect(page.getByLabel('Password')).toBeVisible(); | ^ 16 | await expect(page.getByLabel('Confirm Password')).toBeVisible(); 17 | await expect(page.getByRole('button', { name: 'Create Account' })).toBeVisible(); 18 | }); at /home/runner/work/Demo-Playwright-One/Demo-Playwright-One/tests/registration.spec.js:15:47

Check failure on line 15 in tests/registration.spec.js

View workflow job for this annotation

GitHub Actions / Run Playwright Tests

[chromium] › tests/registration.spec.js:11:3 › Registration - E2E Tests › should display registration form with required fields

1) [chromium] › tests/registration.spec.js:11:3 › Registration - E2E Tests › should display registration form with required fields Retry #1 ─────────────────────────────────────────────────────────────────────────────────────── Error: expect(locator).toBeVisible() failed Locator: getByLabel('Password') Expected: visible Error: strict mode violation: getByLabel('Password') resolved to 2 elements: 1) <input required="" id="password" minlength="6" type="password" name="password" autocomplete="new-password" placeholder="Choose password"/> aka getByRole('textbox', { name: 'Password', exact: true }) 2) <input required="" type="password" id="confirmPassword" name="confirmPassword" autocomplete="new-password" placeholder="Confirm password"/> aka getByRole('textbox', { name: 'Confirm Password' }) Call log: - Expect "toBeVisible" with timeout 5000ms - waiting for getByLabel('Password') 13 | await expect(page.getByLabel('Username')).toBeVisible(); 14 | await expect(page.getByLabel('Email')).toBeVisible(); > 15 | await expect(page.getByLabel('Password')).toBeVisible(); | ^ 16 | await expect(page.getByLabel('Confirm Password')).toBeVisible(); 17 | await expect(page.getByRole('button', { name: 'Create Account' })).toBeVisible(); 18 | }); at /home/runner/work/Demo-Playwright-One/Demo-Playwright-One/tests/registration.spec.js:15:47

Check failure on line 15 in tests/registration.spec.js

View workflow job for this annotation

GitHub Actions / Run Playwright Tests

[chromium] › tests/registration.spec.js:11:3 › Registration - E2E Tests › should display registration form with required fields

1) [chromium] › tests/registration.spec.js:11:3 › Registration - E2E Tests › should display registration form with required fields Error: expect(locator).toBeVisible() failed Locator: getByLabel('Password') Expected: visible Error: strict mode violation: getByLabel('Password') resolved to 2 elements: 1) <input required="" id="password" minlength="6" type="password" name="password" autocomplete="new-password" placeholder="Choose password"/> aka getByRole('textbox', { name: 'Password', exact: true }) 2) <input required="" type="password" id="confirmPassword" name="confirmPassword" autocomplete="new-password" placeholder="Confirm password"/> aka getByRole('textbox', { name: 'Confirm Password' }) Call log: - Expect "toBeVisible" with timeout 5000ms - waiting for getByLabel('Password') 13 | await expect(page.getByLabel('Username')).toBeVisible(); 14 | await expect(page.getByLabel('Email')).toBeVisible(); > 15 | await expect(page.getByLabel('Password')).toBeVisible(); | ^ 16 | await expect(page.getByLabel('Confirm Password')).toBeVisible(); 17 | await expect(page.getByRole('button', { name: 'Create Account' })).toBeVisible(); 18 | }); at /home/runner/work/Demo-Playwright-One/Demo-Playwright-One/tests/registration.spec.js:15:47
await expect(page.getByLabel('Confirm Password')).toBeVisible();
await expect(page.getByRole('button', { name: 'Create Account' })).toBeVisible();
});

test('valid registration flow - should redirect to login on success', async ({ page }) => {
const uniqueUser = `newuser_${Date.now()}`;
await page.getByLabel('Username').fill(uniqueUser);
await page.getByLabel('Email').fill(`${uniqueUser}@example.com`);
await page.getByLabel('Password').fill('Password123!');

Check failure on line 24 in tests/registration.spec.js

View workflow job for this annotation

GitHub Actions / Run Playwright Tests

[chromium] › tests/registration.spec.js:20:3 › Registration - E2E Tests › valid registration flow - should redirect to login on success

2) [chromium] › tests/registration.spec.js:20:3 › Registration - E2E Tests › valid registration flow - should redirect to login on success Retry #2 ─────────────────────────────────────────────────────────────────────────────────────── Error: locator.fill: Error: strict mode violation: getByLabel('Password') resolved to 2 elements: 1) <input required="" id="password" minlength="6" type="password" name="password" autocomplete="new-password" placeholder="Choose password"/> aka getByRole('textbox', { name: 'Password', exact: true }) 2) <input required="" type="password" id="confirmPassword" name="confirmPassword" autocomplete="new-password" placeholder="Confirm password"/> aka getByRole('textbox', { name: 'Confirm Password' }) Call log: - waiting for getByLabel('Password') 22 | await page.getByLabel('Username').fill(uniqueUser); 23 | await page.getByLabel('Email').fill(`${uniqueUser}@example.com`); > 24 | await page.getByLabel('Password').fill('Password123!'); | ^ 25 | await page.getByLabel('Confirm Password').fill('Password123!'); 26 | await page.getByRole('button', { name: 'Create Account' }).click(); 27 | at /home/runner/work/Demo-Playwright-One/Demo-Playwright-One/tests/registration.spec.js:24:39

Check failure on line 24 in tests/registration.spec.js

View workflow job for this annotation

GitHub Actions / Run Playwright Tests

[chromium] › tests/registration.spec.js:20:3 › Registration - E2E Tests › valid registration flow - should redirect to login on success

2) [chromium] › tests/registration.spec.js:20:3 › Registration - E2E Tests › valid registration flow - should redirect to login on success Retry #1 ─────────────────────────────────────────────────────────────────────────────────────── Error: locator.fill: Error: strict mode violation: getByLabel('Password') resolved to 2 elements: 1) <input required="" id="password" minlength="6" type="password" name="password" autocomplete="new-password" placeholder="Choose password"/> aka getByRole('textbox', { name: 'Password', exact: true }) 2) <input required="" type="password" id="confirmPassword" name="confirmPassword" autocomplete="new-password" placeholder="Confirm password"/> aka getByRole('textbox', { name: 'Confirm Password' }) Call log: - waiting for getByLabel('Password') 22 | await page.getByLabel('Username').fill(uniqueUser); 23 | await page.getByLabel('Email').fill(`${uniqueUser}@example.com`); > 24 | await page.getByLabel('Password').fill('Password123!'); | ^ 25 | await page.getByLabel('Confirm Password').fill('Password123!'); 26 | await page.getByRole('button', { name: 'Create Account' }).click(); 27 | at /home/runner/work/Demo-Playwright-One/Demo-Playwright-One/tests/registration.spec.js:24:39

Check failure on line 24 in tests/registration.spec.js

View workflow job for this annotation

GitHub Actions / Run Playwright Tests

[chromium] › tests/registration.spec.js:20:3 › Registration - E2E Tests › valid registration flow - should redirect to login on success

2) [chromium] › tests/registration.spec.js:20:3 › Registration - E2E Tests › valid registration flow - should redirect to login on success Error: locator.fill: Error: strict mode violation: getByLabel('Password') resolved to 2 elements: 1) <input required="" id="password" minlength="6" type="password" name="password" autocomplete="new-password" placeholder="Choose password"/> aka getByRole('textbox', { name: 'Password', exact: true }) 2) <input required="" type="password" id="confirmPassword" name="confirmPassword" autocomplete="new-password" placeholder="Confirm password"/> aka getByRole('textbox', { name: 'Confirm Password' }) Call log: - waiting for getByLabel('Password') 22 | await page.getByLabel('Username').fill(uniqueUser); 23 | await page.getByLabel('Email').fill(`${uniqueUser}@example.com`); > 24 | await page.getByLabel('Password').fill('Password123!'); | ^ 25 | await page.getByLabel('Confirm Password').fill('Password123!'); 26 | await page.getByRole('button', { name: 'Create Account' }).click(); 27 | at /home/runner/work/Demo-Playwright-One/Demo-Playwright-One/tests/registration.spec.js:24:39
await page.getByLabel('Confirm Password').fill('Password123!');
await page.getByRole('button', { name: 'Create Account' }).click();

await expect(page).toHaveURL(/\/login/);
await expect(page.getByRole('heading', { name: 'Login' })).toBeVisible();
});

test('valid registration flow - new user can login after registration', async ({ page }) => {
const uniqueUser = `reguser_${Date.now()}`;
await page.getByLabel('Username').fill(uniqueUser);
await page.getByLabel('Email').fill(`${uniqueUser}@example.com`);
await page.getByLabel('Password').fill('Password123!');

Check failure on line 36 in tests/registration.spec.js

View workflow job for this annotation

GitHub Actions / Run Playwright Tests

[chromium] › tests/registration.spec.js:32:3 › Registration - E2E Tests › valid registration flow - new user can login after registration

3) [chromium] › tests/registration.spec.js:32:3 › Registration - E2E Tests › valid registration flow - new user can login after registration Retry #2 ─────────────────────────────────────────────────────────────────────────────────────── Error: locator.fill: Error: strict mode violation: getByLabel('Password') resolved to 2 elements: 1) <input required="" id="password" minlength="6" type="password" name="password" autocomplete="new-password" placeholder="Choose password"/> aka getByRole('textbox', { name: 'Password', exact: true }) 2) <input required="" type="password" id="confirmPassword" name="confirmPassword" autocomplete="new-password" placeholder="Confirm password"/> aka getByRole('textbox', { name: 'Confirm Password' }) Call log: - waiting for getByLabel('Password') 34 | await page.getByLabel('Username').fill(uniqueUser); 35 | await page.getByLabel('Email').fill(`${uniqueUser}@example.com`); > 36 | await page.getByLabel('Password').fill('Password123!'); | ^ 37 | await page.getByLabel('Confirm Password').fill('Password123!'); 38 | await page.getByRole('button', { name: 'Create Account' }).click(); 39 | at /home/runner/work/Demo-Playwright-One/Demo-Playwright-One/tests/registration.spec.js:36:39

Check failure on line 36 in tests/registration.spec.js

View workflow job for this annotation

GitHub Actions / Run Playwright Tests

[chromium] › tests/registration.spec.js:32:3 › Registration - E2E Tests › valid registration flow - new user can login after registration

3) [chromium] › tests/registration.spec.js:32:3 › Registration - E2E Tests › valid registration flow - new user can login after registration Retry #1 ─────────────────────────────────────────────────────────────────────────────────────── Error: locator.fill: Error: strict mode violation: getByLabel('Password') resolved to 2 elements: 1) <input required="" id="password" minlength="6" type="password" name="password" autocomplete="new-password" placeholder="Choose password"/> aka getByRole('textbox', { name: 'Password', exact: true }) 2) <input required="" type="password" id="confirmPassword" name="confirmPassword" autocomplete="new-password" placeholder="Confirm password"/> aka getByRole('textbox', { name: 'Confirm Password' }) Call log: - waiting for getByLabel('Password') 34 | await page.getByLabel('Username').fill(uniqueUser); 35 | await page.getByLabel('Email').fill(`${uniqueUser}@example.com`); > 36 | await page.getByLabel('Password').fill('Password123!'); | ^ 37 | await page.getByLabel('Confirm Password').fill('Password123!'); 38 | await page.getByRole('button', { name: 'Create Account' }).click(); 39 | at /home/runner/work/Demo-Playwright-One/Demo-Playwright-One/tests/registration.spec.js:36:39

Check failure on line 36 in tests/registration.spec.js

View workflow job for this annotation

GitHub Actions / Run Playwright Tests

[chromium] › tests/registration.spec.js:32:3 › Registration - E2E Tests › valid registration flow - new user can login after registration

3) [chromium] › tests/registration.spec.js:32:3 › Registration - E2E Tests › valid registration flow - new user can login after registration Error: locator.fill: Error: strict mode violation: getByLabel('Password') resolved to 2 elements: 1) <input required="" id="password" minlength="6" type="password" name="password" autocomplete="new-password" placeholder="Choose password"/> aka getByRole('textbox', { name: 'Password', exact: true }) 2) <input required="" type="password" id="confirmPassword" name="confirmPassword" autocomplete="new-password" placeholder="Confirm password"/> aka getByRole('textbox', { name: 'Confirm Password' }) Call log: - waiting for getByLabel('Password') 34 | await page.getByLabel('Username').fill(uniqueUser); 35 | await page.getByLabel('Email').fill(`${uniqueUser}@example.com`); > 36 | await page.getByLabel('Password').fill('Password123!'); | ^ 37 | await page.getByLabel('Confirm Password').fill('Password123!'); 38 | await page.getByRole('button', { name: 'Create Account' }).click(); 39 | at /home/runner/work/Demo-Playwright-One/Demo-Playwright-One/tests/registration.spec.js:36:39
await page.getByLabel('Confirm Password').fill('Password123!');
await page.getByRole('button', { name: 'Create Account' }).click();

await expect(page).toHaveURL(/\/login/);

await page.getByLabel('Username').fill(uniqueUser);
await page.getByLabel('Password').fill('Password123!');
await page.getByRole('button', { name: 'Sign In' }).click();

await expect(page).toHaveURL(/\/dashboard/);
await expect(page.getByRole('heading', { name: 'Dashboard' })).toBeVisible();
});

test('invalid registration flow - should show error for duplicate username', async ({ page }) => {
await page.getByLabel('Username').fill(VALID_CREDENTIALS.username);
await page.getByLabel('Email').fill('new@example.com');
await page.getByLabel('Password').fill('Password123!');

Check failure on line 53 in tests/registration.spec.js

View workflow job for this annotation

GitHub Actions / Run Playwright Tests

[chromium] › tests/registration.spec.js:50:3 › Registration - E2E Tests › invalid registration flow - should show error for duplicate username

4) [chromium] › tests/registration.spec.js:50:3 › Registration - E2E Tests › invalid registration flow - should show error for duplicate username Error: locator.fill: Error: strict mode violation: getByLabel('Password') resolved to 2 elements: 1) <input required="" id="password" minlength="6" type="password" name="password" autocomplete="new-password" placeholder="Choose password"/> aka getByRole('textbox', { name: 'Password', exact: true }) 2) <input required="" type="password" id="confirmPassword" name="confirmPassword" autocomplete="new-password" placeholder="Confirm password"/> aka getByRole('textbox', { name: 'Confirm Password' }) Call log: - waiting for getByLabel('Password') 51 | await page.getByLabel('Username').fill(VALID_CREDENTIALS.username); 52 | await page.getByLabel('Email').fill('new@example.com'); > 53 | await page.getByLabel('Password').fill('Password123!'); | ^ 54 | await page.getByLabel('Confirm Password').fill('Password123!'); 55 | await page.getByRole('button', { name: 'Create Account' }).click(); 56 | at /home/runner/work/Demo-Playwright-One/Demo-Playwright-One/tests/registration.spec.js:53:39
await page.getByLabel('Confirm Password').fill('Password123!');
await page.getByRole('button', { name: 'Create Account' }).click();

await expect(page).toHaveURL(/\/register/);
await expect(page.getByRole('alert')).toContainText('Username already exists');
});

test('invalid registration flow - should show error when passwords do not match', async ({ page }) => {
await page.getByLabel('Username').fill('newuser');
await page.getByLabel('Email').fill('new@example.com');
await page.getByLabel('Password').fill('Password123!');
await page.getByLabel('Confirm Password').fill('Password456!');
await page.getByRole('button', { name: 'Create Account' }).click();

await expect(page).toHaveURL(/\/register/);
await expect(page.getByRole('alert')).toContainText('Passwords do not match');
});

test('invalid registration flow - should show error for short password', async ({ page }) => {
await page.getByLabel('Username').fill('newuser');
await page.getByLabel('Email').fill('new@example.com');
await page.getByLabel('Password').fill('12345');
await page.getByLabel('Confirm Password').fill('12345');
await page.getByRole('button', { name: 'Create Account' }).click();

await expect(page).toHaveURL(/\/register/);
await expect(page.getByRole('alert')).toContainText('at least 6 characters');
});

test('should have link to login page', async ({ page }) => {
await expect(page.getByRole('link', { name: 'Sign in' })).toBeVisible();
await page.getByRole('link', { name: 'Sign in' }).click();
await expect(page).toHaveURL(/\/login/);
});
});
Loading