Before you write anything, you need one picture in your head. Everything else in Playwright follows from it, and people who skip this spend weeks confused about missing await keywords.
A Playwright test is a Node.js program that remote-controls a real browser. Your code runs in one process. Chrome (or Firefox, or WebKit) runs in another. Playwright sends it commands and waits for answers.
That one fact explains the thing you will type most: await.
import { test, expect } from '@playwright/test';
test('loads the login page', async ({ page }) => {
await page.goto('/');
await page.getByRole('button', { name: 'Sign in' }).click();
});
Every command crosses over to the browser and comes back. await is how your test waits for that trip to finish.
Forget one await and your test runs ahead of the browser. This is one of the very few ways to make a Playwright test unstable, and it is the first thing I check when a junior shows me a test that fails at random.
The other things this model gives you:
{ page }is a fixture. Playwright builds a fresh, isolated browser page for every test and hands it in. No test can see another test's cookies, storage or state. That is why a Playwright test that passes alone passes anywhere. Isolation is the default, not something you build.- Actions auto-wait.
click()waits until the element exists, is visible and is enabled before clicking, up to a timeout. You almost never write "wait for X, then click X"; the click is the wait. - Assertions retry.
await expect(locator).toHaveText('1')polls the page until it is true or time runs out. More on this in the assertions lecture. It is the reason good Playwright tests contain no sleeps.
So the habit is simple: await everything that touches the page. If you use TypeScript, your editor will warn you about a missing await. Listen to it.
The official tour of this model: Writing tests.
No problem for this one. It is the mental model the rest of the track stands on. The next lecture writes your first real test.