TypeScript · @playwright/test
Healthcare with Playwright
Pick a specialty, filter doctors, choose a day (Sundays closed) and a free time slot, fill new or existing patient details, then reschedule or cancel.
App under test
🩺 MediCare+
- URL
- /apps/clinic
- Existing patient
- P-1001
- Video consult
- 20% off
- Closed
- Sundays
Scenarios to automate
Work top to bottom — each one adds a new technique.
- 1
Specialty & filters
BeginnerToggle specialty-*, combine filter-gender, filter-fee and filter-available-today; assert doctor-count.
- 2
Sort order
Intermediatesort-doctors “Lowest fee” must order doctor-fee values ascending.
- 3
Disabled dates
IntermediateSunday chips in appointment-day are disabled; pick the first enabled day with :not([disabled]).
- 4
Booked slots
IntermediateSlots with data-available="false" are disabled; choose a free one and check slot-summary.
- 5
Existing patient lookup
Intermediatepatient-existing + P-1001 shows patient-found; any other ID shows patient-not-found.
- 6
Conditional insurance fields
Beginnerhas-insurance reveals insurance-provider and policy-number, both validated.
- 7
Reschedule
AdvancedMove an appointment in reschedule-modal and assert appointment-slot changed.
- 8
Cancel
Advancedcancel-appt-<id> → confirm-cancel-appointment sets appointment-status to Cancelled.
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 ×2 · getByLabel ×3 · CSS ×3 · XPath ×1 · getByTestId ×9
test('books a video consultation', async ({ page }) => {
await page.goto('/apps/clinic');
await page.getByTestId('specialty-cardiology').click();
await expect(page.getByTestId('doctor-count')).toContainText('2 doctors');
await page.getByTestId('book-doctor').nth(0).click();
await expect(page.getByTestId('doctor-title')).toContainText('Ananya Rao');
await page.getByTestId('type-video').click();
// First open day (Sundays are disabled), then the first free slot
await page.locator('[data-testid="appointment-day"]:not([disabled])').first().click();
await page.locator('[data-testid="slot"][data-available="true"]').first().click();
await expect(page.getByTestId('slot-summary')).toContainText('Video');
await page.getByRole('button', { name: 'Continue' }).click();
await page.getByTestId('patient-new').click();
await page.getByLabel('Full name').fill('Amir Khan');
await page.locator('#patient-age').fill('36');
await page.getByRole('combobox', { name: 'Gender' }).selectOption('male');
await page.getByLabel('Phone').fill('9876543210');
await page.locator('#patient-email').fill('amir@example.com');
await page.getByLabel('Symptoms / reason for visit').fill('Occasional chest discomfort after exercise');
await page.locator('#consent').check();
await page.locator('xpath=//button[normalize-space()="Confirm appointment"]').click();
await expect(page.getByTestId('appointment-confirmed')).toBeVisible();
await expect(page.getByTestId('appointment-id')).toContainText('APT-');
await expect(page.getByTestId('appointment-type')).toContainText('Video consult');
});