TypeScript · @playwright/test
Government services with Playwright
A six-section application with autosaved drafts you can resume, split date-of-birth dropdowns, conditional fields, “same as present address”, document uploads, a verification code, appointment booking and ARN tracking.
App under test
🏛️ GovServe
- URL
- /apps/gov
- Login
- citizen@govserve.in / Gov@123
- Login OTP
- 5821
- Form verification code
- 7439
- Uploads
- PDF/JPG ≤ 2 MB · photo JPG ≤ 1 MB
- Offices
- weekdays only
Scenarios to automate
Work top to bottom — each one adds a new technique.
- 1
Citizen login + OTP
BeginnerEmail + password, then OTP 5821. Opening a deep link such as /apps/gov/status signed out shows the login in place and returns to that page after sign-in.
- 2
Section validation
Beginnersection-next on an empty section shows section-errors plus an error-* per field.
- 3
Date dropdowns
Intermediate31 Feb or a future date in dob-day/month/year shows error-dob.
- 4
Conditional field
Beginnermarital-status “Married” reveals spouse-name, which becomes required.
- 5
Copy address
Intermediatesame-address copies present into permanent fields and disables that fieldset.
- 6
Upload validation
IntermediateUpload a .txt or >2 MB file to address-proof-file to see the type/size error; valid files show *-name.
- 7
Autosave & resume
Advanceddraft-status goes “Saving draft…” → “✓ Draft saved”; save-exit, then resume-<id> restores the section and values.
- 8
Review & edit
IntermediateOn the last step, edit-section-N jumps back; review-* rows reflect your answers.
- 9
Appointment & tracking
AdvancedPick an office, a weekday and a free appointment-slot; then track the ARN on the status page.
Sample Playwright suite
A working starting point that finds elements every way Playwright can — by role, label, text, id, name, CSS, XPath and data-testid — so you practice them all. Pick your language, switch to data-testid only to compare, or try your own in the Locator Playground.
import { test, expect } from '@playwright/test';
// playwright.config.ts → use: { baseURL: 'https://www.practiceqaautomation.com' }
// Locators in this suite: getByRole ×6 · getByLabel ×9 · CSS ×9 · XPath ×4 · getByTestId ×16
test('applies for a passport and books an appointment', async ({ page }) => {
await page.goto('/apps/gov');
// Sign in first
await page.getByLabel('Email').fill('citizen@govserve.in');
await page.locator('#gs-password').fill('Gov@123');
await page.getByRole('button', { name: 'Continue' }).click();
await page.getByTestId('gs-code').fill('5821');
await page.locator('xpath=//button[normalize-space()="Verify & continue"]').click();
await page.getByRole('button', { name: 'Apply now' }).click();
await expect(page).toHaveURL(/\/apps\/gov\/apply\//);
// 1. Personal
await page.getByLabel('Given name').fill('Amir');
await page.locator('#surname').fill('Khan');
await page.getByTestId('dob-day').selectOption('15');
await page.getByRole('combobox', { name: 'Month' }).selectOption('8');
await page.locator('#dob-year').selectOption('1990');
await page.locator('xpath=//button[normalize-space()="Male"]').click();
await page.getByLabel('Place of birth').fill('Pune');
await page.getByTestId('marital-status').selectOption('married');
await page.locator('#spouse-name').fill('Sara Khan');
await page.getByTestId('section-next').click();
// 2. Address
await page.locator('#house').fill('12B');
await page.getByLabel('Street / area').fill('Palm Residency, Baner');
await page.getByTestId('city').fill('Pune');
await page.locator('#state').selectOption('Maharashtra');
await page.getByTestId('pincode').fill('411045');
await page.locator('#same-address').check();
await page.getByTestId('section-next').click();
// 3. Family, 4. Emergency contact
await page.locator('#father-name').fill('Imran Khan');
await page.getByTestId('mother-name').fill('Farah Khan');
await page.getByTestId('section-next').click();
await page.getByLabel('Name').fill('Sara Khan');
await page.getByLabel('Mobile').fill('9812345678');
await page.getByRole('combobox', { name: 'Relationship' }).selectOption('spouse');
await page.getByTestId('section-next').click();
// 5. Documents
await page.getByRole('combobox', { name: 'Proof of address' }).selectOption('aadhaar');
await page.getByLabel('Upload address proof').setInputFiles('fixtures/address-proof.pdf');
await page.getByLabel('Passport photo').setInputFiles('fixtures/photo.jpg');
await expect(page.getByTestId('photo-file-name')).toContainText('photo.jpg');
await page.getByTestId('section-next').click();
// 6. Review & submit
await expect(page.getByTestId('review-name')).toContainText('Amir Khan');
await page.locator('#declaration').check();
await page.getByLabel('Type the code').fill('7439');
await page.locator('xpath=//button[normalize-space()="Submit application"]').click();
await expect(page.getByTestId('arn')).toContainText('ARN-26');
await page.getByRole('combobox', { name: 'Passport office' }).selectOption('psk-pune');
await page.locator('[data-testid="appointment-day"]:not([disabled])').first().click();
await page.locator('[data-testid="appointment-slot"][data-available="true"]').first().click();
await page.locator('xpath=//button[normalize-space()="Confirm appointment"]').click();
await expect(page.getByTestId('appointment-receipt')).toBeVisible();
await expect(page.getByTestId('receipt-name')).toContainText('Amir Khan');
});