Production-ready end-to-end browser testing with the Page Object Model
Clean, readable tests with shared page classes, reusable actions, auto-screenshots on failure, and full Docker support.
Installation Β· Running Tests Β· Docker Β· Writing Tests Β· Configuration
- Page Object Model β locators and actions live in dedicated page classes; tests stay clean and readable
- Shared fixtures β
loginPage,dashboardPage, andauthenticatedPageare injected automatically into every test - Auto-screenshots β Playwright captures a screenshot, video, and trace on every failure automatically
- Environment variables β base URL and credentials are never hard-coded;
.envkeeps them local - Docker support β the official Playwright image ships with all browsers pre-installed; no local setup needed for CI
- HTML report β one command opens a full visual report with logs, screenshots, and traces
playwright-automation/
βββ pages/
β βββ BasePage.js # Shared helpers: navigate, click, fill, assert, screenshot
β βββ LoginPage.js # Login screen β locators + signIn() / expectError()
β βββ DashboardPage.js # Dashboard β locators + navigateTo() / signOut()
βββ tests/
β βββ navigation.test.js # Smoke tests β public pages, HTTP status, JS errors
β βββ login.test.js # Login β happy path, wrong password, empty fields
β βββ dashboard.test.js # Dashboard β content, nav links, sign-out
βββ utils/
β βββ fixtures.js # Custom fixtures that wire page objects into tests
βββ screenshots/ # On-demand screenshots (git-ignored)
βββ test-results/ # Raw artefacts: JSON, videos, traces (git-ignored)
βββ playwright-report/ # HTML report generated after each run (git-ignored)
βββ playwright.config.js # Central Playwright configuration
βββ Dockerfile # Container image for CI / isolated runs
βββ docker-compose.yml # Convenience wrapper for Docker runs
βββ .env.example # Template β copy to .env and fill in your values
βββ package.json
| Tool | Minimum version |
|---|---|
| Node.js | 18 |
| npm | 9 |
Docker is optional β see Running in Docker if you prefer a container-based setup.
git clone https://github.com/your-username/playwright-automation.git
cd playwright-automationnpm installnpm run install:browsersThis downloads Chromium (and Firefox / WebKit if you enable them in playwright.config.js).
cp .env.example .envOpen .env and fill in your values:
# Root URL of the application under test
BASE_URL=https://your-app.com
# Credentials used by the sign-in tests
LOGIN_EMAIL=user@example.com
LOGIN_PASSWORD=your_password_here
.envis listed in.gitignoreand will never be committed to version control.
npm testnpx playwright test tests/login.test.jsnpx playwright test --grep "dashboard"npm run test:headednpm run test:uinpm run test:debugAfter any test run, open the full visual report:
npm run reportThe report (at playwright-report/index.html) shows pass/fail status, error messages, captured screenshots, videos, and traces for every failing test.
No local Node.js or browser installation required β the official Playwright image includes everything.
docker build -t playwright-tests .docker run --rm --env-file .env playwright-testsdocker run --rm --env-file .env playwright-tests \
npx playwright test tests/login.test.jsReports and screenshots are written back to your local directories automatically:
# Run all tests
docker compose run --rm tests
# Run a specific file
docker compose run --rm tests npx playwright test tests/navigation.test.js// pages/SettingsPage.js
const { BasePage } = require('./BasePage');
class SettingsPage extends BasePage {
constructor(page) {
super(page);
this.heading = page.locator('h1');
this.saveButton = page.locator('button:has-text("Save")');
}
async open() {
await super.open('/settings');
}
}
module.exports = { SettingsPage };// utils/fixtures.js (add inside the base.extend({}) call)
const { SettingsPage } = require('../pages/SettingsPage');
settingsPage: async ({ page }, use) => {
await use(new SettingsPage(page));
},// tests/settings.test.js
const { test, expect } = require('../utils/fixtures');
test('settings page loads after login', async ({ authenticatedPage, settingsPage }) => {
await settingsPage.open();
await settingsPage.expectVisible('h1');
await settingsPage.expectUrlContains('/settings');
});All settings live in playwright.config.js. The most common things to change:
| Setting | Where | Default |
|---|---|---|
| App URL | BASE_URL in .env |
https://example.com |
| Browsers | projects array in config |
Chromium only |
| Retries on CI | retries |
2 |
| Action timeout | actionTimeout |
15 s |
| Navigation timeout | navigationTimeout |
30 s |
| Screenshots | screenshot |
On failure only |
| Video | video |
Retained on failure |
To enable Firefox or WebKit, uncomment the relevant block in playwright.config.js:
// {
// name: 'firefox',
// use: { ...devices['Desktop Firefox'] },
// },
// {
// name: 'webkit',
// use: { ...devices['Desktop Safari'] },
// },| Variable | Required | Description |
|---|---|---|
BASE_URL |
Yes | Root URL of the application under test |
LOGIN_EMAIL |
For auth tests | Email address used to sign in |
LOGIN_PASSWORD |
For auth tests | Password used to sign in |
| Command | What it does |
|---|---|
npm test |
Run all tests headlessly |
npm run test:headed |
Run all tests with the browser visible |
npm run test:ui |
Open Playwright's interactive UI mode |
npm run test:debug |
Step through tests one action at a time |
npm run report |
Open the HTML report in the browser |
npm run codegen |
Record a new test by clicking through the app |
npm run install:browsers |
Download Playwright browser binaries |
BasePage
β navigate Β· click Β· fill Β· expectText Β· expectVisible Β· screenshot Β· wait
β
βββ LoginPage extends BasePage
β open() Β· enterCredentials() Β· submit() Β· signIn() Β· expectError()
β
βββ DashboardPage extends BasePage
open() Β· expectLoaded() Β· navigateTo() Β· signOut() Β· getNotificationText()
Tests never reference raw CSS selectors. They call methods on page objects, which makes tests readable as plain English and means a selector change only needs to be fixed in one place.
MIT