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
Pincode lookup
BeginnerAfter 6 digits a spinner runs, then sender-city shows the city; unknown pincodes show “Not serviceable”.
- 2
Weight maths
Intermediate30×20×15 cm → volumetric-weight 1.8 kg; chargeable-weight is the higher value rounded up to 0.5 kg.
- 3
Service rules
Intermediateservice-same-day is disabled unless both pincodes are in the same city.
- 4
COD limit
IntermediateDeclared value above ₹20,000 with pay-cod shows error-payment.
- 5
Live quote
Beginnerfreight-charge and shipment-total update as weight, service, insurance and payment change.
- 6
Label & barcode
Intermediateawb-number is SF + 10 digits; download-label saves a text file named after it.
- 7
Polling a timeline
AdvancedA new shipment's current-status moves Booked → Picked up → In transit every ~4s; wait for text.
- 8
Unknown AWB
BeginnerTracking 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.
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');
});