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 journeys 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. A single test runs everywhere without changes.
Keep URLs, accounts, and credentials in environment variables instead of
hard-coding them in tests.
Shared fixtures
Fixture data (mock users, API keys, seed scripts) lives outsidetests/; most
teams use fixtures/ at the project root. Reference them from test variables or
modules.