mcpbeat Sign in

Visual Test Agent Skill

Visually verify a component by launching its Storybook story and taking a screenshot with playwright-cli. Use after making visual changes to a component.

2k tokens
context cost
the whole folder, loaded on every use
1
files
instructions only
0
copies elsewhere
how many repositories repackaged it
20188
stars on the repo
on the repository, not the skill itself

Install

one command, takes just this skill from the repository
npx skills add https://github.com/microsoft/fluentui --skill visual-test

What it tells the agent to use

found in the instruction text
Bash runs shell commands — read the instruction before connecting
Read reads your files

The instruction itself

8 sections, as written by the author

Visual Test a Component

Visually verify $ARGUMENTS by launching Storybook and capturing a screenshot with playwright-cli.

Prerequisites

Run playwright-cli via npx so nothing is installed globally on the user's box. The first invocation downloads @playwright/[email protected] into the npx cache; subsequent calls are cached. Every command below uses this form:

npx -y @playwright/[email protected] <command>

Critical: use the per-component Storybook only

Always boot the per-component stories package (react-<component>-stories) via nx storybook target, which only imports its own component's stories and dependencies.

Steps

  • Find the component's stories package. Each v9 component has a dedicated stories package named react-<component>-stories:
   yarn nx show project react-<lowercase-component-name>-stories --json

If nx returns nothing with output of Could not find project react-<component>-stories, the component doesn't have its own stories package — check for a preview package (react-<component>-preview-stories) or ask before proceeding.

  • Start the component's Storybook dev server. Use the storybook target on the stories project directly — it's the most portable, since library aliases like react-<component>:start were only added in April 2026 and may not exist in older workspace snapshots:
   yarn nx run react-<component>-stories:storybook &
  • Find the storybook port. Three quirks to know:
  • Storybook picks a random high port on first boot (e.g. 49360), not the Storybook default 6006. Don't assume.
  • The nx wrapper process often exits 0 after delegating to storybook, leaving the actual server running as a child. So the nx PID isn't the storybook PID.
  • The storybook child opens two listening sockets: one for HTTP content, one for the webpack HMR event-stream. They are not ordered — either one can be numerically lower. Picking by port number is unreliable; pick by Content-Type.

Reliable detection — target the storybook node child (not the yarn wrapper), then probe each listening socket until one returns text/html:

   # Wait up to 180s for the storybook child to bind an HTTP port.
   # Pattern matches the node child specifically, not `yarn storybook dev` (the wrapper has no sockets).
   for i in $(seq 1 180); do
     SB_CHILD=$(pgrep -f "node.*\.bin/storybook dev" | head -1)
     if [ -n "$SB_CHILD" ]; then
       for port in $(lsof -a -p "$SB_CHILD" -i -P -sTCP:LISTEN 2>/dev/null | awk 'NR>1 {print $9}' | sed 's/.*://'); do
         CT=$(curl -sI --max-time 2 "http://localhost:$port/" 2>/dev/null | grep -i '^content-type:' | grep -i 'text/html')
         if [ -n "$CT" ]; then SB_PORT=$port; break; fi
       done
       if [ -n "$SB_PORT" ]; then break; fi
     fi
     sleep 1
   done
   echo "Storybook child PID=$SB_CHILD on port $SB_PORT"

Then wait for Storybook to finish compiling stories — the HTTP port answers before index.json is populated:

   for i in $(seq 1 60); do
     N=$(curl -s --max-time 2 "http://localhost:$SB_PORT/index.json" 2>/dev/null \
       | python3 -c "import json,sys; print(len(json.load(sys.stdin).get('entries', {})))" 2>/dev/null || echo 0)
     if [ "$N" -gt 0 ]; then break; fi
     sleep 2
   done

If no port turns up, or index.json never populates — do not fall back to the workspace-wide Storybook; read the nx output log and debug the per-component boot. The most common real failure is missing build artifacts for unstable re-export deps (see troubleshooting below).

  • Open the page with playwright-cli:
   npx -y @playwright/[email protected] open "http://localhost:$SB_PORT"
  • Navigate to the specific story iframe and capture a screenshot.

Use the iframe URL for a clean render without Storybook chrome:

   npx -y @playwright/[email protected] goto "http://localhost:$SB_PORT/iframe.html?id=components-<component>--default&viewMode=story"
   npx -y @playwright/[email protected] screenshot --filename=/tmp/visual-test-$ARGUMENTS.png
  • View the screenshot using the Read tool to visually inspect the rendered component.
  • Use snapshot to get the accessibility tree and find interactive element refs:
   npx -y @playwright/[email protected] snapshot

