--- name: feature-testing description: Post-implementation end-to-end feature verification. Use after implementing a feature to verify it works across UI, API, and agent layers using Playwright MCP tools, make dev-push, diagnostic logs API, and structured test logging. --- # Feature Testing ## Overview Use this skill after implementing a feature to verify it actually works end-to-end. It guides you through phased verification across UI, API, and agent layers — using Playwright MCP for browser testing, `make dev-push` for agent deploys, the diagnostic logs API for agent verification, and a markdown log for tracking results. **When to invoke:** After completing implementation of any feature, bugfix, or behavior change. Before claiming "done" or creating a PR. **Credentials:** NEVER hardcode credentials. Always read from root `.env` using the `E2E_*` variables (`E2E_BASE_URL`, `E2E_API_URL`, `E2E_ADMIN_EMAIL`, `E2E_ADMIN_PASSWORD`, `E2E_MACOS_DEVICE_ID`, `E2E_WINDOWS_DEVICE_ID`). For agent deploys, use `BREEZE_API_KEY` and `BREEZE_DEV_DEVICE` from `.env.dev`. Source these files before running any commands that need auth. ## Phase 1: Classify Feature Determine which phases to run based on what was implemented: | Feature Type | Example | Phases | |---|---|---| | UI-only | New dashboard widget, form validation | 2, 4, 7 | | API-only | New endpoint, query change | 2, 5, 7 | | Agent-side | New command handler, collector | 2, 3, 5, 6, 7 | | Full-stack | New feature spanning UI + API + agent | 2, 3, 4, 5, 6, 7 | ## Phase 2: Environment Check ### Required .env Variables Read the root `.env` file and confirm these are set: | Variable | Purpose | Example | |---|---|---| | `E2E_BASE_URL` | Web app URL | `http://localhost:4321` (or the `baseUrl` from `pnpm wt-stack up`) | | `E2E_API_URL` | API URL | `http://localhost:3001` | | `E2E_ADMIN_EMAIL` | Login email | `admin@breeze.local` | | `E2E_ADMIN_PASSWORD` | Login password | (set in .env) | | `E2E_MACOS_DEVICE_ID` | macOS test device | UUID | | `E2E_WINDOWS_DEVICE_ID` | Windows test device | UUID | Point these at a local or lab stack, never at a hosted production URL. ### Docker Services Check that required services are running: ```bash docker compose ps --format "table {{.Name}}\t{{.Status}}" | grep -E "api|web|postgres|redis" ``` All four services (api, web, postgres, redis) must show "Up". ### Device Online Check (agent tests only) ```bash curl -sf "${E2E_API_URL}/api/v1/devices/${E2E_MACOS_DEVICE_ID}" \ -H "X-API-Key: ${BREEZE_API_KEY}" | python3 -c "import sys,json; d=json.load(sys.stdin); print(f'{d[\"hostname\"]} — {d[\"status\"]}')" ``` ### Clear Rate Limits Prevent login failures during testing: ```bash docker exec breeze-redis redis-cli -a "$(grep '^REDIS_PASSWORD=' .env | cut -d= -f2)" --no-auth-warning EVAL "local k=redis.call('KEYS','login:*'); for _,v in ipairs(k) do redis.call('DEL',v) end; return #k" 0 ``` ## Phase 3: Build & Deploy (Agent Only) Use `make dev-push` to build and deploy agent code to the test device. The Makefile target at `agent/Makefile:116-144` handles: detect platform, cross-compile, upload binary, trigger restart. ### Deploy ```bash cd agent make dev-push ``` Reads defaults from `../.env.dev` (gitignored): - `BREEZE_DEV_DEVICE` — target device UUID - `BREEZE_API_KEY` — API key (`brz_...`) or JWT - `BREEZE_API_URL` — API base URL Override any default: `make dev-push DEVICE= AUTH_TOKEN= API_URL=` ### Verify Deploy Landed Poll the device API to confirm the new version is running: ```bash curl -sf "${E2E_API_URL}/api/v1/devices/${DEVICE_ID}" \ -H "X-API-Key: ${BREEZE_API_KEY}" | python3 -c "import sys,json; d=json.load(sys.stdin); print(f'version={d.get(\"agentVersion\",\"?\")} status={d[\"status\"]}')" ``` The version should show `dev-`. Agent typically restarts within 5-10 seconds. ## Phase 4: UI Verification (Playwright MCP) Use Playwright MCP tools for browser-based verification. Load tools via `ToolSearch` first. ### Login Pattern ``` 1. browser_navigate → ${E2E_BASE_URL}/login 2. browser_snapshot → confirm login form rendered 3. browser_fill_form → email + password fields 4. browser_click → submit button 5. browser_wait_for → URL changes away from /login (timeout 10s) 6. browser_snapshot → confirm dashboard loaded ``` ### Navigation URLs | Page | URL | |---|---| | Dashboard | `/` | | Devices | `/devices` | | Device Detail | `/devices/{id}` | | Alerts | `/alerts` | | Scripts | `/scripts` | | Automations | `/automations` | | Reports | `/reports` | | Settings | `/settings` | | Monitoring | `/monitoring` | | Discovery | `/network/discovery` | | CIS Benchmarks | `/compliance/cis` | | Policies | `/policies` | ### Verification Steps 1. **Snapshot** — `browser_snapshot` to get accessibility tree, confirm elements render 2. **Interact** — `browser_click`, `browser_fill_form`, `browser_select_option` to exercise the feature 3. **Screenshot** — `browser_take_screenshot` for visual confirmation if snapshot isn't enough 4. **Console check** — `browser_console_messages` to catch JS errors 5. **Network check** — `browser_network_requests` to verify API calls succeed (no 4xx/5xx) ### Astro Hydration Note Astro React islands hydrate after initial page load. After `browser_navigate`, wait for network idle before interacting with React components. If clicks don't register, the island hasn't hydrated yet — add a short wait or re-snapshot to confirm interactive elements are present. ### Common Selectors Use `browser_snapshot` output (accessibility tree) to find elements. Common patterns: - Buttons: look for `button` role with name text - Links: look for `link` role with name text - Forms: look for `textbox` role with name matching label - Tables: look for `table`, `row`, `cell` roles ## Phase 5: API Verification ### Authentication Methods | Method | Header | When to use | |---|---|---| | API Key | `X-API-Key: brz_...` | Automated testing, scripts | | JWT | `Authorization: Bearer ` | After login, browser-initiated | To get a JWT for API testing: ```bash curl -sf -X POST "${E2E_API_URL}/api/v1/auth/login" \ -H "Content-Type: application/json" \ -d "{\"email\":\"${E2E_ADMIN_EMAIL}\",\"password\":\"${E2E_ADMIN_PASSWORD}\"}" \ | python3 -c "import sys,json; print(json.load(sys.stdin)['tokens']['accessToken'])" ``` ### Common Endpoints | Endpoint | Method | Purpose | |---|---|---| | `/api/v1/devices` | GET | List devices | | `/api/v1/devices/:id` | GET | Device detail | | `/api/v1/devices/:id/diagnostic-logs` | GET | Agent logs | | `/api/v1/alerts` | GET | List alerts | | `/api/v1/scripts` | GET | List scripts | | `/api/v1/automations` | GET | List automations | | `/api/v1/auth/login` | POST | Login | | `/api/v1/auth/refresh` | POST | Refresh token | | `/api/v1/dev/push` | POST | Dev push binary | ### Verification Pattern ```bash # Example: verify a new endpoint returns expected data TOKEN=$(curl -sf -X POST "${E2E_API_URL}/api/v1/auth/login" \ -H "Content-Type: application/json" \ -d "{\"email\":\"${E2E_ADMIN_EMAIL}\",\"password\":\"${E2E_ADMIN_PASSWORD}\"}" \ | python3 -c "import sys,json; print(json.load(sys.stdin)['tokens']['accessToken'])") curl -sf "${E2E_API_URL}/api/v1/" \ -H "Authorization: Bearer ${TOKEN}" | python3 -m json.tool ``` Check for: - Correct HTTP status code - Expected response shape (fields present, correct types) - No error messages in response body - Correct data values ## Phase 6: Agent Log Verification (Agent Only) ### Diagnostic Logs API `GET /api/v1/devices/:deviceId/diagnostic-logs` Query parameters: | Param | Type | Description | |---|---|---| | `level` | string | Comma-separated: `debug`, `info`, `warn`, `error` | | `component` | string | Filter by component: `heartbeat`, `websocket`, `updater`, `main`, etc. | | `since` | ISO string | Start of time range | | `until` | ISO string | End of time range | | `search` | string | Text search in message + fields | | `page` | number | Page number (default 1) | | `limit` | number | Results per page (default/max 1000) | Example: ```bash curl -sf "${E2E_API_URL}/api/v1/devices/${DEVICE_ID}/diagnostic-logs?level=error,warn&since=$(date -u -v-5M +%Y-%m-%dT%H:%M:%SZ)" \ -H "Authorization: Bearer ${TOKEN}" | python3 -m json.tool ``` ### Direct SQL Fallback If the API is unreachable or for richer queries: ```bash docker exec breeze-postgres-dev psql -U breeze -d breeze -c " SELECT timestamp, level, component, message, agent_version FROM agent_logs WHERE device_id = '${DEVICE_ID}' AND timestamp > now() - interval '5 minutes' ORDER BY timestamp DESC LIMIT 30;" ``` ### What to Look For - **No new errors/warnings** after deploy — the feature shouldn't introduce regressions - **Expected log messages** — if the feature includes logging, confirm those messages appear - **Correct agent_version** — should show `dev-` matching the deploy - **Component tagging** — logs should use the correct component name ### Enable Debug Shipping Default shipping level is `warn`. To get full detail during testing: ```json { "type": "set_log_level", "payload": { "level": "debug", "durationMinutes": 30 } } ``` Send via device commands endpoint or WebSocket. Auto-reverts after duration. ## Phase 7: Record Results Log test results in `docs/testing/FEATURE_TEST_LOG.md` for traceability. ### Entry Format ```markdown ## [Feature Name] — YYYY-MM-DD **Branch:** `branch-name` **Commit:** `abc1234` **Tested by:** Claude / Human **Result:** PASS / PARTIAL / FAIL ### What was tested - [ ] UI: description of UI verification - [ ] API: description of API verification - [ ] Agent: description of agent verification ### Evidence - Screenshot: (path or description) - API response: (summary) - Agent logs: (relevant excerpt) ### Issues Found - (none, or describe issues) ### Notes - (any additional context) ``` ### TaskCreate Checklist After recording results, create tasks for any follow-up: - Failing tests that need investigation - Edge cases discovered during verification - Performance concerns observed - Documentation gaps ## Phase 8: Tear Down If you brought the stack up for this verification (`pnpm wt-stack up`, `pnpm test-stack up`, or a compose-mode `up`), tear it down from the same worktree and branch — nothing does it for you: ```bash pnpm wt-stack down # dev stack (drops volumes) pnpm test-stack down # integration pg+redis docker compose ls -a # confirm nothing from this run is still listed ``` If you verified against a shared dev stack you did not start, leave it up. Either way, state in the final summary what is still running. Full checklist (orphaned projects, bare containers): `worktree-stack` skill → "Tear down when done". ## Quick Reference ### Playwright MCP Cheat Sheet Load tools first: `ToolSearch("playwright")` | Action | Tool | |---|---| | Open URL | `browser_navigate` | | Get page structure | `browser_snapshot` | | Click element | `browser_click` | | Fill form fields | `browser_fill_form` | | Take screenshot | `browser_take_screenshot` | | Check JS errors | `browser_console_messages` | | Check network | `browser_network_requests` | | Press key | `browser_press_key` | | Wait for element | `browser_wait_for` | | Select dropdown | `browser_select_option` | ### Dev-Push Commands ```bash cd agent && make dev-push # Use .env.dev defaults cd agent && make dev-push DEVICE= # Override device cd agent && make dev-push API_URL= # Override API URL ``` ### Rate Limit Clear ```bash docker exec breeze-redis redis-cli -a "$(grep '^REDIS_PASSWORD=' .env | cut -d= -f2)" --no-auth-warning EVAL "local k=redis.call('KEYS','login:*'); for _,v in ipairs(k) do redis.call('DEL',v) end; return #k" 0 ```