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:
asyncandawait. Browser actions take time, so every one returns a promise youawait. Forgetting anawaitis the most common beginner mistake — the action fires but the test races ahead. Always await.pageis 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 thenpage.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, sonpm run test:e2eis 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
- Install Playwright in a scratch project with
npm init playwright@latestand run the example test. - Clone the AgentPay repo,
npm install, and runnpm run test:e2e; watch it start the servers and run. - Write a test that opens
/loginand asserts the heading is visible; run it headed to watch the browser. - Break it on purpose (assert a heading that does not exist) and read how Playwright reports the failure.
- Add a
console.log(await page.title())aftergotoand confirm the page title; remove it after. - Find
baseURLandwebServerin AgentPay'splaywright.config.tsand explain what each does.
Official documentation
- Playwright — Installation — Setting up Playwright and its browsers.
- Playwright — Writing tests — The test/expect API and the first test.
- Playwright — Test configuration —
baseURL,webServerand the config file.
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