PracticeQAAutomation logoPracticeQAAutomation
Pw

TypeScript · @playwright/test

Media streaming with Playwright

Pick a profile (Kids hides mature titles), browse scrolling rows, save to My List, and drive a custom player — play/pause, seek, ±10s, speed, volume, subtitles, skip intro — with progress that feeds “Continue watching”.

App under test

▶️ StreamBox

URL
/apps/stream
Login
viewer@streambox.tv / Stream@123
Profiles
Amir · Sara · Kids
Skip intro
shown 0:03–0:30
Plans
Basic · Standard · Premium

Scenarios to automate

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

  1. 1

    Account login

    Beginner

    Email + password (sb-login-id, sb-password, sb-login) before the profile picker; sb-logout returns to the login.

  2. 2

    Profile gate

    Beginner

    No profile → profile-picker; switch-profile returns to it. Kids hides A/UA titles and restricts /watch.

  3. 3

    Unique row locators

    Intermediate

    A title can appear in several rows, so cards are open-<row>-<id> (e.g. open-trending-t3).

  4. 4

    Player state

    Intermediate

    player-toggle flips aria-label Play/Pause and data-playing on player; player-time advances.

  5. 5

    Transient button

    Advanced

    skip-intro only exists between 0:03 and 0:30 — wait for it, click, and assert the time jumped to 0:30.

  6. 6

    Range sliders

    Intermediate

    Drive player-seek and player-volume (fill / keyboard / JS); mute toggles the volume to 0.

  7. 7

    Continue watching

    Advanced

    Watch a bit, go home: row-continue shows the title with a progress bar.

  8. 8

    Reorder a list

    Intermediate

    In My List, move-up/down-<id> or drag mylist-item to reorder; order persists.

  9. 9

    Plan change modal

    Beginner

    choose-<plan> shows an upgrade or downgrade note; confirm-plan updates current-plan.

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

// playwright.config.ts → use: { baseURL: 'https://www.practiceqaautomation.com' }
// Locators in this suite: getByRole ×3 · getByLabel ×1 · CSS ×1 · XPath ×2 · getByTestId ×14
test('watches a title and resumes it', async ({ page }) => {
  await page.goto('/apps/stream');

  // Sign in first
  await page.getByLabel('Email').fill('viewer@streambox.tv');
  await page.locator('#sb-password').fill('Stream@123');
  await page.getByRole('button', { name: 'Sign in' }).click();
  await page.getByTestId('profile-amir').click();
  await expect(page.getByTestId('active-profile')).toContainText('Amir');
  await page.getByTestId('open-trending-t3').click();
  await expect(page.getByTestId('title-modal')).toBeVisible();
  await page.getByTestId('mylist-t3').click();
  await expect(page.getByTestId('mylist-t3')).toContainText('In My List');
  await page.getByTestId('play-t3').click();
  await expect(page.getByTestId('watch-title')).toContainText('Orbit Nine');
  await page.getByRole('combobox', { name: 'Playback speed' }).selectOption('2');
  await page.getByTestId('player-toggle').click();

  // Skip intro appears a moment after playback starts
  await page.locator('xpath=//button[normalize-space()="Skip intro"]').click();
  await expect(page.getByTestId('player-time')).toContainText('00:3');
  await page.getByTestId('player-toggle').click();
  await page.getByTestId('skip-forward-10').click();
  await expect(page.getByTestId('player-time')).toContainText('00:4');
  await page.locator('xpath=//a[normalize-space()="Home"]').click();
  await expect(page.getByTestId('row-continue')).toContainText('Orbit Nine');
  await page.getByRole('link', { name: 'My List' }).click();
  await expect(page.getByTestId('mylist-item').nth(0)).toContainText('Orbit Nine');
});

Practicing another tool?