| description | Run automated QA on a frontend PR. Executes QA steps from the PR description against localhost using Playwright, then posts PASS/FAIL results with screenshots back to the PR. Use when asked to QA a PR or run qa-bot. |
|---|
If a PR number or URL was passed as an argument, use it. Otherwise, ask the user:
Which PR would you like to QA? (provide a PR number or URL)
Resolve the PR details with:
gh pr view <number_or_url> --json number,url,title,headRefName,bodyParse the ## QA Steps section from the PR body. Each filled-in line item (e.g. - [ ] ... or - ...) is one step. Ignore unfilled template placeholders like [Add QA steps here].
If no filled-in QA steps are found, fall back in this order:
Fallback 1 β Linear ticket: Check the PR title and description for a Linear ticket ID (e.g. [MON-170], Closes MON-170). If found, fetch the ticket:
- Use the Linear MCP
get_issuetool to retrieve the ticket title and description - Infer a QA plan from the ticket's description and the PR title
- Present the inferred steps to the user and ask for confirmation before proceeding:
I couldn't find QA steps in the PR. Based on Linear ticket MON-170, here's what I plan to test:
- ...
- ... Does this look right, or would you like to adjust?
Fallback 2 β Prompt the user: If there's no Linear ticket, or the ticket description is too vague to infer steps, ask:
This PR doesn't have QA steps and I couldn't find a clear Linear ticket to infer from. Please describe what you'd like me to test.
TODO: Once Woon's skill is named and its interface is defined, call it here, passing the raw QA steps and getting back clarified, Playwright-executable steps.
For now, use the raw steps as-is.
Branch assumption: The user is expected to already be on the correct branch before invoking qa-bot. Exception: if the PR branch has been merged and deleted from remote, run from main β the feature will already be present. Do not stash, checkout, or pull branches automatically unless the user explicitly asks.
Check localhost is running: Navigate to http://localhost:3001 and confirm the app responds. If it doesn't respond:
- Run
pnpm devin the back-office repo directory (run in background) - Poll
http://localhost:3001until it responds (up to 60 seconds) - If still not responding after 60s, tell the user and stop.
Check for pending server migrations:
cd /Users/anthony/dev/server && mix ecto.migrations 2>&1 | grep "down"If any migrations are listed as down, stop and prompt the user:
There are pending database migrations on the server. Please run
mix ecto.migratein the server repo before QA can proceed.
Before running the steps, start a video recording using Playwright's recordVideo option:
- Pre-create the recording directory via Bash:
mkdir -p /tmp/qa-bot-recording - Use
browser_run_code_unsafeto create a new browser context with recording enabled:
async (page) => {
const browser = page.context().browser();
const ctx = await browser.newContext({
recordVideo: { dir: '/tmp/qa-bot-recording', size: { width: 1280, height: 800 } },
viewport: { width: 1280, height: 800 }
});
const p = await ctx.newPage();
// ... login, then run all QA steps ...
const video = p.video();
await ctx.close();
return { videoPath: video ? await video.path() : null };
}Login in the new context: navigate to /account/signin, fill input[type=email] and input[type=password], click button[type=submit], then waitForURL('**/users**').
For each clarified step:
- Execute the action in the recorded context
- Mark the step as PASS or FAIL with a one-line reason
If a step fails, continue to the next step (don't abort the whole run).
Upload the recording to a GitHub release asset:
gh release create "qa-bot-$(date +%s)" --repo <owner>/<repo> --title "qa-bot recording" --notes "" --draft <video_path>#qa-recording.webm
# Get the download URL:
gh release view <tag> --repo <owner>/<repo> --json assets --jq '.assets[-1].url'Post a comment to the PR:
gh pr comment <number> --body "<results>"Format the comment as:
## π€ qa-bot Results β
/β
| # | Step | Status | Notes |
|---|------|--------|-------|
| 1 | Navigate to /transactions and verify table loads | β
PASS | Table rendered with 5 rows |
| 2 | Click into a transaction and confirm Details tab | β FAIL | Details tab not found in snapshot |
π¬ [QA recording](<release_asset_url>)
_Run `/qa-bot` to re-check after fixes._
The overall header emoji is β if all steps pass, β if any fail.
Look up the PR author's GitHub team to find their Slack channel:
# Find which engineering team the PR author belongs to
for team in execution foundation trading growth customer-accounts issuers investing money; do
gh api orgs/hiivemarkets/teams/$team/memberships/<author_login> 2>/dev/null | grep -q '"state":"active"' && echo $team && break
doneMap the team slug to the Slack channel using the #team-dope-<slug>-prs pattern. Check it exists:
# Use Slack MCP slack_search_channels with query "team-dope-<slug>-prs" to confirm the channel IDOnly post to Slack if ALL of the following are true:
- The PR branch is still open (not merged)
- All QA steps passed
If any step failed, or the PR is already merged: skip the Slack post silently.
If the channel is not found: skip the Slack post silently. Do not fall back to any other channel.
- URL:
http://localhost:3001 - Login via
/account/signin - Email:
anthony+sa@hiive.com - Password:
Letmeintoh11ve
- After
browser_navigate, usebrowser_wait_forwith a visible string before interacting - Use
browser_snapshotto understand page state before asserting PASS/FAIL - For Chakra
<Select>elements, usebrowser_evaluatewith the React native setter IIFE trick (see smoke-test-create-transaction skill) browser_select_optionis unreliable β avoid it