{"id":51152175,"url":"https://github.com/stefen-taime/api-testing-demo-v2","last_synced_at":"2026-06-26T07:01:51.533Z","repository":{"id":351345441,"uuid":"1210608091","full_name":"Stefen-Taime/api-testing-demo-v2","owner":"Stefen-Taime","description":"Demo project covering 11 API testing types with FastAPI, JWT, Playwright, JMeter, Docker Compose, and Postgres.","archived":false,"fork":false,"pushed_at":"2026-04-14T15:40:38.000Z","size":4412,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-14T17:24:23.201Z","etag":null,"topics":["api-testing","docker-compose","fastapi","jmeter","jwt","playwright","postgresql","qa"],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Stefen-Taime.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-14T15:24:34.000Z","updated_at":"2026-04-14T15:40:41.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/Stefen-Taime/api-testing-demo-v2","commit_stats":null,"previous_names":["stefen-taime/api-testing-demo-v2"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/Stefen-Taime/api-testing-demo-v2","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Stefen-Taime%2Fapi-testing-demo-v2","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Stefen-Taime%2Fapi-testing-demo-v2/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Stefen-Taime%2Fapi-testing-demo-v2/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Stefen-Taime%2Fapi-testing-demo-v2/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Stefen-Taime","download_url":"https://codeload.github.com/Stefen-Taime/api-testing-demo-v2/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Stefen-Taime%2Fapi-testing-demo-v2/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34806448,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-26T02:00:06.560Z","response_time":106,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api-testing","docker-compose","fastapi","jmeter","jwt","playwright","postgresql","qa"],"created_at":"2026-06-26T07:01:50.702Z","updated_at":"2026-06-26T07:01:51.525Z","avatar_url":"https://github.com/Stefen-Taime.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# API Testing Demo V2\n\nThis project tells a simple story: a client gets a `JWT`, creates an order through a FastAPI API, the API stores that order in SQL, sends a notification to a dedicated microservice, and a `/dashboard` UI shows the current system state.  \nThe goal of the repository is to demonstrate, along that same end-to-end flow, **11 types of API testing** with real executions, real outputs, and screenshots embedded directly in this README.\n\n## The Business Scenario\n\n1. The auth service issues a token through `/oauth/token`.\n2. The client calls `POST /api/orders` with a `Bearer JWT`.\n3. The API stores the order in SQL and decrements inventory.\n4. The API calls the notification microservice.\n5. The dashboard reads `/api/dashboard-data` and displays the current state.\n\n![Dashboard](./docs/screenshots/dashboard.png)\n\n## The 11 Test Types Covered\n\n| # | Type | What it means in this project |\n| --- | --- | --- |\n| 1 | `Smoke Testing` | Check that the API starts correctly and answers on its core endpoints. |\n| 2 | `Functional Testing` | Validate the expected business behavior for creating and reading orders. |\n| 3 | `Integration Testing` | Verify that the API, database, and notification service work together correctly. |\n| 4 | `Regression Testing` | Lock down fragile behaviors that must not break over time. |\n| 5 | `Load Testing` | Measure behavior under expected traffic. |\n| 6 | `Stress Testing` | Push the system harder to observe how it behaves near its limits. |\n| 7 | `Security Testing` | Verify authentication, rejection of dangerous payloads, and non-exposure of internal data. |\n| 8 | `UI Testing` | Verify that the UI consumes the API correctly and reflects live system state. |\n| 9 | `Fuzz Testing` | Send invalid or random inputs to test robustness. |\n| 10 | `Reliability Testing` | Verify consistency and stability over repeated requests. |\n| 11 | `Contract Testing` | Verify that JSON responses still match the published schemas. |\n\n## Stack\n\n| Component | Role |\n| --- | --- |\n| `app/main.py` | FastAPI business API |\n| `services/auth_service/main.py` | JWT auth service |\n| `services/notification_service/main.py` | Notification microservice |\n| `SQLite` | Fast local database for non-Docker runs |\n| `Postgres` | External database in Docker Compose |\n| `Playwright` | Real browser UI testing |\n| `JMeter` | Load and stress testing |\n| `Docker Compose` | Realistic distributed environment |\n| `OWASP ZAP` | Entry point for baseline security scanning |\n\n## Quick Start\n\nRun the API locally:\n\n```bash\nmake run\n```\n\nRun the distributed Docker stack:\n\n```bash\nmake docker-up\n```\n\nGenerate a demo token locally:\n\n```bash\nmake token\n```\n\nRun the main test campaigns:\n\n```bash\nmake test\nmake test-ui\nmake load\nmake stress\n```\n\n## Overall Campaign Result\n\nLatest documented local campaign: **April 14, 2026**.\n\n| Verification | Observed result |\n| --- | --- |\n| API suite | `19 passed in 10.86s` |\n| Browser UI suite | `2 passed (8.3s)` |\n| Load | `900 samples`, `92.7/s`, `0.00% error` |\n| Stress | `4800 samples`, `258.5/s`, `0.00% error` |\n| Docker Compose | `config validated` |\n\n![Validation report](./docs/screenshots/validation-report.png)\n\n## How To Read The Test Sections\n\nFor the `pytest` suites, [tests/conftest.py](./tests/conftest.py) starts a real local HTTP mini-stack and the tests talk to the application through `httpx`.  \nFor browser UI validation, the campaign uses [playwright/tests/dashboard.spec.js](./playwright/tests/dashboard.spec.js).  \nFor performance, the JMeter plans live in [jmeter/load-test-plan.jmx](./jmeter/load-test-plan.jmx) and [jmeter/stress-test-plan.jmx](./jmeter/stress-test-plan.jmx).\n\n## 1. Smoke Testing\n\n- `What we test`: basic API startup and core endpoint availability.\n- `Why it matters`: this is the fastest signal that the platform is simply alive.\n- `How it is implemented`: [tests/test_smoke.py](./tests/test_smoke.py) calls `/health` and `/api/items`.\n- `What it proves`: the API answers through a real HTTP server and returns a coherent seeded catalog.\n- `Command`: `make test TEST_ARGS='tests/test_smoke.py -q'`\n- `Observed result`: `2 passed in 3.41s`\n- `Raw output`: [docs/validation/raw/smoke.txt](./docs/validation/raw/smoke.txt)\n\n![Smoke output](./docs/screenshots/smoke-output.png)\n\n## 2. Functional Testing\n\n- `What we test`: valid order creation, invalid payload rejection, and reading a created order.\n- `Why it matters`: the business flow must work before any advanced testing has value.\n- `How it is implemented`: [tests/test_functional.py](./tests/test_functional.py) creates an order, expects `201`, then verifies order retrieval and `422` validation failures.\n- `What it proves`: the core business behavior matches the expected API contract for a normal client.\n- `Command`: `make test TEST_ARGS='tests/test_functional.py -q'`\n- `Observed result`: `3 passed in 4.93s`\n- `Raw output`: [docs/validation/raw/functional.txt](./docs/validation/raw/functional.txt)\n\n![Functional output](./docs/screenshots/functional-output.png)\n\n## 3. Integration Testing\n\n- `What we test`: coordination between orders, inventory, dashboard summary, and the notification service.\n- `Why it matters`: an API can be correct in isolation but fail when real components interact.\n- `How it is implemented`: [tests/test_integration.py](./tests/test_integration.py) creates an order, re-reads inventory, re-reads dashboard data, and checks notification effects through the counters.\n- `What it proves`: a successful order flows correctly across the whole application chain, not just inside one function.\n- `Command`: `make test TEST_ARGS='tests/test_integration.py -q'`\n- `Observed result`: `2 passed in 4.75s`\n- `Raw output`: [docs/validation/raw/integration.txt](./docs/validation/raw/integration.txt)\n\n![Integration output](./docs/screenshots/integration-output.png)\n\n## 4. Regression Testing\n\n- `What we test`: idempotency and the guarantee that a failed business operation does not mutate inventory.\n- `Why it matters`: these are classic behaviors that often break during feature work or refactoring.\n- `How it is implemented`: [tests/test_regression.py](./tests/test_regression.py) sends the same request twice with `X-Request-Id`, then verifies that an out-of-stock failure does not change state.\n- `What it proves`: the most sensitive order-creation regressions are explicitly locked down.\n- `Command`: `make test TEST_ARGS='tests/test_regression.py -q'`\n- `Observed result`: `2 passed in 4.83s`\n- `Raw output`: [docs/validation/raw/regression.txt](./docs/validation/raw/regression.txt)\n\n![Regression output](./docs/screenshots/regression-output.png)\n\n## 5. Load Testing\n\n- `What we test`: API behavior under expected traffic.\n- `Why it matters`: a system should stay smooth under realistic usage, not only in an idle state.\n- `How it is implemented`: [jmeter/load-test-plan.jmx](./jmeter/load-test-plan.jmx) exercises `health`, `items`, and `orders` after resetting demo state.\n- `What it proves`: the platform sustains a stable local load with no errors during the documented run.\n- `Command`: `jmeter -n -t jmeter/load-test-plan.jmx -l docs/validation/raw/load-results.jtl`\n- `Observed result`: `900 samples`, `93.2/s`, `0.00% error`\n- `Raw output`: [docs/validation/raw/load.txt](./docs/validation/raw/load.txt)\n\n![Load output](./docs/screenshots/load-output.png)\n\n## 6. Stress Testing\n\n- `What we test`: API behavior under a stronger and more aggressive workload.\n- `Why it matters`: stress testing looks for the edge of the system and how it behaves under pressure.\n- `How it is implemented`: [jmeter/stress-test-plan.jmx](./jmeter/stress-test-plan.jmx) increases the workload after resetting state with larger stock levels.\n- `What it proves`: the system remains coherent and completes the documented local stress campaign without errors.\n- `Command`: `jmeter -n -t jmeter/stress-test-plan.jmx -l docs/validation/raw/stress-results.jtl`\n- `Observed result`: `4800 samples`, `271.1/s`, `0.00% error`\n- `Raw output`: [docs/validation/raw/stress.txt](./docs/validation/raw/stress.txt)\n\n![Stress output](./docs/screenshots/stress-output.png)\n\n## 7. Security Testing\n\n- `What we test`: mandatory `Bearer JWT` authentication, rejection of a bad token, blocking of scripted payloads, and non-leakage of internal fields.\n- `Why it matters`: an order API must not allow anonymous writes or expose internal structure details.\n- `How it is implemented`: [tests/test_security.py](./tests/test_security.py) calls `POST /api/orders` with and without authentication, then injects malicious content into `notes`.\n- `What it proves`: the write surface is protected and defensive validation works on the critical cases covered by the demo.\n- `Command`: `make test TEST_ARGS='tests/test_security.py -q'`\n- `Observed result`: `4 passed in 4.78s`\n- `Raw output`: [docs/validation/raw/security.txt](./docs/validation/raw/security.txt)\n\n![Security output](./docs/screenshots/security-output.png)\n\n## 8. UI Testing\n\n- `What we test`: the link between the `/dashboard` interface and the API, first at the HTML/JS level and then in a real browser.\n- `Why it matters`: a backend can be correct while the screen integration is still wrong.\n- `How it is implemented`: [tests/test_ui.py](./tests/test_ui.py) checks HTTP wiring and bootstrap data; [playwright/tests/dashboard.spec.js](./playwright/tests/dashboard.spec.js) opens Chromium and verifies that the screen updates after a real API order.\n- `What it proves`: the dashboard really consumes the API and reflects an order created in the system.\n- `HTTP command`: `make test TEST_ARGS='tests/test_ui.py -q'`\n- `HTTP result`: `2 passed in 4.78s`\n- `HTTP raw output`: [docs/validation/raw/ui-http.txt](./docs/validation/raw/ui-http.txt)\n- `Browser command`: `npm run ui:test -- --reporter=line`\n- `Browser result`: `2 passed (6.4s)`\n- `Browser raw output`: [docs/validation/raw/ui-browser.txt](./docs/validation/raw/ui-browser.txt)\n\n![UI HTTP output](./docs/screenshots/ui-http-output.png)\n\n![UI Browser output](./docs/screenshots/ui-browser-output.png)\n\n## 9. Fuzz Testing\n\n- `What we test`: API robustness against absurd, random, or invalid values.\n- `Why it matters`: a robust API should reject unexpected inputs cleanly instead of crashing or drifting into bad state.\n- `How it is implemented`: [tests/test_fuzz.py](./tests/test_fuzz.py) sends 60 varied payloads with allowed statuses in `{404, 409, 422}`.\n- `What it proves`: the API remains defensive and returns controlled errors for unreliable input.\n- `Command`: `make test TEST_ARGS='tests/test_fuzz.py -q'`\n- `Observed result`: `1 passed in 4.52s`\n- `Raw output`: [docs/validation/raw/fuzz.txt](./docs/validation/raw/fuzz.txt)\n\n![Fuzz output](./docs/screenshots/fuzz-output.png)\n\n## 10. Reliability Testing\n\n- `What we test`: consistency under repeated requests over a longer run than the other suites.\n- `Why it matters`: some failures only appear after many operations accumulate.\n- `How it is implemented`: [tests/test_reliability.py](./tests/test_reliability.py) loops across `health`, `items`, `orders`, and periodically creates idempotent orders.\n- `What it proves`: final counters, stock levels, and notifications remain coherent after many calls.\n- `Command`: `make test TEST_ARGS='tests/test_reliability.py -q'`\n- `Observed result`: `1 passed in 6.20s`\n- `Raw output`: [docs/validation/raw/reliability.txt](./docs/validation/raw/reliability.txt)\n\n![Reliability output](./docs/screenshots/reliability-output.png)\n\n## 11. Contract Testing\n\n- `What we test`: JSON response compliance against published schemas.\n- `Why it matters`: API consumers depend on response structure, not only on HTTP status codes.\n- `How it is implemented`: [tests/test_contract.py](./tests/test_contract.py) validates responses against [contracts/order.schema.json](./contracts/order.schema.json) and [contracts/order-list.schema.json](./contracts/order-list.schema.json).\n- `What it proves`: response shape is stabilized for clients that consume the API.\n- `Command`: `make test TEST_ARGS='tests/test_contract.py -q'`\n- `Observed result`: `2 passed in 4.71s`\n- `Raw output`: [docs/validation/raw/contract.txt](./docs/validation/raw/contract.txt)\n\n![Contract output](./docs/screenshots/contract-output.png)\n\n## What This Project Demonstrates\n\n- An API tested through a real HTTP server rather than only through an in-memory client.\n- Real `JWT Bearer` authentication on write operations.\n- Multi-service integration with SQL persistence and notification delivery.\n- A clear educational walkthrough of 11 major API testing types.\n- Real execution screenshots embedded directly in the documentation.\n\n## Current Limits\n\n- Local non-Docker runs use `SQLite`, not `Postgres`.\n- The JWT flow is real, but it does not yet use a full OIDC provider such as Keycloak.\n- The `ZAP` entry point is useful for baseline scanning, but it is not a full offensive security audit.\n- The notification service stays intentionally simple to keep the demo readable.\n\n## Useful Files\n\n- API: [app/main.py](./app/main.py)\n- Persistence: [app/store.py](./app/store.py)\n- Auth: [services/auth_service/main.py](./services/auth_service/main.py)\n- Notification: [services/notification_service/main.py](./services/notification_service/main.py)\n- Docker config: [docker-compose.yml](./docker-compose.yml)\n- Makefile: [Makefile](./Makefile)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstefen-taime%2Fapi-testing-demo-v2","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstefen-taime%2Fapi-testing-demo-v2","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstefen-taime%2Fapi-testing-demo-v2/lists"}