PAPracticeAutomation
Pw

TypeScript Β· @playwright/test

E-commerce with Playwright

Automate a full shopping journey β€” login, catalogue, cart, coupons, checkout and order history.

App under test

Nova Shop

URL
/shop
User
demo_user
Password
Demo@123
Coupons
SAVE10 Β· FLAT20
Declined card
4000 0000 0000 0002
Launch Nova Shop β†’

Scenarios to automate

Work top to bottom β€” each one adds a new technique.

  1. 1

    Valid & invalid login

    Beginner

    demo_user / Demo@123 succeeds; wrong password and empty fields show login-error.

  2. 2

    Locked-out user

    Beginner

    locked_user gets β€œSorry, this user has been locked out.”

  3. 3

    Slow login

    Intermediate

    slow_user takes ~3s β€” wait for the URL or product grid, never sleep.

  4. 4

    Route guard

    Beginner

    Visiting /shop/cart signed out redirects to /shop.

  5. 5

    Search, filter & sort

    Intermediate

    Assert product-count text, no-results state, and that product-price values are sorted.

  6. 6

    Cart badge & quantities

    Intermediate

    Add/remove from the grid, change qty in the cart, check line-total and totals maths.

  7. 7

    Coupons

    Intermediate

    SAVE10 = 10% off, FLAT20 = $20 off above $100, anything else is rejected.

  8. 8

    Checkout validation

    Intermediate

    Submit empty to collect error-* messages; fix them one by one.

  9. 9

    Declined card

    Advanced

    4000 0000 0000 0002 shows payment-error; switch to Cash on delivery and succeed.

  10. 10

    Order history

    Advanced

    Order id on the success page must appear in orders-table after navigation.

Sample Playwright suite

A working starting point written against this app's real data-testids.

shop.spec.ts
import { test, expect } from '@playwright/test';

test.beforeEach(async ({ page }) => {
  await page.goto('/shop');
  await page.getByTestId('username').fill('demo_user');
  await page.getByTestId('password').fill('Demo@123');
  await page.getByTestId('login-button').click();
  await expect(page).toHaveURL(/\/shop\/products/);
});

test('buy headphones with a coupon', async ({ page }) => {
  await page.getByTestId('search-input').fill('headphones');
  await expect(page.getByTestId('product-card')).toHaveCount(1);
  await page.getByTestId('add-to-cart-p1').click();
  await expect(page.getByTestId('cart-badge')).toHaveText('1');

  await page.getByTestId('cart-link').click();
  await page.getByTestId('coupon-input').fill('SAVE10');
  await page.getByTestId('apply-coupon').click();
  await expect(page.getByTestId('discount')).toContainText('$13.00');

  await page.getByTestId('checkout-button').click();
  await page.getByTestId('first-name').fill('Ada');
  await page.getByTestId('last-name').fill('Lovelace');
  await page.getByTestId('email').fill('ada@example.com');
  await page.getByTestId('phone').fill('5551234567');
  await page.getByTestId('address').fill('1 Analytical Way');
  await page.getByTestId('city').fill('Austin');
  await page.getByTestId('state').selectOption('Texas');
  await page.getByTestId('zip').fill('73301');
  await page.getByTestId('card-name').fill('Ada Lovelace');
  await page.getByTestId('card-number').fill('4242424242424242');
  await page.getByTestId('card-expiry').fill('12/30');
  await page.getByTestId('card-cvv').fill('123');
  await page.getByTestId('accept-terms').check();
  await page.getByTestId('place-order').click();

  // Placing the order takes ~2s β€” web-first assertions wait for it.
  await expect(page.getByTestId('order-success')).toBeVisible();
  await expect(page.getByTestId('order-id')).toHaveText(/^NS-\d+$/);
});

test('sorts by price, low to high', async ({ page }) => {
  await page.getByTestId('sort-select').selectOption('price-asc');
  const prices = (await page.getByTestId('product-price').allTextContents())
    .map((p) => Number(p.replace('$', '')));
  expect(prices).toEqual([...prices].sort((a, b) => a - b));
});

Practising another tool?