Writing Your First Playwright Test
Learn how to write and run your first automated test with Playwright.
Creating a Test File
Create a new file named example.spec.ts in the tests directory:
typescript
import { test, expect } from '@playwright/test';
test('has title', async ({ page }) => {
await page.goto('https://playwright.dev/');
// Expect a title "to contain" a substring.
await expect(page).toHaveTitle(/Playwright/);
});
test('get started link', async ({ page }) => {
await page.goto('https://playwright.dev/');
// Click the get started link.
await page.getByRole('link', { name: 'Get started' }).click();
// Expects page to have a heading with the name of Installation.
await expect(page.getByRole('heading', { name: 'Installation' })).toBeVisible();
});Understanding the Test Structure
Import Statements
Every test file starts by importing the necessary functions:
typescript
import { test, expect } from '@playwright/test';- test: Function to define a test case
- expect: Function to make assertions
Test Function
Each test is defined using the test function:
typescript
test('test name', async ({ page }) => {
// Test code here
});- First parameter: Test description (string)
- Second parameter: Async function that receives fixtures like
page - page: Browser page object to interact with
Common Actions
Navigation
typescript
// Navigate to a URL
await page.goto('https://example.com');
// Navigate back
await page.goBack();
// Navigate forward
await page.goForward();
// Reload page
await page.reload();Interacting with Elements
typescript
// Click on an element
await page.getByRole('button', { name: 'Submit' }).click();
// Type text into an input
await page.getByLabel('Email').fill('user@example.com');
// Select from dropdown
await page.getByLabel('Country').selectOption('USA');
// Check a checkbox
await page.getByLabel('Accept terms').check();Assertions
typescript
// Check if element is visible
await expect(page.getByText('Welcome')).toBeVisible();
// Check element text content
await expect(page.getByRole('heading')).toHaveText('Dashboard');
// Check page title
await expect(page).toHaveTitle('My App');
// Check URL
await expect(page).toHaveURL(/dashboard/);
// Check element count
await expect(page.getByRole('listitem')).toHaveCount(5);Running Tests
Run All Tests
bash
npx playwright testRun Specific Test File
bash
npx playwright test example.spec.tsRun in UI Mode
bash
npx playwright test --uiRun in Debug Mode
bash
npx playwright test --debugComplete Example
Here's a complete test that demonstrates a login flow:
typescript
import { test, expect } from '@playwright/test';
test.describe('Login Flow', () => {
test('successful login', async ({ page }) => {
// Navigate to login page
await page.goto('https://example.com/login');
// Fill in credentials
await page.getByLabel('Email').fill('user@example.com');
await page.getByLabel('Password').fill('securePassword123');
// Click login button
await page.getByRole('button', { name: 'Login' }).click();
// Verify successful login
await expect(page).toHaveURL(/dashboard/);
await expect(page.getByText('Welcome back')).toBeVisible();
});
test('login with invalid credentials', async ({ page }) => {
await page.goto('https://example.com/login');
await page.getByLabel('Email').fill('wrong@example.com');
await page.getByLabel('Password').fill('wrongPassword');
await page.getByRole('button', { name: 'Login' }).click();
// Verify error message
await expect(page.getByText('Invalid credentials')).toBeVisible();
await expect(page).toHaveURL(/login/);
});
});Best Practices
- Use descriptive test names that explain what is being tested
- Keep tests independent - each test should work on its own
- Use
test.describe()to group related tests - Prefer user-facing selectors like
getByRole()andgetByLabel() - Always wait for elements before interacting with them
- Use auto-waiting - Playwright waits automatically for elements to be ready