testing php applications

Browser And End-To-End Testing Orientation

Browser tests run the application through a real browser. They can catch broken JavaScript, forms, navigation, focus, rendering, and integration behaviour that lower-level tests cannot see. They are slower and more fragile, so keep them focused.

Automate Critical Journeys

Good candidates include login, checkout, registration, password reset, and key administrative workflows. Use accessible roles, labels, and stable test IDs rather than selectors coupled to CSS layout.

Debug With Evidence

Browser tooling can preserve screenshots, traces, videos, and console output. Use deterministic seed data and clean isolation so a failure can be reproduced locally and in CI.

import { test, expect } from '@playwright/test';

test('customer can sign in', async ({ page }) => {
  await page.goto('/login');
  await page.getByLabel('Email').fill('amo@example.com');
  await page.getByLabel('Password').fill('correct-password');
  await page.getByRole('button', { name: 'Sign in' }).click();
  await expect(page.getByRole('heading', { name: 'Your account' })).toBeVisible();
});

Common Mistakes

  • Automating every small rule through the browser.
  • Using brittle selectors tied to styling.
  • Sharing test accounts and dirty data.
  • Ignoring traces and console errors after failure.

What To Practise

  • Choose browser-worthy journeys.
  • Use stable accessible selectors.
  • Keep browser data deterministic.

Practice

Practice: Outline A Checkout Browser Test

Write a browser-test outline for placing a simple order.

Requirements

  • Seed one purchasable product and test customer.
  • Use roles or labels for actions.
  • Assert an order confirmation visible to the user.
  • Keep price calculation checks at lower levels too.
Show solution

The browser journey proves wiring, not every pricing edge case.

import { test, expect } from '@playwright/test';

test('customer places an order', async ({ page }) => {
  await page.goto('/products/desk-lamp');
  await page.getByRole('button', { name: 'Add to basket' }).click();
  await page.getByRole('link', { name: 'Basket' }).click();
  await page.getByRole('button', { name: 'Checkout' }).click();
  await expect(page.getByRole('heading', { name: 'Order confirmed' })).toBeVisible();
});

Seed data and authentication setup depend on the project, but the journey stays short and user-visible.