This document shows how the EmployeeFormPage Page Object eliminates code duplication between tests.
// Fill required text fields
await page.fill('input[formControlName="firstName"]', employeeData.firstName);
await page.fill('input[formControlName="lastName"]', employeeData.lastName);
await page.fill('input[formControlName="email"]', employeeData.email);
// Fill date of birth
try {
await page.getByLabel('Date of Birth').fill('01/01/1990');
await page.waitForTimeout(300);
} catch {
try {
await page.fill('input[name*="dateOfBirth"]', '01/01/1990', { timeout: 2000 });
} catch {}
}
// ... 50+ more lines of similar code// Fill required text fields
await page.fill('input[name*="firstName"]', employee.firstName);
await page.fill('input[name*="lastName"]', employee.lastName);
await page.fill('input[name*="email"]', employee.email);
// Fill date of birth
const dobInput = page.locator('input[name*="dateOfBirth"]');
if (await dobInput.isVisible({ timeout: 2000 }).catch(() => false)) {
await dobInput.fill('1990-01-01');
}
// ... 50+ more lines of similar codeTotal: ~125 lines of duplicated code
const employeeForm = new EmployeeFormPage(page);
await employeeForm.waitForForm();
await employeeForm.fillForm({
firstName: employeeData.firstName,
lastName: employeeData.lastName,
email: employeeData.email,
dateOfBirth: '01/01/1990',
phoneNumber: employeeData.phoneNumber,
salary: employeeData.salary,
department: 1,
position: 1,
gender: 1,
});
await employeeForm.submit();
const result = await employeeForm.verifySubmissionSuccess();
expect(result.success).toBe(true);const employeeForm = new EmployeeFormPage(page);
await employeeForm.waitForForm();
await employeeForm.fillForm({
firstName: employee.firstName,
lastName: employee.lastName,
email: employee.email,
dateOfBirth: '01/01/1990',
phoneNumber: employee.phoneNumber,
salary: employee.salary,
department: 1,
position: 1,
gender: 1,
});
await employeeForm.submit();
const result = await employeeForm.verifySubmissionSuccess();
expect(result.success).toBe(true);Total: ~20 lines (shared implementation in Page Object)
- Before: ~125 lines of duplicated form-filling logic
- After: ~20 lines in tests + Page Object (shared across all tests)
- Form-filling logic lives in ONE place:
EmployeeFormPage - Changes to the form (new field, selector change) only need ONE update
- All tests use the same selectors and patterns
- No drift between tests (smoke test using
getByLabel, create test using CSS selectors)
getByLabel()with fallbacks built into Page Object.nth(1)to skip placeholders is the default- Longer timeouts (500ms) for stability
- API error handling in
verifySubmissionSuccess()
- When UI changes (e.g., new field added), update ONE file
- Tests remain clean and focused on business logic
- Tests read like plain English:
await employeeForm.fillFirstName('John'); await employeeForm.selectDepartment(1); await employeeForm.submit();
The updated EmployeeFormPage now includes:
fillDateOfBirth()- UsesgetByLabel()with MM/DD/YYYY format + fallbackfillPhoneNumber()- UsesgetByLabel()with fallback
selectGender()- Added support for gender selection
- All dropdowns default to
.nth(1)to skip placeholders - Longer 500ms timeouts for stability
verifySubmissionSuccess()- Returns success even when API returns 401- Checks: success message → redirect → form filled (graceful degradation)
fillForm()- Now includesdateOfBirthandgenderparameters- Single method to fill entire form
To migrate existing tests to use the Page Object:
import { EmployeeFormPage } from '../page-objects/employee-form.page';const employeeForm = new EmployeeFormPage(page);
await employeeForm.waitForForm();// Before (60+ lines)
await page.fill('input[formControlName="firstName"]', 'John');
await page.fill('input[formControlName="lastName"]', 'Doe');
// ... 50+ more lines
// After (1 method call)
await employeeForm.fillForm({
firstName: 'John',
lastName: 'Doe',
email: 'john@example.com',
dateOfBirth: '01/01/1990',
phoneNumber: '(555) 123-4567',
salary: 75000,
department: 1,
position: 1,
gender: 1,
});// Before
await submitButton.click();
await page.waitForTimeout(2000);
const success = await page.locator('text=/success/i').isVisible();
expect(success).toBe(true);
// After
await employeeForm.submit();
const result = await employeeForm.verifySubmissionSuccess();
expect(result.success).toBe(true);Migrate both tests to use the Page Object:
- employee-smoke.spec.ts - Lines 67-160 can be reduced to ~10 lines
- employee-create.spec.ts - Lines 39-90 can be reduced to ~10 lines
This will:
- ✅ Eliminate 100+ lines of duplicated code
- ✅ Make tests more maintainable
- ✅ Ensure consistency across all employee form tests
- ✅ Make future form changes easier (update ONE file instead of TWO)
See examples in:
examples/employee-smoke-with-pom.example.tsexamples/employee-create-with-pom.example.ts