Writing Your First Test
Walk through a fully annotated test that navigates to a page, interacts with elements, and verifies the outcome.
Anatomy of a Playwright Test
Every Playwright test follows the same three-phase structure: Arrange (set up the browser state), Act (perform the user actions), and Assert (verify the expected outcome). Playwright's test runner provides a page fixture automatically, so you never need to instantiate a browser manually inside a test.
Tests are grouped into files using test.describe blocks (JavaScript) or standard class groupings (Java/Python). Within each group you can define beforeEach and afterEach hooks to avoid repetition — for example, navigating to the login page before every test in a suite.
test.only (JS) or pytest -k (Python) while developing to run a single test in isolation without executing the entire suite.Navigating, Clicking, and Asserting
The example below tests a simple login form. It navigates to the login page, fills in credentials, clicks the submit button, and then asserts that the dashboard heading is visible. Notice how there is no sleep() — Playwright automatically waits for each element to be ready before interacting with it, and for the navigation to complete before asserting.
Running and Inspecting Results
Run your test with npx playwright test or pytest. On failure Playwright captures a screenshot and, if configured, a video and a trace file that you can open in the Playwright Trace Viewer to see every step alongside DOM snapshots, network requests, and console output.
import { test, expect } from '@playwright/test';
// Group related tests with describe
test.describe('Login flow', () => {
// Navigate before every test in this group
test.beforeEach(async ({ page }) => {
await page.goto('/login');
});
test('successful login redirects to dashboard', async ({ page }) => {
// Arrange — fill in credentials
await page.getByLabel('Email').fill('user@example.com');
await page.getByLabel('Password').fill('secret123');
// Act — submit the form
await page.getByRole('button', { name: 'Sign in' }).click();
// Assert — dashboard heading should be visible
await expect(page.getByRole('heading', { name: 'Dashboard' })).toBeVisible();
await expect(page).toHaveURL('/dashboard');
});
test('wrong password shows error message', async ({ page }) => {
await page.getByLabel('Email').fill('user@example.com');
await page.getByLabel('Password').fill('wrongpass');
await page.getByRole('button', { name: 'Sign in' }).click();
await expect(page.getByText('Invalid credentials')).toBeVisible();
});
});
import com.microsoft.playwright.*;
import com.microsoft.playwright.assertions.PlaywrightAssertions;
import org.junit.jupiter.api.*;
class LoginTest {
static Playwright playwright;
static Browser browser;
Page page;
@BeforeAll
static void launchBrowser() {
playwright = Playwright.create();
browser = playwright.chromium().launch();
}
@BeforeEach
void createPage() {
page = browser.newPage();
page.navigate("http://localhost:3000/login");
}
@Test
void successfulLogin() {
page.getByLabel("Email").fill("user@example.com");
page.getByLabel("Password").fill("secret123");
page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName("Sign in")).click();
PlaywrightAssertions.assertThat(page).hasURL("/dashboard");
}
@AfterEach
void closePage() { page.close(); }
@AfterAll
static void closeBrowser() { browser.close(); playwright.close(); }
}
import pytest
from playwright.sync_api import Page, expect
@pytest.fixture(autouse=True)
def go_to_login(page: Page):
# Navigate before every test in this module
page.goto("/login")
def test_successful_login(page: Page):
# Arrange
page.get_by_label("Email").fill("user@example.com")
page.get_by_label("Password").fill("secret123")
# Act
page.get_by_role("button", name="Sign in").click()
# Assert
expect(page).to_have_url("/dashboard")
expect(page.get_by_role("heading", name="Dashboard")).to_be_visible()
def test_wrong_password_shows_error(page: Page):
page.get_by_label("Email").fill("user@example.com")
page.get_by_label("Password").fill("wrongpass")
page.get_by_role("button", name="Sign in").click()
expect(page.get_by_text("Invalid credentials")).to_be_visible()
Written by PV
© 2026 All Rights Reserved