PracticeQAAutomation logoPracticeQAAutomation
Pw

TypeScript · @playwright/test

Education with Playwright

Sign up with live password rules or log in, enroll in a course, watch lessons to unlock “Mark complete”, finish the course to unlock a timed quiz, and earn a certificate.

App under test

🎓 LearnHub

URL
/apps/lms
Learner
learner@learnhub.dev
Password
Learn@123
Pass mark
60%

Scenarios to automate

Work top to bottom — each one adds a new technique.

  1. 1

    Sign-up validation

    Beginner

    password-strength updates as you type; a weak password, mismatched confirm or reused email each fail.

  2. 2

    Catalog filters

    Beginner

    Combine course-search, category-* chips and level-filter; assert course-count.

  3. 3

    Wait for enabled

    Intermediate

    mark-complete is disabled until play-video finishes (~1.5s) — wait for it to be enabled.

  4. 4

    Progress tracking

    Intermediate

    Each completed lesson updates course-progress and the lesson check marks; state survives reloads.

  5. 5

    Locked content

    Intermediate

    quiz-locked shows until 100%; visiting /quiz directly also shows the locked state.

  6. 6

    Mixed question types

    Intermediate

    Answer radio (q1-*), checkboxes (q2-*), a select (q3) and free text (q4).

  7. 7

    Unanswered confirm

    Advanced

    Submitting with blanks opens unanswered-modal; submit-anyway grades as wrong.

  8. 8

    Timer auto-submit

    Advanced

    Mock the clock past 5:00 and assert the quiz auto-submits to quiz-result.

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
learnhub.spec.ts
import { test, expect } from '@playwright/test';

// playwright.config.ts → use: { baseURL: 'https://www.practiceqaautomation.com' }
// Locators in this suite: getByRole ×5 · getByLabel ×4 · getByPlaceholder ×1 · CSS ×1 · XPath ×4 · getByTestId ×8
test('completes a course and earns a certificate', async ({ page }) => {
  await page.goto('/apps/lms');
  await page.getByLabel('Email').fill('learner@learnhub.dev');
  await page.locator('#login-password').fill('Learn@123');
  await page.getByRole('button', { name: 'Log in' }).click();
  await expect(page).toHaveURL(/\/apps\/lms\/courses/);
  await page.getByTestId('course-search').fill('Selenium');
  await expect(page.getByTestId('course-count')).toContainText('1 course');
  await page.locator('xpath=//button[normalize-space()="Enroll for free"]').click();
  await expect(page).toHaveURL(/\/apps\/lms\/course\/c1/);

  // Each lesson: play the video, then mark it complete (auto-advances)
  await page.getByRole('button', { name: 'Play video' }).click();
  await page.locator('xpath=//button[normalize-space()="Mark complete"]').click();
  await page.getByRole('button', { name: 'Play video' }).click();
  await page.locator('xpath=//button[normalize-space()="Mark complete"]').click();
  await page.getByRole('button', { name: 'Play video' }).click();
  await page.locator('xpath=//button[normalize-space()="Mark complete"]').click();
  await expect(page.getByTestId('course-progress')).toContainText('100%');
  await page.getByTestId('start-quiz').click();
  await page.getByLabel('An explicit wait for a condition').click();
  await page.getByLabel('A dedicated data-testid attribute').check();
  await page.getByLabel('ARIA role + accessible name').check();
  await page.getByTestId('q3').selectOption('frame');
  await page.getByPlaceholder('Type your answer', { exact: true }).fill('data-testid');
  await page.getByRole('button', { name: 'Submit answers' }).click();
  await expect(page.getByTestId('quiz-score')).toContainText('100%');
  await expect(page.getByTestId('certificate')).toBeVisible();
  await expect(page.getByTestId('certificate-id')).toContainText('LH-');
});

Practicing another tool?