Skip to content

About

QA portfolio with UI, API, SQL and AI-based testing examples

Resources

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

QA Portfolio — Booking.com Test Suite

Acceptance Tests Nightly Full Run Manual Quality Gate API Mock Tests

A portfolio-focused QA automation project modelled on Booking.com, using Gherkin BDD, Playwright (TypeScript), Cypress (JavaScript), and GitHub Actions CI/CD.

Execution model: the mock API suite is deterministic and runs for real. The local teaching UI and mock API run together for manual browser checks. Supported UI automation runs for real against the local teaching stand; it never visits Booking.com. Experimental scenarios remain visible under @WIP but are deliberately excluded from quality gates.


Tech Stack

Layer Tool Language
Test design & specification Gherkin / Cucumber —
E2E & API automation Playwright TypeScript
E2E & API automation Cypress JavaScript
SQL learning examples (not DB tests) SQL PostgreSQL syntax
Lightweight API checks cURL Bash
CI/CD quality gates GitHub Actions YAML

Project Structure

scripts/
├── ai-generate-feature.ts           # AI feature generator (Claude API or offline mock)
└── validate-generated-draft.js      # parser + explicit dry-run step matching

tests/
├── manual/
│   └── features/
│       ├── api/                     # executable API specifications
│       │   ├── 01_login_success.feature
│       │   ├── 02_login_failure.feature
│       │   ├── 03_search_city.feature
│       │   ├── 04_search_dates.feature
│       │   ├── 05_price_filter.feature
│       │   ├── 06_currency_conversion.feature
│       │   ├── 07_add_to_wishlist.feature
│       │   ├── 08_remove_from_wishlist.feature
│       │   ├── 09_view_details.feature
│       │   ├── 10_get_reviews.feature
│       │   ├── 11_hotel_review_crud.feature   ← Full CRUD lifecycle
│       │   └── ai_reviews_ep.feature          ← 🤖 AI-generated (EP)
│       ├── e2e/                     # UI specifications
│           ├── booking.feature
│           ├── language_switch.feature
│           ├── currency_switch.feature
│           ├── search_filters.feature
│           ├── invalid_login.feature
│           ├── form_validation.feature
│           ├── bva_search_boundaries.feature  ← Boundary Value Analysis
│           ├── ep_login_credentials.feature   ← Equivalence Partitioning
│           ├── decision_table_search_filters.feature ← Decision Table
│           ├── state_transition_booking_flow.feature ← State Transition
│           ├── ai_price_filter_currency_switch.feature ← 🤖 AI-generated (Decision Table, WIP)
│           ├── ai_wishlist_state_transition.feature    ← 🤖 AI-generated (State Transition, WIP)
│           └── ai_guest_count_bva.feature              ← 🤖 AI-generated (BVA, WIP)
│       └── drafts/{api,e2e}/         # new generated drafts, always @WIP
└── automation/
    ├── api/
    │   ├── playwright/              # Playwright API step definitions (TS)
    │   ├── cypress/                 # Cypress API step definitions (JS)
    │   ├── curl/                    # 10 cURL scripts with response validation
    │   └── sql/                     # 10 SQL queries (JOINs, CTEs, window fns)
    └── e2e/
        ├── playwright/
        │   ├── pages/               # Page Object Model (TypeScript)
        │   └── steps/               # Step definitions (TypeScript)
        ├── cypress/
        │   ├── pages/               # Page Object Model (JavaScript)
        │   └── steps/               # Step definitions (JavaScript)
        └── fixtures/
            └── world.ts             # Playwright browser/request lifecycle

Test Design Techniques

This project demonstrates six core ISTQB test design techniques:

Technique Feature file Coverage
Boundary Value Analysis bva_search_boundaries.feature Guest count (0–31), stay duration
Equivalence Partitioning ep_login_credentials.feature Email format classes, password classes
Decision Table decision_table_search_filters.feature Filter combinations → expected outcomes
State Transition state_transition_booking_flow.feature Full booking lifecycle state machine
Scenario Outline / Pairwise booking.feature, invalid_login.feature Multi-city search, multi-credential sets
Error Guessing 02_login_failure.feature, form_validation.feature Invalid inputs, empty fields

Test Suites & Tags

Suite Tag When Scope
Acceptance @Acceptance Every push to main Core happy paths
Smoke @Smoke Nightly (sequential after Acceptance) Key critical flows
Regression @Regression Nightly (sequential after Smoke) Full coverage
Work In Progress @WIP Never in CI (excluded) Features in development

