Every test is made of two things: actions and checks. You have seen checks already. Now let's cover the actions, because these four will handle almost everything a real user does:
await page.getByLabel('Email').fill('demo@nimbus.app'); // set a field's value
await page.getByRole('button', { name: 'Sign in' }).click(); // click
await page.getByTestId('status-filter').selectOption('Customer'); // choose from a <select>
await page.getByLabel('I agree').check(); // tick a checkbox
Before any action runs, Playwright performs actionability checks: the element must exist, be visible, be stable (not mid-animation), and be enabled. The action retries these checks up to the timeout, then acts. Two consequences:
- You do not write "wait for the button, then click". The click is the wait.
- If the click fails because a modal covers the button, that is what a user would hit too. An actionability failure is often a real finding about the app, not a flaw in your test.
A few details that will save you time:
fill()replaces the field's value (unlike typing, which appends). For most forms,fillis what you want.pressSequentially()exists for the rare case where the app reacts to each keystroke.press('Enter')submits many forms:await page.getByLabel('Password').press('Enter').- Actions need one element. If your locator matches several, Playwright fails with a strict-mode violation instead of guessing. Narrow it with a better locator, or use
.first()when any match is truly fine. - Actions are user intent. If a user cannot do it with mouse and keyboard, a plain action is the wrong tool.
The full list and the checks behind them: Actions and Auto-waiting.
The problem below is pure actions-and-assertions: remove the last item from the cart and prove the empty state appears.