QA PRACTICE•FRAMEWORK
Playwright · Selenium · Cypress
Framework
Compare three automation frameworks on the same E2E flow, then learn a maintainable Playwright Page Object Model structure through real QA examples.
Same check · three tools
Choose your automation framework
Learn the same stable locator and assertion pattern in Playwright, Selenium and Cypress.
123456789
import { test, expect } from '@playwright/test';
test('user can add a product to the cart', async ({ page }) => {
await page.goto('https://qapractice.hakdogan.com/ecommerce');
await page.getByTestId('product-search').fill('Keyboard');
await page.getByRole('button', { name: /add keyboard to cart/i }).click();
await expect(page.getByTestId('cart-count')).toHaveText('1');
});Live browser runner
Write and run a focused check
Playwright-style commands execute against the practice target below. Try changing the locator or expected text and read the failure log.
Practice target
Profile settings
Not run yet
Run the example to see command results.
Lesson 1 of 4 · Beginner
Automate the Inputs test
You already tested this form manually in Practice. Now learn how the same check is organised in Playwright, Selenium and Cypress.
Goal
Connect an acceptance criterion to code.
Files
Spec + Page Object + fixture.
Time
About 15 minutes · no account.
Lesson path
Progress
1 of 7 steps
inputs.spec.ts
Test: what to verify
1234567891011121314
import { test, expect } from '@playwright/test';
import { InputsPage } from './inputs.page';
test('invalid email shows a field error', async ({ page }) => {
const inputs = new InputsPage(page);
await inputs.goto();
await inputs.fillEmail('not-an-email');
await inputs.fillPassword('Pass-w0rd!');
await inputs.submit();
await expect(inputs.emailError).toHaveText(
'Please enter a valid email address.',
);
});Run it
$ npx playwright test inputs.spec.tsAcceptance criteria → assertions
- AC-002 Invalid email is rejected →
emailError.toHaveText() - AC-003 Error appears beside the field →
getByTestId('email-error') - AC-006 Focus order is logical → add the keyboard step next
Common mistakes
- Do not put raw selectors in the spec.
- Do not use
waitForTimeoutfor validation. - Keep assertions in the test so the expected behaviour is visible.
Your turn
Write the positive Inputs test, then continue with Buttons.
The framework
How the framework fits together
Code layers
Test → Page Object → Component
The test describes what should happen. The Page Object owns where things are and how a user interacts with them.
Run layers
Config → Runner → CI
Config sets the rules, Playwright runs the test, and CI repeats it for every change.
- tests/ → describe-blocks tagged
@smoke/@regression. - pages/ → Page Object Model for every screen with role-based locators.
- components/ → reusable component objects (header, toast, modal).
- utils/auth.ts → shared
signInAsfor user and admin journeys (storage promotion included). - utils/ → cross-cutting helpers: auth, mocks, waits, retries, downloads.
- data/ → pure data builders (faker-powered) — no I/O, no shared state.
- tsconfig.json → strict TypeScript,
noEmitcheck-only for the suite. - playwright.config.ts → projects, retries, traces, screenshots, video, GREP.
- .github/ → 4-shard matrix, nightly cron, artifact upload on failure.
+All project files · download the complete starter project
tests/login.spec.ts
Auth happy path + client-side validation negative cases.
12345678910111213141516171819202122232425
import { test, expect } from 'playwright/test';
import { LoginPage } from '../pages/login.page';
test.describe('Authentication @smoke', () => {
test('demo credentials reach Bug Playground', async ({ page }) => {
const login = new LoginPage(page);
await login.goto();
await login.useDemoAccount();
await login.submit();
await expect(page).toHaveURL(/\/bug-playground\/\/?$/);
});
test('invalid email and short password show validation messages @regression', async ({
page,
}) => {
const login = new LoginPage(page);
await login.goto();
await login.signIn('not-an-email', 'short');
await expect(login.emailFormatError).toHaveText(/Use a valid email address/i);
await expect(login.passwordLengthError).toHaveText(
/Password must be at least 8/i,
);
});
});Run locally
Setup
- unzip/ → extract
qapractice.hakdogan.com.zip. - cd/ → enter
qapractice.hakdogan.com/. - install/ → run
npm install. - browsers/ → run
npx playwright install. - test/ → run
npx playwright test.
Usage
- report/ →
npx playwright show-report. - smoke/ →
npx playwright test --grep @smoke. - regression/ →
npx playwright test --grep @regression. - debug/ →
npx playwright test --debug. - node/ → Node.js v18+ (v20 recommended).