How to Monitor User Flows with Playwright Test Suites
Write Playwright tests for your critical user flows (login, search, checkout), run them locally, then deploy to Oack as a scheduled browser monitor — you get alerted when any test fails. This guide uses the PokéStore demo app as an example.
Prerequisites
- Node.js ≥ 18 — install. Verify with
node --version. - oackctl CLI — install guide. Authenticate with
oackctl login. - Oack account with a team and a browser monitor — sign up free.
- Git — to clone the demo project.
Step 1 — Clone the Demo Project
We'll use PokéStore, a demo Pokémon store with login, search, cart, and checkout flows.
The Playwright tests live in the web/ directory.
git clone https://github.com/oack-io/poke-store.git
cd poke-store/web Step 2 — Install Dependencies and Playwright
Install the project dependencies and the Playwright browsers. The project uses Playwright 1.52+.
npm install
npx playwright install npx playwright install downloads the Chromium browser binary that Playwright uses.
This is a one-time step per machine.
Step 3 — Understand the Test Structure
The test configuration and tests:
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
testDir: './tests/e2e',
fullyParallel: true,
reporter: 'html',
use: {
baseURL: process.env.BASE_URL || 'https://poke-store.oack.io',
trace: 'on-first-retry',
screenshot: 'only-on-failure',
},
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
},
],
});
Key points: tests run against https://poke-store.oack.io by default (override with BASE_URL env var),
Chromium only, HTML reporter, screenshots on failure.
The test file covers the full user journey:
import { test, expect } from '@playwright/test';
async function loginAsAsh(page) {
await page.goto('/login');
await page.getByTestId('email-input').fill('ash@pokemon.com');
await page.getByTestId('password-input').fill('pikachu123');
await page.getByTestId('login-submit').click();
await page.waitForURL(/\/store/);
}
test.describe('PokéStore', () => {
test('should log in and see store', async ({ page }) => {
await loginAsAsh(page);
await expect(page.getByTestId('user-name')).toHaveText('Ash Ketchum');
});
test('should search Pokémon', async ({ page }) => {
await loginAsAsh(page);
await page.getByTestId('search-input').fill('pikachu');
await expect(page.getByTestId('pokemon-name')).toContainText('Pikachu');
});
}); Step 4 — Run Tests Locally
Run the full test suite against the live PokéStore demo:
npx playwright test You should see all tests pass:
Running 13 tests using 4 workers
13 passed (24.1s)
To open last HTML report run:
npx playwright show-report Open the HTML report to see detailed results, screenshots, and timing:
npx playwright show-report To run against your own local server instead, override the base URL:
BASE_URL=http://localhost:6001 npx playwright test Step 5 — Run a One-Off Test on Oack
Upload the test suite to Oack's browser infrastructure for a single run. This validates that your tests work on Oack before deploying them as a scheduled monitor.
oackctl test --team <TEAM_ID> --monitor <MONITOR_ID> --dir . Expected output:
Packaging .
Files: 74 (112.7 KB)
Running test...
Result: PASSED
Report: https://api-ru.oack.io/api/v1/artifacts/.../report/index.html Click the report link to see the same Playwright HTML report you see locally — but run on Oack's infrastructure.
Step 6 — Deploy as a Scheduled Monitor
Deploy the test suite so it runs on a schedule (e.g. every 5 minutes). When any test fails, the monitor transitions to DOWN and your alert channels fire.
oackctl deploy --team <TEAM_ID> --monitor <MONITOR_ID> --dir . Expected output:
Packaging .
Files: 74 (112.7 KB)
Uploading suite...
Suite: 112.7 KB
Tests: tests/e2e/store.spec.ts
Git: 8169f4ce (main)
Deployed.
Monitor: https://app-ru.oack.io/teams/.../monitors/... Open the monitor URL in the dashboard. You'll see:
- Pass/fail status — green UP when all tests pass, red DOWN on any failure.
- Playwright HTML report — full test breakdown with screenshots, error details, and timing for every run.
- Git metadata — commit SHA, branch, and who deployed.
Step 7 — Skip Repetitive Flags with .oackctl.env
Create a .oackctl.env file so you don't need to pass --team and --monitor every time:
OACKCTL_TEAM=your-team-id-here
OACKCTL_MONITOR=your-monitor-id-here Now you can deploy with just:
oackctl deploy --dir .
Add .oackctl.env to your .gitignore if it contains team-specific IDs.
Step 8 — Deploy Multiple Checks with oack.config.json
For larger projects, define multiple monitors from the same test suite — each running a different subset of tests:
{
"team": "<TEAM_ID>",
"dir": ".",
"checks": [
{
"name": "PokéStore Login",
"pw_grep": "login"
},
{
"name": "PokéStore Checkout",
"pw_grep": "checkout"
},
{
"name": "PokéStore Full Suite"
}
]
} Deploy all checks at once:
oackctl config-deploy --config oack.config.json Expected output:
Deploying 3 check suites...
PokéStore Login .............. created (monitor abc12345)
PokéStore Checkout ........... created (monitor bcd23456)
PokéStore Full Suite ......... created (monitor cde34567)
Done.
Each check becomes its own browser monitor with independent health status and alerts.
The pw_grep field filters tests by name — only matching tests run for that monitor.
What's Next
- Add alert channels so you get notified on failures — see Alert Channels
- Learn about pageload monitoring (no scripting needed) — see Web Checker — Pageload
- Set up on-call so the right person gets paged — see On-Call Scheduling
- Manage everything as code — see Terraform: First Monitor