feat(qa): TestRail QA automation — Playwright pipeline with grounded specs, spec cache, and ephemeral Docker envs#1160
feat(qa): TestRail QA automation — Playwright pipeline with grounded specs, spec cache, and ephemeral Docker envs#1160Miraeld wants to merge 18 commits into
Conversation
Up to standards ✅🟢 Issues
|
| Metric | Results |
|---|---|
| Coverage variation | Report missing for 3fb41021 |
| Diff coverage | ✅ ∅ diff coverage (50.00%) |
Coverage variation details
Coverable lines Covered lines Coverage Common ancestor commit (3fb4102) Report Missing Report Missing Report Missing Head commit (7d14a41) 19533 629 3.22% Coverage variation is the difference between the coverage for the head and common ancestor commits of the pull request branch:
<coverage of head commit> - <coverage of common ancestor commit>
Diff coverage details
Coverable lines Covered lines Diff coverage Pull request (#1160) 0 0 ∅ (not applicable) Diff coverage is the percentage of lines that are covered by tests out of the coverable lines that the pull request added or modified:
<covered lines added or modified>/<coverable lines added or modified> * 100%
1 Codacy didn't receive coverage data for the commit, or there was an error processing the received data. Check your integration for errors and validate that your coverage setup is correct.
NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.
…ess spec Design-only documents for the upcoming QA automation deep audit: - canary-testrail-spec.md: consolidated spec covering TestRail scenario generation, TestRail run execution via Canary, and Canary E2E integration in the pipeline - canary-wp-spec.md: Canary × WordPress foundational spec (WP fixtures, agent inheritance pattern, session lifecycle reference) No implementation — brainstorm/audit prep for week of 2026-06-30. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…line New agents: - canary-imagify-session-agent: Imagify-specific Canary session runner, extends canary-wp-session-agent (user-level) with Imagify URLs, selectors, ability slugs, and imagify-abilities fixture - canary-e2e: drop-in replacement for e2e-qa-tester using Canary CLI; same JSON contract + canary_sessions field; reads qa-plan.md P0/P1 flows - testrail-scenario-agent: analyses PRs → stages YAML → publishes to TestRail with refs-based dedup and section auto-creation on confirm - testrail-run-agent: fetches TestRail run → executes cases via Canary → results table → posts pass/fail/blocked on user confirm New skills: - /testrail-scenarios: entry point for PR → TestRail scenario generation - /testrail-run: entry point for TestRail run execution via Canary Modified: - qa-engineer: add e2e_mode routing (playwright/canary), write qa-plan.md before E2E delegation, route to canary-e2e or e2e-qa-tester accordingly - orchestrator: add e2e_mode startup selection with canary signal detection Spec: canary-testrail-spec.md updated with all 13 audit questions resolved. Also archiving testrail-automation.md (superseded by canary-testrail-spec.md). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…session end
Canary has no --output flag, so artifacts always land in ~/.canary/sessions/<id>/
first. After each session end the agents now mv the directory to
.ai/{issue_N}/canary/<id>/, patch artifactsDir in session.json, and leave a
symlink at the original path so `npx @usecanary/ui` continues to work.
- canary-e2e: add relocation block in Step 3, update all path refs throughout
- canary-imagify-session-agent: add relocation step in Workflow with both
caller conventions (canary-e2e uses QA_PLAN_PATH, testrail-run-agent uses
TESTRAIL_RUN_ID)
- canary-wp-spec.md: trim §1 Problem + §2 Vision (historical rationale, no
value to future sessions), renumber §3-11 → §2-10, add artifact relocation
note to the primer
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Remove everything that is explanation-for-humans rather than operative instruction for AI: design rationale sections, "why we did this" blocks, stale file-lists and open-question tables, duplicate architecture prose, implementation-order checklists, and obsolete "optional future" sections. - canary-wp-spec.md: §2 Architecture collapsed to 3 tight subsections (routing, inheritance, artifact locations); removed §7 GitHub Actions, §8 open questions, §9 file list; trimmed §5 screenshot shell block, §6 TS example, "Why GET not POST" aside - canary-testrail-spec.md: removed pipeline context block, "How they connect" prose, name-change note, both Goal subsections, dedup fallback, §6.1/6.2/6.4 (Problem/Vision/design now in agent files), §9 file list, §11 implementation order; trimmed §8 replay, §7.1 "why this split", §7.3 trust-guard (updated: guard not present); updated artifact paths to .ai/testrail/$RUN_ID/canary/ - testrail-run-agent.md: add relocation step after session end (move to .ai/testrail/$RUN_ID/canary/); update all path references - testrail-scenarios/SKILL.md, testrail-run/SKILL.md: remove meta-sentences - testrail-automation.md: deleted (superseded by canary-testrail-spec.md) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add a TestRail scenario reviewer that runs between generation and publish: - testrail-review-agent + /testrail-review skill: prune low-signal cases, collapse near-duplicates, fix smoke-test flags, and enforce cross-file section coherence; moves reviewed YAML pending/ -> reviewed/. - testrail-scenario-agent: add "quality over quantity" rules (no unit-test runner cases, no source-inspection cases, no near-duplicates, smoke-test discipline); publish mode now reads from reviewed/. - testrail-scenarios skill: offer the reviewer after staging; publish reads reviewed/. Add .claude/testrail/A-plus-design.md — the design for making the TestRail -> browser execution step reliable (grounded Explorer map + state isolation + anti-hallucination guards + TestRail expected-results as the assertion oracle). Design only; implementation deferred. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…gent Implements the A+ design (.claude/testrail/A-plus-design.md): replace the fragile run-time "prose -> Playwright" guess with grounded, closed-loop execution. - testrail-explorer-agent (NEW, opus): drives the live app via Canary, captures real locators + seed/teardown + verification criteria per feature, writes/refreshes .claude/testrail/specs/*.md stamped with source_files + derived_sha; --check drift mode writes nothing. - /testrail-setup skill (NEW): thin entry point (all / <feature> / --check). - specs/_foundation.md (NEW): shared non-DOM base, pre-filled with known constants; live rows + unverified API-key path marked "captured by Explorer". - testrail-run-agent (EDIT, sonnet): resolve case -> feature spec via whole-element section match, load _foundation + feature spec as grounding, seed prerequisites + LIFO teardown (state isolation), assert against the TestRail expected-result (oracle), warn on stale grounding. Reviewed by workflow-reviewer (NEEDS_REVISION -> fixed): anchored the section-id resolution to whole array elements (872 no longer matches 8724), canonicalised the "Ground truth" section across explorer/run-agent/design so destructive markers are actually consumed, documented _foundation as the always-loaded non-resolvable base, and moved Canary step scripts to per-session /tmp dirs. Authoring only — Explorer not yet run; mcp-abilities feature spec is the next step (needs live wp-env + Canary). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ve explore) Explorer confirmed: API key lives in `imagify_settings` WP option (not settings.local.json). Adds authenticated curl helpers for REST/MCP seeding, real attachment IDs, and live setting keys. Stamps derived_sha=4bc0e342 / last_explored=2026-06-30. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
settings.md: grounded live (Canary session mr0faaqg). Covers sections 32
(Settings) and 7689 (general settings). Real locators captured:
- auto_optimize: getByLabel("Auto-Optimize images on upload"), #imagify_auto_optimize
- save: #submit
- notice: #setting-error-settings_updated (C14169 escaping via wp_kses)
- C174 documented as BLOCKED (requires multisite)
Browser fix: chromium-1208 symlinked to chromium-1217 (extraction bug workaround).
testrail-run skill + agent: add --cases filter to execute only specific
case IDs (comma-separated), enabling targeted runs without burning tokens
on all 66 cases.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… config file loading - Fold testrail-review-agent into testrail-scenario-agent as a third mode (generate/review/publish) — same artifact, same rules, previously duplicated near-verbatim between the two files. - Update testrail-review and testrail-scenarios skills to spawn the merged agent. - Ground testrail-run-agent on dual nginx/apache environments, config loaded from .ai/settings.local.json, WP-CLI env setup, and batch result posting. - Add mcp-abilities.md and mixpanel-tracking.md grounded specs.
A-plus-design.md's core architecture (Explorer/Executor split, grounded specs, drift detection, state isolation) is now built in testrail-explorer-agent.md and testrail-run-agent.md. canary-testrail-spec.md and canary-wp-spec.md were pre-build design drafts, superseded by the same implementation.
…y case Add a coverage pre-check (Step 2b) to testrail-run-agent that resolves spec coverage for the whole filtered test list up front, then asks once per missing/ambiguous TestRail section whether to generate the spec or block and continue — instead of surfacing the same BLOCKED reason on every affected case. The run agent has no Agent-spawning tool by design, so the generate path is handled by the testrail-run skill: it spawns testrail-explorer-agent for the named feature(s), then re-invokes testrail-run-agent on the same run/case selection once grounding is done.
Canary's QuickJS scripting API has near-zero training-data representation compared to @playwright/test, causing more script-authoring errors than a well-known tool would. Rewrites testrail-run-agent to generate one real .spec.ts per TestRail case (test.step()/expect.soft(), executed via `npx playwright test --reporter=json`) with results published as a live Artifact dashboard, and testrail-explorer-agent to discover locators via mcp__playwright instead of the Canary CLI. Deletes canary-e2e.md and canary-imagify-session-agent.md; e2e-qa-tester (already Playwright-MCP-based) is now the sole PR-QA path, with e2e_mode/canary-e2e branching removed from qa-engineer and the orchestrator. Also rewrites e2e-qa-tester to draft its spec directly from the PR's diff and existing POMs and run it via the Playwright Test runner, falling back to a single targeted mcp__playwright snapshot only when a drafted locator or assertion doesn't hold — cutting the per-action MCP round-trips of a full interactive walkthrough down to the rare case an assumption is actually wrong.
…QA envs - .claude/testrail/translation.md: prose→spec.ts thinking protocol the run agent must read before translating (oracle-first reading, step classification, three-source noun resolution, plan-before-code, failure interpretation hierarchy) - Spec compile-cache: generated case specs live in Tests/e2e/testrail-cases/ (committed corpus, @steps-hash header decides reuse vs re-translation); end-of-run user-gated promote/keep/delete with CI promotion shortlist - Ephemeral QA envs: bin/qa-env.sh + Tests/e2e/qa-env/ (Docker compose, one nginx + one apache WordPress, installs build-zip output, generates .ai/settings.local.json, DB snapshots for per-case reset); run agent provisions automatically when no reachable config exists - Live results ledger .ai/testrail/<run>/results.md updated per case (replaces per-case Artifact redeploys; crash/turn-budget resumable) - Audit fixes: trace/video resolved by glob (Playwright nests per-test dirs), apache_cases per-case frontmatter (schema + settings.md), empty-apache-path guard, merge-base ancestry drift checks, qa-plan contract closed in e2e-qa-tester, compile gate before execution, ability slugs corrected to the 7 that exist - Knowledge consolidation: imagify-playwright-fixtures.md folded into _foundation.md; hardcoded ports/creds replaced by config-driven $E2E_URL - Scenario agent: live section fetch + duplicate-section guard at publish; automation_hints captured from the PR diff into .claude/testrail/hints.yml Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Live smoke (run 1283, cases 26359/26362 — both PASS with trace+video) surfaced: - .distignore lacked /.ai, /node_modules, /generatedpackages, /.e2e-screenshots, /.e2e-temp — build-zip.sh was packing 240MB of local artifacts (incl. Canary browser profiles with cookies) into imagify.zip; now 2.9MB - compose mounted ../../generatedpackages (= Tests/generatedpackages) — needs three levels up to repo root - TESTRAIL_OUTPUT_DIR must be $OUT/artifacts, never $OUT: Playwright cleans outputDir at test start and was deleting results.json mid-run (bug existed in the original design too) — run agent + config header updated - DB snapshot/restore moved inside the DB container (mariadb-dump/mariadb over local socket): the wordpress:cli image's newer client refuses non-SSL TCP and WP-CLI doesn't reliably forward ssl flags - qa-env.sh preserves an existing imagify.api_key from the old config when IMAGIFY_TESTS_API_KEY is unset - run agent documents the Node >= 18 requirement (nvm-pinned Node 16 shadows Homebrew's Node on Local-user machines) First two cached case specs committed under Tests/e2e/testrail-cases/ (@status green 2026-07-03), translated per .claude/testrail/translation.md. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Run agent Step 0 is Docker-only: always provision via bin/qa-env.sh (the generated .ai/settings.local.json is the only config source; wp_path / hand-maintained Local-site support removed everywhere) - New Step 0-end: qa-env.sh down is mandatory at the end of every run (posting done/declined, disposition, or turn-budget stop) — environments never outlive the run; evidence under .ai/ survives teardown - Specs cleaned of pre-Docker environment references: 'Local site shell' → $WPCMD, stale admin/admin creds → loginAsAdmin + generated config, personal machine path removed from mcp-abilities source-of-truth note (re-ground via /testrail-setup mcp-abilities after 2.3.0 merge) - _foundation.md env section rewritten for the ephemeral qa-env Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…te_thumbnails Newer wordpress-stubs no longer flag the wp-admin/includes/image.php require_once, and PHPStan treats an unmatched ignore as an error (ignore.unmatchedLine, non-ignorable). composer.lock is gitignored, so CI installs fresh deps — this was about to start failing on develop too. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Description
TestRail QA automation pipeline for Imagify, built on Playwright + ephemeral Docker environments (Canary was retired mid-branch; no Canary code remains). No product code is changed — the diff is entirely QA infrastructure (
.claude/,Tests/e2e/,bin/,.distignore,.gitignore).Note
Parts of this pipeline were AI-generated (Claude Code) and human-reviewed. The full run flow was executed live before this PR was refreshed — see "What was tested".
Two user-facing goals:
/testrail-scenarios— generate TestRail test cases from merged PRs (staged as YAML for human review, published on explicit confirm, deduped viarefs)./testrail-run— fetch a TestRail run (run ID / milestone / active), translate each human-written case into a Playwright.spec.ts, execute sequentially with trace/video evidence, keep a live results ledger, and post results back to TestRail only after user confirmation.Type of change
Detailed scenario
What was tested
Automated, live end-to-end run (2026-07-03):
bin/qa-env.sh up(zip build → Docker up → WP install on nginx + apache → plugin install → API key seed → DB snapshot) → TestRail run 1283 resolved via API → cases C26359 and C26362 translated per the doctrine → compile gate → executed → both PASS (~1.1s each, trace + video captured) → results ledger written → DB snapshot reset verified → post-reset replay PASS →qa-env.sh down. Posting to TestRail was intentionally skipped (both cases already PASSED in the run). The two resulting cached specs are committed underTests/e2e/testrail-cases/as living proof.Execution surfaced and fixed 5 bugs review alone would not have caught, notably:
.distignorewas missing/.ai,/node_modules,/generatedpackages—bin/build-zip.shpacked 240 MB of local artifacts (including browser profiles with cookies) intoimagify.zip; now 2.9 MB / 1,280 files, verified clean. Also: Playwright cleansoutputDirat test start (reporter JSON must live outside it), trace/video nest in per-test subdirs (resolved by glob), DB dump/restore moved inside the DB container (newer mariadb client refuses non-SSL TCP), Node ≥ 18 requirement documented.How to test
Requirements: Docker Desktop, Node ≥ 18,
TESTRAIL_USERNAME/TESTRAIL_API_KEYin the environment, optionallyIMAGIFY_TESTS_API_KEY.The run agent never posts to TestRail without an explicit confirmation, and never deletes cached specs without a user choice.
Affected Features & Quality Assurance Scope
No runtime plugin feature is affected — zero PHP changes vs
develop(verified: the diff excludes everything outside.claude/,Tests/,bin/,.distignore,.gitignore). QA scope is the pipeline itself: environment provisioning, TestRail API interaction (read + gated write), Playwright execution, and the distribution-zip content (.distignorechange — see Risks).Technical description
Documentation
Reading order for review:
.claude/testrail/translation.md— translation doctrine: how prose TestRail cases become Playwright specs (oracle-first reading, step classification, POM → grounded-spec → live-observation noun resolution, plan-before-code, failure-interpretation hierarchy)..claude/agents/testrail-run-agent.md— the run flow: provision → resolve run → coverage pre-check → per-case (ground → cache check → seed → translate → lint/compile gate → execute → outcome → results ledger → LIFO teardown) → disposition → gated posting → env teardown.bin/qa-env.sh+Tests/e2e/qa-env/— ephemeral environments: one nginx + one apache WordPress frombin/build-zip.sh's zip, generated.ai/settings.local.json, DB snapshots for per-case reset. Environments never outlive the run..claude/testrail/specs/— grounded feature specs (drift-stamped viaderived_sha, mapped bytestrail_sections, per-caseapache_cases).Tests/e2e/testrail-cases/— the spec compile-cache: one committed.spec.tsper case with a@steps-hashheader; unchanged case + fresh grounding → reused with zero re-translation. End of run: user-gated promote-to-CI / keep / delete.New dependencies
None in the plugin. Tooling-only: Docker (dev machine requirement for TestRail runs),
mariadb/wordpress/nginxDocker images pulled at provision time. No composer/npm dependency changes.Risks
.distignorechange alters distribution-zip content — mitigated: verified the built zip (2.9 MB, 1,280 files) contains no.ai/,node_modules/,.claude/, orTests/paths and installs+activates correctly on both qa-env sites; wordpress.org CI is unaffected (fresh checkout, no npm step). This exclusion list fix should also be backported todevelopas a standalone PR (flagged).refsprevents duplicate cases; duplicate-section guard at publish.Mandatory Checklist
Code validation
Code style
Unticked items justification
Built-in tests: no product PHP changed, so there is nothing for PHPUnit to cover. The executable pieces were validated by live execution instead:
qa-env.shfull lifecycle (up / reset / down), the Playwright config via a real two-case run with evidence, and the two committed specs underTests/e2e/testrail-cases/are runnable tests (executed green twice, including after a DB reset). Agent instruction files (.claude/*.md) are not unit-testable by nature.Additional Checks
🤖 Generated with Claude Code