Then interact with elements by ref (e.g., click, hover) before taking more screenshots.

  • If the component doesn't look right, go back to the code, fix the issue, and repeat from step 4 (Storybook hot-reloads changes).
  • Clean up when done:
   npx -y @playwright/[email protected] close
   # Kill storybook — the nx wrapper may already be gone, so target the child
   [ -n "$SB_CHILD" ] && kill "$SB_CHILD" 2>/dev/null
   lsof -i :$SB_PORT -t 2>/dev/null | xargs kill 2>/dev/null

Troubleshooting

yarn nx run react-<component>-stories:storybook says the target doesn't exist.

The workspace graph may be stale (recent reparent). Run yarn nx reset then retry. If stroybook aliases still don't exist, use the direct yarn invocation:

cd packages/react-components/react-<component>/stories && yarn storybook dev --port 0 &
# --port 0 asks Storybook to pick a free port; detect it via the pgrep/lsof pattern above

Story ID Pattern

Story IDs follow the pattern <category>-<component>--<story>:

# Default story for Button
components-button--default

# Appearance variant
components-button--appearance

# Default story for Menu
components-menu--default

To discover exact story IDs, open the Storybook sidebar and use snapshot to find navigation links,

or check the story file's export default { title: '...' } metadata.

Iframe URL Format

# Local storybook (replace $SB_PORT with the actual port)
http://localhost:$SB_PORT/iframe.html?id=components-button--default&viewMode=story

# Dark theme
http://localhost:$SB_PORT/iframe.html?id=components-button--default&viewMode=story&globals=theme:webDarkTheme

The /iframe.html URL gives a clean render without Storybook chrome — always prefer this for screenshots.

Tips

  • Use npx -y @playwright/[email protected] snapshot to get an accessibility tree — useful for verifying ARIA attributes and finding interactive elements.
  • Use npx -y @playwright/[email protected] click <ref> to interact with the component (test hover states, open menus, etc.) before taking a screenshot.
  • Use npx -y @playwright/[email protected] resize <width> <height> to test responsive behavior.
  • For multiple story variants, take a screenshot of each: Default, Appearance, Size, Disabled, etc.

Other skills for the same job

different authors, same section of the catalogue
Webapp Testing
by anthropics
vendor ×12

Toolkit for interacting with and testing local web applications using Playwright. Supports verifying frontend functionality, debugging UI behavior, capturing browser screenshots, and viewing browser logs.

6k tokens scripts
Notebooklm
by ZhanlinCui
×6

Use this skill to query your Google NotebookLM notebooks directly from Claude Code for source-grounded, citation-backed answers from Gemini. Browser automation, library management, persistent auth. Drastically reduced hallucinations through document-only responses.

26k tokens scripts
Playwright Skill
by lackeyjb
×4

Complete browser automation with Playwright. Auto-detects dev servers, writes clean test scripts to /tmp. Test pages, fill forms, take screenshots, check responsive design, validate UX, test login flows, check links, automate any browser task. Use when user wants to test websites, automate browser interactions, validate web functionality, or perform any browser-based testing.

12k tokens scripts
Electron
by vercel-labs
vendor ×2

Automate Electron desktop apps (VS Code, Slack, Discord, Figma, Notion, Spotify, etc.) using agent-browser via Chrome DevTools Protocol. Use when the user needs to interact with an Electron app, automate a desktop app, connect to a running app, control a native app, or test an Electron application. Triggers include "automate Slack app", "control VS Code", "interact with Discord app", "test this Electron app", "connect to desktop app", or any task requiring automation of a native Electron application.

2k tokens
Anchor Browser Automation
by christophacham
×2

Automate Anchor Browser tasks via Rube MCP (Composio). Always search tools first for current schemas.

756 tokens needs MCP
Browser Tool Automation
by christophacham
×2

Automate Browser Tool tasks via Rube MCP (Composio). Always search tools first for current schemas.

749 tokens needs MCP
Giil
by Dicklesworthstone
×2

Get Image [from] Internet Link - Zero-setup CLI for downloading full-resolution images from iCloud, Dropbox, Google Photos, and Google Drive share links. Four-tier capture strategy, browser automation, HEIC conversion, album support. Node.js/Playwright.

3k tokens
Browser Extension Builder
by ComeOnOliver
×2

Expert in building browser extensions that solve real problems - Chrome, Firefox, and cross-browser extensions. Covers extension architecture, manifest v3, content scripts, popup UIs, monetization strategies, and Chrome Web Store publishing. Use when: browser extension, chrome extension, firefox addon, extension, manifest v3.

4k tokens

How to use it

Copy the folder

Take microsoft/visual-test from the repository into ~/.claude/skills for personal use, or into .claude/skills inside a project.

Check the name does not clash

The agent identifies a skill by the name field in its header. Two skills with the same name cannot sit side by side — one of them will be ignored.

Install what it needs

The instructions reference npx. Without those the skill loads but fails at the first command.