PracticeQAAutomation logoPracticeQAAutomation
Pw

TypeScript · @playwright/test

Logistics with Playwright

Pincode serviceability lookups that auto-fill the city, volumetric vs chargeable weight maths, service rules, COD limits, a barcode label and a live tracking timeline.

App under test

📦 ShipFast

URL
/apps/logistics
Pincodes
400001, 560001, 110001…
Demo AWB
SF1234567890
COD limit
₹20,000

Scenarios to automate

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

  1. 1

    Pincode lookup

    Beginner

    After 6 digits a spinner runs, then sender-city shows the city; unknown pincodes show “Not serviceable”.

  2. 2

    Weight maths

    Intermediate

    30×20×15 cm → volumetric-weight 1.8 kg; chargeable-weight is the higher value rounded up to 0.5 kg.

  3. 3

    Service rules

    Intermediate

    service-same-day is disabled unless both pincodes are in the same city.

  4. 4

    COD limit

    Intermediate

    Declared value above ₹20,000 with pay-cod shows error-payment.

  5. 5

    Live quote

    Beginner

    freight-charge and shipment-total update as weight, service, insurance and payment change.

  6. 6

    Label & barcode

    Intermediate

    awb-number is SF + 10 digits; download-label saves a text file named after it.

  7. 7

    Polling a timeline

    Advanced

    A new shipment's current-status moves Booked → Picked up → In transit every ~4s; wait for text.

  8. 8

    Unknown AWB

    Beginner

    Tracking a random AWB shows track-error; SF1234567890 shows a delivered journey.

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

// playwright.config.ts → use: { baseURL: 'https://www.practiceqaautomation.com' }
// Locators in this suite: getByRole ×1 · getByLabel ×4 · CSS ×7 · XPath ×1 · getByTestId ×14
test('books and tracks a shipment', async ({ page }) => {
  await page.goto('/apps/logistics');
  await page.getByTestId('ship-now').click();
  await expect(page).toHaveURL(/\/apps\/logistics\/ship/);
  await page.locator('#sender-name').fill('Amir Khan');
  await page.locator('#sender-phone').fill('9876543210');
  await page.getByTestId('sender-pincode').fill('400001');
  await expect(page.locator('#sender-city')).toContainText('Mumbai');
  await page.getByTestId('sender-address').fill('12 Marine Drive, Churchgate');
  await page.locator('#receiver-name').fill('Sara Khan');
  await page.getByTestId('receiver-phone').fill('9812345678');
  await page.locator('#receiver-pincode').fill('560001');
  await expect(page.getByTestId('receiver-city')).toContainText('Bengaluru');
  await page.locator('#receiver-address').fill('44 MG Road, Ashok Nagar');
  await page.getByTestId('package-parcel').click();
  await page.getByLabel('Weight (kg)').fill('2');
  await page.getByLabel('Length (cm)').fill('30');
  await page.getByLabel('Width (cm)').fill('20');
  await page.getByLabel('Height (cm)').fill('15');
  await expect(page.getByTestId('volumetric-weight')).toContainText('1.8 kg');
  await expect(page.getByTestId('chargeable-weight')).toContainText('2 kg');
  await page.locator('#declared-value').fill('2500');
  await page.getByTestId('service-express').click();
  await page.getByTestId('pay-prepaid').click();
  await expect(page.getByTestId('shipment-total')).toContainText('220.00');
  await page.getByRole('button', { name: 'Book shipment' }).click();
  await expect(page.getByTestId('shipment-booked')).toBeVisible();
  await expect(page.getByTestId('awb-number')).toContainText('SF');
  await page.locator('xpath=//a[normalize-space()="Track shipment"]').click();
  await expect(page.getByTestId('tracking-result')).toContainText('Mumbai → Bengaluru');
});

Practicing another tool?