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 ≥ 18install. Verify with node --version.
  • oackctl CLIinstall guide. Authenticate with oackctl login.
  • Oack account with a team and a browser monitorsign 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.

Terminal
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+.

Terminal
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:

web/playwright.config.ts
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:

web/tests/e2e/store.spec.ts (excerpt)
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:

Terminal
npx playwright test

You should see all tests pass:

Output
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:

Terminal
npx playwright show-report

To run against your own local server instead, override the base URL:

Terminal
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.

Terminal
oackctl test --team <TEAM_ID> --monitor <MONITOR_ID> --dir .

Expected output:

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.

Terminal
oackctl deploy --team <TEAM_ID> --monitor <MONITOR_ID> --dir .

Expected output:

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.env
OACKCTL_TEAM=your-team-id-here
OACKCTL_MONITOR=your-monitor-id-here

Now you can deploy with just:

Terminal
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:

oack.config.json
{
  "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:

Terminal
oackctl config-deploy --config oack.config.json

Expected output:

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