QA ENGINEERING GUIDE
Automation Testing Guide
Introduction to automation testing with Playwright, Cypress and other modern frameworks.
When to automate
Automate tests that run often, exercise stable features and deliver a clear return on investment. Regression suites, critical user journeys and data-heavy validation are ideal candidates.
Do not automate one-off exploratory checks, tests with visually volatile selectors or scenarios whose requirements are still shifting. An automation suite that needs constant repair costs more than the manual testing it replaced.
Types of automation
Automation exists at several levels, and the most reliable strategy mixes them. Each level is faster and cheaper than the one above it, so push coverage down.
- Unit — in-process checks run by the developer with a framework such as Jest or Vitest.
- API — verifies endpoints, contracts and data without a browser.
- UI / E2E — drives the real user interface through a browser.
Popular frameworks
Playwright and Cypress dominate modern UI automation because they manage their own browsers and retry failed steps by default. Selenium remains widely used for cross-browser grid setups, while WebDriverIO offers a Selenium-compatible API with a lighter footprint.
- Playwright — auto-waiting, multi-browser, parallel workers, trace and video on failure.
- Cypress — time-travel debugging, in-browser execution, fast feedback for JS apps.
- Selenium — mature ecosystem, large community, strong grid support.
- WebDriverIO — flexible, extends easily with custom services and reporters.
Anatomy of a test framework
A solid framework separates infrastructure from tests. The test runner executes specs and reports results; selectors locate elements; assertions define passes and failures.
Fixtures prepare state before tests, and reporters produce readable output for humans and CI. Your framework should also hold environment configuration separate from test code so the same suite runs on any environment.
Selector strategies
Prefer selectors tied to user-visible roles and stable attributes over brittle CSS chains. In Playwright use getByRole, getByLabel and getByTestId where possible.
Avoid positioning selectors such as div:nth-child(3) that break on any layout change, and ask developers for a data-testid rather than contorting around unstable markup.
Handling waits and flakiness
Never use fixed sleeps. Assert that a condition becomes true, or rely on auto-waiting so tests move forward the moment the UI is ready.
Flakiness is a symptom, not a bug to be ignored. Investigate the root cause of a flaky test, delete tests you cannot stabilize, and rerun only to confirm a fix rather than to mask one.
CI integration
Automation only pays off when it runs regularly. Trigger the suite on every pull request and merge, run the fast critical set on commit and the full regression suite on schedule.
Store screenshots, traces and videos as CI artifacts so failures are diagnosed from the pipeline, not replayed manually on a developer laptop.
Page object model
The page object pattern wraps a page or component into a class that exposes its actions and locators. Test code then reads like user behavior instead of CSS selection noise.
Keep locators inside the page object, not in the tests. When markup changes you update one class instead of hundreds of scripts.