RizTech Academy logo
RizTech Academy
Web Automation with PlaywrightLesson 1 of 630 min

Playwright: setup and your first test

Time to write automated tests that drive a real browser. The tool this course uses is Playwright — a modern framework, made by Microsoft, that controls Chromium, Firefox and WebKit from one API and was designed from the start to avoid the flakiness that ruined older UI-automation tools. Over this module you will automate the AgentPay console (the reference app — see the repo linked on the course page) end to end. This lesson gets Playwright installed and your first test running and green.

Why Playwright

You met the alternatives' pain in the automation-strategy module: UI tests that are slow and flaky. Playwright was built to fix exactly that:

  • Auto-waiting — it waits for an element to be ready (visible, enabled, stable) before acting, and for a condition to hold before asserting, so you almost never write a manual wait (the actions lesson). This removes the single biggest cause of flakiness.
  • Cross-browser from one API — the same test runs on Chromium, Firefox and WebKit, so your suite catches the cross-browser breakage the web-testing module warned about, automatically.
  • Great debugging — traces, screenshots and videos of a failure, and a UI mode to step through tests (the traces lesson).
  • Web-first assertions — expect(locator).toHaveText(...) retries until it passes or times out, instead of checking once.

It is not the only good tool (Cypress is a common alternative), but it is an excellent default and what this course teaches.

Installing it

Playwright needs Node.js (the JavaScript runtime). In a project you can add it with npm:

npm init playwright@latest

That command scaffolds everything: it installs @playwright/test, downloads the browser binaries, and creates a playwright.config.ts and an example test. Answer its prompts (TypeScript, a tests folder, yes to browsers). If you are adding Playwright to an existing project (as the AgentPay repo does), you instead add the dependency and run npx playwright install chromium to fetch just the browser you need.

Check it worked:

npx playwright test --list

Your first test

A Playwright test lives in a .spec.ts file in the tests folder. Here is the shape, testing that the AgentPay login page loads:

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

test('the login page shows the sign-in form', async ({ page }) => {
  await page.goto('/login');
  await expect(page.getByRole('heading', { name: 'Sign in to AgentPay' })).toBeVisible();
});

Three things to notice:

  • async and await. Browser actions take time, so every one returns a promise you await. Forgetting an await is the most common beginner mistake — the action fires but the test races ahead. Always await.
  • page is the browser tab, handed to you by the { page } fixture (the fixtures lesson). You navigate and act through it.
  • getByRole(...) finds the heading the way a user (or a screen reader) would — by its role and name, not a brittle CSS selector (the locators lesson, next).

Run it:

npx playwright test

You should see it pass. Run npx playwright test --headed to watch the browser do it, which is worth doing once to see what is happening.

The config, and a base URL

playwright.config.ts holds settings for the whole suite. The two that matter most early:

  • baseURL — set it (e.g. http://localhost:5173) and then page.goto('/login') is relative to it, so you do not repeat the host and can point the whole suite at a different environment by changing one line (the test-environments lesson).

  • webServer — Playwright can start your app before the tests and stop it after. AgentPay's config uses this to boot both the API and the web dashboard, so npm run test:e2e is entirely self-contained — you do not start servers by hand:

    webServer: [
      { command: 'npm --prefix ../api run start', port: 4000 },
      { command: 'npm run dev', port: 5173 },
    ],
    

This is a real convenience and a reliability win: the suite always runs against a known, freshly started app, the same way locally and in CI (the CI module).

What you have

A working Playwright setup: the framework and a browser installed, a config with a base URL and (for AgentPay) auto-started servers, and a first passing test that navigates and asserts with a user-facing locator. Everything else in this module — robust locators, actions, assertions, page objects, fixtures, debugging — builds on this loop: goto, act, expect. Keep the app's dev servers understood, and always await.

Check your work

Why Playwright. Auto-waiting (waits for readiness before acting/asserting — kills the top flakiness cause), cross-browser from one API (Chromium/Firefox/WebKit), strong debugging (traces/screenshots/UI mode), and web-first retrying assertions. An excellent default, not the only tool.

Install. npm init playwright@latest scaffolds deps + browsers + config + an example; in an existing project add @playwright/test and npx playwright install. Verify with npx playwright test --list.

First test. A .spec.ts with test('...', async ({ page }) => { ... }); await every action (missing await is the classic bug); page is the tab; assert with a user-facing locator (getByRole). Run with npx playwright test (add --headed to watch).

Config. baseURL makes goto relative and lets you retarget environments in one place; webServer starts your app (AgentPay boots both API and web) so the suite is self-contained and identical locally and in CI.

Practice

  1. Install Playwright in a scratch project with npm init playwright@latest and run the example test.
  2. Clone the AgentPay repo, npm install, and run npm run test:e2e; watch it start the servers and run.
  3. Write a test that opens /login and asserts the heading is visible; run it headed to watch the browser.
  4. Break it on purpose (assert a heading that does not exist) and read how Playwright reports the failure.
  5. Add a console.log(await page.title()) after goto and confirm the page title; remove it after.
  6. Find baseURL and webServer in AgentPay's playwright.config.ts and explain what each does.

Official documentation

Next: locators — finding elements the robust way.

Stuck on this lesson?

Being stuck is part of it — but being stuck alone for three days is not. Our internship programme pairs this curriculum with code review and one-to-one help from working developers, and it is free.

About the internship