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
Scenarios to automate
Work top to bottom β each one adds a new technique.
- 1
Valid & invalid login
Beginnerdemo_user / Demo@123 succeeds; wrong password and empty fields show login-error.
- 2
Locked-out user
Beginnerlocked_user gets βSorry, this user has been locked out.β
- 3
Slow login
Intermediateslow_user takes ~3s β wait for the URL or product grid, never sleep.
- 4
Route guard
BeginnerVisiting /shop/cart signed out redirects to /shop.
- 5
Search, filter & sort
IntermediateAssert product-count text, no-results state, and that product-price values are sorted.
- 6
Cart badge & quantities
IntermediateAdd/remove from the grid, change qty in the cart, check line-total and totals maths.
- 7
Coupons
IntermediateSAVE10 = 10% off, FLAT20 = $20 off above $100, anything else is rejected.
- 8
Checkout validation
IntermediateSubmit empty to collect error-* messages; fix them one by one.
- 9
Declined card
Advanced4000 0000 0000 0002 shows payment-error; switch to Cash on delivery and succeed.
- 10
Order history
AdvancedOrder 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.
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));
});