PracticeQAAutomation logoPracticeQAAutomation
Pw

TypeScript · @playwright/test

Stock trading with Playwright

A watchlist with prices that tick every second, market and limit orders with buying-power, holdings and price-band checks, a confirm step, and a portfolio with live P&L. Simulated — no real money.

App under test

📊 TradeX

URL
/apps/trading
Login
TX1001 / Trade@123
Trading PIN
2468
Starting cash
₹5,00,000
Brokerage
₹20 / order
Limit band
±10% of LTP

Scenarios to automate

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

  1. 1

    Login + trading PIN

    Beginner

    Client ID + password (tx-login-id, tx-password, tx-login), then a 4-digit PIN (tx-code, tx-verify). Wrong details show attempts left in tx-login-error; 3 failures lock the form (tx-unlock).

  2. 2

    Asserting live data

    Intermediate

    price-* changes every second — assert format (₹ + 2 decimals) or that it changed, never an exact value.

  3. 3

    Search & watchlist

    Beginner

    symbol-search → add-<SYM> adds a watch-row; remove-<SYM> deletes it.

  4. 4

    Quantity validation

    Beginner

    0, decimals or text in order-qty show error-order-qty.

  5. 5

    Buying power

    Intermediate

    Order more than cash allows; the error tells you the affordable quantity.

  6. 6

    Limit band

    Intermediate

    A limit price more than 10% away from LTP is rejected in error-limit-price.

  7. 7

    Buy then sell

    Advanced

    Buy at market, then sell part of the holding; holding-qty-<SYM> and cash reconcile (with ₹20 brokerage).

  8. 8

    Open limit orders

    Advanced

    Place a limit order near LTP; it may fill on its own — poll order-status or cancel-<id> it.

  9. 9

    Sell more than held

    Beginner

    side-sell with a quantity above your holding shows “You only hold N share(s)”.

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

// playwright.config.ts → use: { baseURL: 'https://www.practiceqaautomation.com' }
// Locators in this suite: getByRole ×5 · getByLabel ×3 · CSS ×2 · XPath ×4 · getByTestId ×12
test('buys and partly sells a stock', async ({ page }) => {
  await page.goto('/apps/trading');

  // Sign in first
  await page.getByLabel('Client ID').fill('TX1001');
  await page.locator('#tx-password').fill('Trade@123');
  await page.getByRole('button', { name: 'Continue' }).click();
  await page.getByTestId('tx-code').fill('2468');
  await page.locator('xpath=//button[normalize-space()="Verify & continue"]').click();
  await expect(page.getByTestId('price-INFY')).toBeVisible();
  await page.locator('#symbol-search').fill('tata m');
  await page.getByTestId('add-TATAMOTORS').click();
  await expect(page.getByTestId('price-TATAMOTORS')).toBeVisible();
  await page.getByTestId('trade-INFY').click();
  await expect(page).toHaveURL(/\/apps\/trading\/trade\/INFY/);
  await page.getByRole('button', { name: 'Buy', exact: true }).click();
  await page.locator('xpath=//button[normalize-space()="MarketFill now at LTP"]').click();
  await page.getByLabel('Quantity').fill('10');
  await page.getByTestId('review-order').click();
  await expect(page.getByTestId('review-qty')).toContainText('10');
  await page.getByRole('button', { name: 'Confirm' }).click();
  await expect(page.getByTestId('order-result')).toContainText('Filled');
  await page.locator('xpath=//a[normalize-space()="Portfolio"]').click();
  await expect(page.getByTestId('holding-qty-INFY')).toContainText('10');

  // Sell part of the position
  await page.getByRole('link', { name: 'Sell' }).click();
  await page.getByLabel('Quantity').fill('4');
  await page.getByTestId('review-order').click();
  await page.getByRole('button', { name: 'Confirm' }).click();
  await expect(page.getByTestId('order-result')).toContainText('Sold 4 INFY');
  await page.locator('xpath=//a[normalize-space()="Portfolio"]').click();
  await expect(page.getByTestId('holding-qty-INFY')).toContainText('6');
});

Practicing another tool?