PracticeQAAutomation logoPracticeQAAutomation
Pw

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. 1

    Citizen login + OTP

    Beginner

    Email + 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. 2

    Section validation

    Beginner

    section-next on an empty section shows section-errors plus an error-* per field.

  3. 3

    Date dropdowns

    Intermediate

    31 Feb or a future date in dob-day/month/year shows error-dob.

  4. 4

    Conditional field

    Beginner

    marital-status “Married” reveals spouse-name, which becomes required.

  5. 5

    Copy address

    Intermediate

    same-address copies present into permanent fields and disables that fieldset.

  6. 6

    Upload validation

    Intermediate

    Upload a .txt or >2 MB file to address-proof-file to see the type/size error; valid files show *-name.

  7. 7

    Autosave & resume

    Advanced

    draft-status goes “Saving draft…” → “✓ Draft saved”; save-exit, then resume-<id> restores the section and values.

  8. 8

    Review & edit

    Intermediate

    On the last step, edit-section-N jumps back; review-* rows reflect your answers.

  9. 9

    Appointment & tracking

    Advanced

    Pick 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.

Language
govserve.spec.ts
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');
});

Practicing another tool?