API Coverage

# Endpoint Method Test type
01 /api/login POST Auth success, token present
02 /api/login POST Auth failure, 401 response
03 /api/hotels?city= GET City search, result set validation
04 /api/hotels?city=&checkin=&checkout= GET Date-filtered availability
05 /api/hotels?min_price=&max_price= GET Price range filter
06 /api/hotels?currency= GET Currency conversion (USD/EUR/GBP)
07 /api/wishlist POST Create wishlist entry
08 /api/wishlist/{id} DELETE Remove wishlist entry
09 /api/hotel/{id} GET Hotel detail completeness
10 /api/hotel/{id}/reviews GET Review list with user & rating
11 /api/hotel/{id}/reviews/{id} POST/GET/PUT/DELETE Full CRUD lifecycle

Getting Started

Prerequisites

  • Node.js 22.23.2 (pinned in .nvmrc; CI reads the same file)
  • npm 10.9.x (validated with 10.9.8, bundled with this Node.js release)

Setup

git clone https://github.com/yaoleshchuk/qa-pet-project.git
cd qa-pet-project
nvm install
nvm use
npm ci
npx playwright install chromium --with-deps

nvm is optional: another version manager may install the exact version in .nvmrc. Browser installation is not needed for the API-only Cucumber suites.

The staged improvement plan is in docs/improvement-plan.md. See the stage 0 baseline for the historical baseline, and the stage 1 integration evidence for checks against the current PR base.

No .env, credentials, external service, global jq, or global Allure install is needed for the supported local commands. npx --no-install and npm scripts use the locked project dependencies. Do not point mock API commands at Booking.com.


Running Tests

Playwright + Cucumber (strict dry-run — step validation)

# Validate suite structure without a browser (fast, used in CI).
# The command exits non-zero if any non-WIP step is undefined.
npm run test:pw:dry-run

# Run by suite (dry-run)
npm run test:pw:acceptance
npm run test:pw:smoke
npm run test:pw:regression

API Tests against Mock Server (real execution + Allure)

# 1. Start the mock API server (Express, port 3001)
npm run mock:start

# 2. In a separate terminal — run tests by suite
npm run test:api:all          # all implemented @API scenarios
npm run test:api:acceptance   # @API + @Acceptance
npm run test:api:smoke        # @API + @Smoke
npm run test:api:regression   # @API + @Regression

# 3. Generate & open the Allure HTML report
npm run allure:generate
npm run allure:open

Wait for readiness before another terminal runs a command:

curl --fail --silent http://127.0.0.1:3001/health

Stop only the npm run mock:start process started for this task with Ctrl-C. Each test:api:* run first removes reports/api/latest/, then writes its JSON and Allure results there. Thus allure:generate always consumes one current real run, never an old top-level allure-results/ directory.

The mock server simulates all Booking.com API endpoints with realistic seed data, enabling fully deterministic test results without network access.

Local teaching UI + mock API (manual browser exercise)

# Starts one process on http://localhost:3001, waits up to 10 seconds for
# /health, and forwards Ctrl-C/SIGTERM to stop the process cleanly.
npm run ui:local

Open http://localhost:3001. The UI has accessible labels and stable data-testid values for the stage-6 automation work. It searches city/dates and guests, receives availability, price ranges, and converted currencies from the mock API, and provides client-side amenity/star filters and numeric price sort on the received response. It never calculates exchange rates or availability in the browser.

Test-only credentials are testuser@example.com / correct_password. A successful login stores only the display user in tab-scoped sessionStorage; Sign out clears that local display session. Wishlist state can be reloaded while signed in, but belongs to the running mock process and is not tied to an authenticated user. Restart the process, or run curl -X POST http://localhost:3001/api/test/reset, to restore the seed state. The search form visibly states that guests are validated only from 1 to 30: the existing API has no guest-capacity parameter, so this input does not change availability and the UI does not claim otherwise. Bookings, checkout and cancellation are intentionally not implemented.

To use a different isolated port: MOCK_PORT=13025 npm run ui:local. Set UI_READY_TIMEOUT_MS (milliseconds) only when a longer readiness wait is needed.

Real local UI automation

These commands start their own local mock, wait for /health, and stop only that child process. They need the Chromium install from Setup; do not start another server.

npm run test:ui:playwright
npm run test:ui:cypress

