Keep each test focused
Organize a test around one user outcome. A test with dozens of unrelated steps is slower to diagnose and obscures which behavior failed. Split long tests at durable checkpoints and share repeated setup through modules. Commit test changes with the product change they validate. Review goals, assertions, and locator changes with the same care as application code so a test cannot silently stop protecting the intended behavior.Start flat, split by domain later
For the first 10-20 tests, keep everything intests/ at the project root. Once
the directory becomes difficult to scan, split by product domain:
Modules live alongside tests
Put reusable modules next to the tests that use them:Naming
test.yamlsuffix for tests,module.yamlfor modules, enforced by the default globs- Lower-case kebab filenames:
checkout-with-coupon.test.yaml - Test
idis a kebab-case slug; keep it aligned with the filename so the on-disk identifier and on-disk path agree (e.g.id: checkout-with-couponforcheckout-with-coupon.test.yaml) - Group by user outcome, not implementation (
signup-with-sso, notclick-sso-button)
Labels
Labels are how you slice tests in the CLI and dashboard. Common labels:
Label per-test in YAML:
checkout.test.yaml
Environment configuration
Define environments for every target:local,
dev, staging, production. Each environment carries its own base URL,
variables, and secrets. Select an environment to reuse the test against
compatible targets.
Keep URLs, accounts, and credentials in environment variables instead of
hard-coding them in tests.
Shared fixtures
Keep seed scripts and non-secret fixture data infixtures/ at the project
root. Supply API keys through environment variables or CI secrets. Reference
fixtures from test variables or modules.