PracticeQAAutomation logoPracticeQAAutomation
Pw

TypeScript · @playwright/test

Manufacturing with Playwright

A live machine dashboard with status filters and OEE meters, work orders whose bill of materials is checked against stock (shortages block release), a start → complete lifecycle, and quality inspection with tolerance-based pass/fail.

App under test

⚙️ FactoryOS

URL
/apps/factory
Impeller stock
40 units
QC spec
25.00 ± 0.05 mm …
WO numbers
WO-1001 …

Scenarios to automate

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

  1. 1

    Changing data

    Intermediate

    machine-card data-status changes every ~4s; assert counts add up (count-*) rather than specific states.

  2. 2

    Meters

    Beginner

    oee-* use role=meter with aria-valuenow; avg-oee is the mean of all machines.

  3. 3

    BOM maths

    Intermediate

    Pump × 50 → required-bearing 100, required-impeller 50 (stock 40) → shortage-impeller shows −10.

  4. 4

    Blocked action

    Intermediate

    release-wo with a shortage shows wo-error naming the part; wo-qty-dec10 clears it (materials-ok).

  5. 5

    Lifecycle

    Beginner

    start-<id> → In progress → complete-<id> → Completed; buttons change with status.

  6. 6

    Tolerance checks

    Advanced

    25.06 mm fails (Out of tolerance) while 25.05 passes; any defect checkbox forces FAIL.

  7. 7

    Incomplete inspection

    Beginner

    submit-inspection before all measurements shows qc-error; qc-result stays Pending.

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

// playwright.config.ts → use: { baseURL: 'https://www.practiceqaautomation.com' }
// Locators in this suite: getByRole ×5 · getByLabel ×1 · CSS ×4 · XPath ×4 · getByTestId ×11
test('releases a work order and passes QC', async ({ page }) => {
  await page.goto('/apps/factory');
  await expect(page.getByTestId('machine-grid')).toBeVisible();
  await page.getByRole('link', { name: 'Work orders' }).click();
  await page.getByTestId('new-work-order').click();
  await page.getByLabel('Product', { exact: true }).selectOption('pump');
  await page.locator('#wo-qty').fill('50');
  await expect(page.getByTestId('required-impeller')).toContainText('50');
  await expect(page.getByTestId('shortage-impeller')).toContainText('−10');
  await page.locator('xpath=//button[normalize-space()="Release work order"]').click();
  await expect(page.getByTestId('wo-error')).toContainText('Impeller');
  await page.getByTestId('wo-qty-dec10').click();
  await expect(page.getByTestId('materials-ok')).toBeVisible();
  await page.getByRole('combobox', { name: 'Production line' }).selectOption('Line B');
  await page.getByTestId('wo-due').nth(3).click();
  await page.locator('xpath=//button[normalize-space()="Urgent"]').click();
  await page.locator('xpath=//button[normalize-space()="Release work order"]').click();
  await expect(page.getByTestId('wo-status-WO-1001')).toContainText('Released');
  await page.getByRole('button', { name: 'Start' }).click();
  await page.getByRole('button', { name: 'Complete' }).click();
  await expect(page.getByTestId('wo-status-WO-1001')).toContainText('Completed');
  await page.locator('xpath=//a[normalize-space()="Quality"]').click();
  await page.locator('#qc-diameter').fill('25.02');
  await page.locator('#qc-length').fill('119.9');
  await page.locator('#qc-weight').fill('2.43');
  await expect(page.getByTestId('qc-result')).toContainText('PASS');
  await page.getByRole('button', { name: 'Record inspection' }).click();
  await expect(page.getByTestId('inspection-id')).toContainText('QC-');
});

Practicing another tool?