The generic legacy Cypress commands remain configuration-level commands and are not coverage evidence for the teaching model; use the two commands above for real UI runs.

Cypress API against the local mock

Start npm run mock:start, verify /health as above, then run one of the API-only commands below. They use cypress.api.config.js, load only shared @API Gherkin features, and reject a non-local API URL; they never visit Booking.com.

npm run test:cypress:api:all
npm run test:cypress:api:acceptance
npm run test:cypress:api:smoke
npm run test:cypress:api:regression

cURL scripts (lightweight API smoke checks)

# Starts a private mock on 127.0.0.1:3218, waits for /health, runs all ten
# checks, then stops only that child process.
npm run test:curl:smoke

Each script uses the documented mock contract, verifies the HTTP status, parses JSON with the repository's Node.js runtime, uses connect/total timeouts (5/15 seconds), resets its own test state, and cleans its wishlist mutation. The scripts require the runner's CURL_DEDICATED_MOCK=1 marker, so they cannot reset an API/UI server owned by another run. Override CURL_TEST_PORT, CURL_CONNECT_TIMEOUT, or CURL_MAX_TIME when diagnosing; BASE_URL is set by the runner and remains local. The scripts have been run with macOS Bash and use Bash 3-compatible syntax; Linux is documented-compatible but is not claimed as locally executed evidence.

Verifiable coverage matrix

Rows are groups, not additive scenario totals: the same API or UI Gherkin scenario may appear in more than one runner. “Real” means steps/browser requests execute; “dry-run” checks matching only.

