Skip to content
Flarely

Writing checks

A check is a small Playwright project: one or more *.spec.ts files and an optional playwright.config.ts. Nothing proprietary. The runner wraps the config to force one worker, tracing on, screenshot and video on failure, and a per-plan wall clock.

Read the target from the environment

Never hard-code the URL. Read process.env.BASE_URL and set it per run (--base-url on the CLI, env on run_check) or as the check's default env for schedules. The same check then runs against local, preview and production.

import { test, expect } from '@playwright/test';

const base = process.env.BASE_URL!;

test('sign-up creates an account', async ({ page }) => {
  await page.goto(base + '/signup');
  await test.step('fill the form', async () => {
    await page.getByLabel('Email').fill(`check+${Date.now()}@example.com`);
    await page.getByLabel('Password').fill('correct horse battery');
  });
  await page.getByRole('button', { name: 'Create account' }).click();
  await expect(page.getByRole('status')).toHaveText('Account created.');
});

Conventions that make failures repairable

  • One flow per check, named for the outcome: "Checkout completes".
  • Role and label locators over CSS. They survive restyles and read well in a failure message.
  • Wrap phases in test.step. The failure context names the step that broke.
  • Assert on visible outcomes: text, visibility, URL. Not on implementation details.
  • Keep a check under a minute. Free runs get 90 seconds of wall clock; paid get five minutes.

Limits

LimitValue
Files per bundle64
Bundle size512 KB, 128 KB per file
File types.ts .js .mjs .cjs .json .md .txt
Env vars per run32, UPPER_SNAKE keys
Per-test timeout120 s ceiling
Dependencies@playwright/test only, for now

Versions

Every push or edit creates an immutable version with an author (you or an agent) and a message. The history is on the check page and over MCP with get_check_history, which is the first thing to read when a check that used to pass starts failing.