Scenario/group Tool Command Coverage status
Non-@WIP Gherkin selected by default/Acceptance/Smoke/Regression tags Cucumber + Playwright definitions npm run test:pw:dry-run, test:pw:acceptance, test:pw:smoke, test:pw:regression Strict dry-run only; non-empty current JSON and no undefined/ambiguous step. No browser or API execution.
Implemented @API and not @WIP scenarios Playwright API + local mock npm run mock:start; then npm run test:api:all (or a tagged suite) Real API coverage; isolated in-memory mock and fresh JSON/Allure directory.
Same implemented API set Cypress API + local mock npm run mock:start; then npm run test:cypress:api:all Real API coverage; CI compares passed identities with Playwright. Overlap, not extra unique scenarios.
Supported @LocalUI and not @WIP UI group (22 Examples/scenarios) Playwright UI + local UI npm run test:ui:playwright Real browser run; rejects empty/non-passed JSON and retains diagnostics.
Same supported UI group Cypress UI + local UI npm run test:ui:cypress Real browser run; passed total must equal the same selection manifest. Overlaps Playwright UI.
Ten API teaching checks Bash cURL + local mock bash tests/automation/api/curl/01_login_success.sh through 10_get_reviews.sh Real HTTP smoke checks, not a separate count of Gherkin coverage.
Generated @WIP @GeneratedDraft API/E2E files Parser + opt-in Cucumber dry-run npm run ai:generate:mock or npm run test:ai-generator Draft syntax/matching only; excluded from ordinary and real suites; external AI is optional and not used for baseline validation.
Existing @WIP and non-@LocalUI model exclusions — — Visible, but deliberately not passed/covered by normal gates. Booking, payment, cancellation, guest-capacity availability, ownership and persistent auth are outside the teaching model.
tests/automation/api/sql/*.sql — — PostgreSQL learning examples only. No database, connection, fixture lifecycle, or executable DB harness; not integration-test coverage.

CI/CD (GitHub Actions)

Workflow Trigger Jobs
on-main-acceptance.yml Pull request, push to main, manual Typecheck plus four independent strict dry-run profiles
manual-quality-gate.yml Manual dispatch Selectable strict dry-run profile
nightly-full-run.yml Daily 00:00 UTC, manual Four independent strict dry-run profiles
api-mock-tests.yml Pull request, push to main, daily 01:30 UTC, manual Real API suites against a restarted mock, retained diagnostics and Allure report

The dry-run workflows type-check the TypeScript suite and fail on undefined or ambiguous non-WIP steps without opening a browser. The mock-server workflow runs API tests for real, records every selected suite, and preserves reports on failure. Pages publishing is a separate job and never runs for pull requests.

@WIP scenarios are excluded from these gates. A green dry-run therefore means that all included steps are matched; it does not prove WIP coverage. The current exclusion is quantified in stage 1 integration evidence.

To enable GitHub Pages: go to Settings → Pages → Source and set it to GitHub Actions.


Allure Reports

API tests produce a full Allure HTML report as a CI artifact only from current results. A runner with no current result must fail rather than publish an old report.

Live report

📊 View latest Allure report →

The report is published to GitHub Pages after every push to main and every nightly run via the api-mock-tests.yml workflow. It includes:

  • ✅ Pass / ❌ Fail / ⚠️ Broken status per test
  • Full step-by-step execution log for each scenario
  • Tags, feature grouping, and suite breakdown
  • Duration timeline and statistics

How it works

Mock server starts (Express, port 3001)
        ↓
Cucumber runs API tests against mock server
        ↓
allure-cucumberjs writes results to reports/api/latest/allure-results/
        ↓
allure generate → allure-report/ (HTML)
        ↓
GitHub Pages deploys report → live URL

Run locally

# Terminal 1 — start mock server
npm run mock:start

# Terminal 2 — run one fresh suite and generate its report
npm run test:api:acceptance
npm run allure:generate
npm run allure:open        # opens browser automatically

SQL Queries

Located in tests/automation/api/sql/. These are educational PostgreSQL examples mapped to test ideas; they do not validate this mock server at a database layer. The repository has no test database, DB connection, migration/fixture lifecycle, or executable SQL harness. Do not report them as passed integration tests.

  • Window functions: RANK(), ROW_NUMBER(), LAG(), PERCENT_RANK()
  • CTEs (Common Table Expressions) for multi-step logic
  • PERCENTILE_CONT for statistical assertions on review ratings
  • STRING_AGG for amenity list validation
  • Conditional aggregation with SUM(CASE WHEN … END)
  • Date overlap logic for availability validation

AI Feature Generator

An interactive CLI tool that uses the Claude API to generate draft Gherkin .feature files from a plain-English description.

How it works

You describe what to test
        ↓
CLI asks: test type, tags, test design technique
        ↓
Claude API generates a draft Gherkin feature tagged @WIP + @API/@E2E
        ↓
It is saved under tests/manual/features/drafts/{e2e|api}/
        ↓
Gherkin is parsed and that exact @WIP draft is dry-run matched to steps

Setup

Add your Anthropic API key to .env:

ANTHROPIC_API_KEY=sk-ant-...

Get a key at console.anthropic.com.

Usage

npm run ai:generate

# Offline, without ANTHROPIC_API_KEY and without an external request
npm run ai:generate:mock

# Reproducible non-interactive mock example
npx ts-node --project tsconfig.json scripts/ai-generate-feature.ts --mock --non-interactive \
  --description "login response" --type api

Example session:

╔══════════════════════════════════════╗
║   AI Feature File Generator  🤖       ║
╚══════════════════════════════════════╝

? Describe the feature to test: hotel price filter with currency switch
? Test type (e2e / api): (e2e) e2e
? Tags (e.g. @Smoke @Regression): (@ Smoke @Regression)
  Techniques: 0) none  1) BVA  2) EP  3) Decision Table  4) State Transition  5) Error Guessing
? Test design technique (0–5): (0) 3

  ⏳  Calling Claude API…

  ✅  Feature file generated!
     → tests/manual/features/e2e/decision_table_hotel_price_filter_with_currency_switch.feature

Generated files always have @WIP, @GeneratedDraft, and exactly one type tag: @API or @E2E. They live in tests/manual/features/drafts/, are excluded from ordinary profiles, and never receive @LocalUI automatically. The generator gives the provider the local mock API contract (for API drafts), local-UI limitations, and the supported step wording. Its examples use fixed fixture-friendly dates, not a specific current year.

The validation parses Gherkin first, then explicitly selects the generated @WIP draft in Cucumber dry-run mode and requires at least one selected scenario with no undefined or ambiguous steps. It does not execute steps or launch a browser. Passing it only proves syntax and step matching, not that the scenario is meaningful or that the system behaves correctly.

To promote a draft: review its intent against the contract and supported product model; implement or confirm the required assertions and steps; run the relevant scenario for real against the local mock/local UI; then move it into the appropriate working feature directory, remove @WIP and @GeneratedDraft, and add @LocalUI only after local-UI support was verified. Finally run the affected normal suite. Never promote a draft based only on generator validation.


Built with ☕ by Yaroslav Oleshchuk

About

QA portfolio with UI, API, SQL and AI-based testing examples

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages