| name | playwright-admin-panel |
| description | Run deep browser UI tests against the admin panels (global and project-level) using MCP Playwright. |
MCP Playwright Admin Panel Testing
You are executing the /playwright-admin-panel skill. Follow these steps exactly.
This skill runs a sequence of browser-based UI verification flows against the SlateFlow admin panels using MCP Playwright. It tests both the global admin surface (/admin) and project-level admin surface (/projects/:id/admin), covering user management, feature flag toggling, holidays, project members, project settings, and swim lane configuration.
Accepted Arguments
/playwright-admin-panel # run all 6 flows (default)
/playwright-admin-panel users # only global Users tab
/playwright-admin-panel flags # only Settings/feature-flags tab
/playwright-admin-panel holidays # only Holidays tab
/playwright-admin-panel project-members # only Project Admin Members tab
/playwright-admin-panel project-settings # only Project Admin Settings tab
/playwright-admin-panel project-lanes # only Project Admin Lanes tab
Valid flow tokens: users, flags, holidays, project-members, project-settings, project-lanes
If no flows are specified, all 6 run.
Step 1 — Parse and Validate Arguments
Determine which flows to run from the command arguments. Default: all (users, flags, holidays, project-members, project-settings, project-lanes).
Step 2 — Pre-flight Health Check
First, create a unique run folder for this invocation to isolate all artifacts:
RUN_ID=$(node -e "process.stdout.write(new Date().toISOString().replace(/[:.]/g,'-').slice(0,16))")
RUN_DIR=".playwright-mcp/run-$RUN_ID"
mkdir -p "$RUN_DIR"
echo "Run folder: $RUN_DIR"
Store $RUN_DIR as a variable for cleanup at the end.
Mandatory artifact rule — all files generated during this run must be created inside the run folder:
- Every screenshot call must pass an explicit
filename parameter prefixed with the run folder name: filename: "run-<RUN_ID>/<flow>-<NN>-<description>.png". The path is relative to .playwright-mcp/ (the MCP output dir) — do NOT prefix it with .playwright-mcp/.
- Naming convention:
<flow>-<NN>-<short-description>.png, e.g. login-01-form.png, users-07-created.png, flags-08-toggled.png.
- Never call the screenshot tool without
filename — auto-named files land in .playwright-mcp/ root, outside the run folder.
Now run the health check script to confirm both servers are up and detect the frontend port:
node .claude/skills/playwright-ui/check-servers.mjs
Parse the output to extract FRONTEND_PORT=<port> (either 5173 or 5174) and store it in a variable for use in all subsequent steps.
If the script exits non-zero, stop here and tell the user to run npm run dev first.
Step 3 — Login Flow (Always Runs First)
Purpose: Establish session (sf_token httpOnly cookie) in the browser context for all subsequent flows.
Use the MCP Playwright tools:
browser_navigate to http://localhost:$FRONTEND_PORT/login
browser_screenshot (filename: "run-<RUN_ID>/login-01-form.png") — confirm the login form is visible (email + password fields, sign-in button)
browser_type into the email field: admin@flow.local
browser_type into the password field: Admin1234!
browser_click on the "Sign in" / submit button
browser_wait_for_url to not contain /login (should redirect to /dashboard or similar)
browser_screenshot (filename: "run-<RUN_ID>/login-02-dashboard.png") — confirm the dashboard page rendered
If login fails, stop here and report the failure. Otherwise, continue to the requested flows below.
Step 4 — Run Requested Flows
Reminder: every screenshot in the flows below must use filename: "run-<RUN_ID>/<flow>-<NN>-<description>.png" so the file is created directly inside the run folder.
Users Flow (if requested)
Purpose: Test global admin user management — create, edit, deactivate, delete.
browser_navigate to http://localhost:$FRONTEND_PORT/admin
browser_screenshot — confirm admin panel loaded, Users tab is active
browser_screenshot — confirm user table has existing rows (e.g., admin@flow.local visible)
browser_click on "Create User", "+ New User", or similar button
- Fill the user creation form:
browser_type into email field: testuser_[timestamp]@example.com (use timestamp to ensure uniqueness)
browser_type into display name field: Test User [timestamp]
browser_type into password field: TestPass123!
browser_click on role dropdown and select global_reader
browser_click the "Create" / submit button
browser_screenshot — confirm the new user appears in the user table
- Locate the newly created user row and
browser_click "Edit Skills" link/button
browser_screenshot — confirm the skills modal opened
- Close the modal (Escape or X button) —
browser_screenshot
- Locate the newly created user row and
browser_click the role dropdown
- Select
super_admin from the dropdown
browser_screenshot — confirm role changed to super_admin in the table
- Locate the newly created user row and
browser_click "Deactivate" / toggle button
browser_screenshot — confirm the user status changed (e.g., badge now shows "Inactive")
- Locate the newly created user row and
browser_click "Delete" button
- If a confirmation dialog appears,
browser_click "Confirm" / "Yes"
browser_screenshot — confirm the user is removed from the table
Flags Flow (if requested)
Purpose: Test feature flag toggling and sidebar UI updates.
browser_navigate to http://localhost:$FRONTEND_PORT/admin
browser_screenshot — confirm admin panel loaded
browser_click on the "Settings" tab
browser_screenshot — confirm feature flag toggles are visible (showing rows like "Calendar", "Retrospective", etc.)
- Locate the
retrospective flag row (by label or key)
browser_screenshot — note its current toggle state (on/off)
browser_click the toggle button for the retrospective flag
browser_screenshot — confirm the toggle state flipped visually
browser_navigate to http://localhost:$FRONTEND_PORT/dashboard
browser_screenshot — check the sidebar navigation; if retrospective was toggled ON, the "Retrospective" link should appear (or disappear if toggled OFF)
browser_navigate back to http://localhost:$FRONTEND_PORT/admin
browser_click the "Settings" tab
browser_click the retrospective flag toggle again to revert it to its original state
browser_screenshot — confirm the toggle is back to original state
Holidays Flow (if requested)
Purpose: Test holiday management (calendar-gated feature).
Pre-condition check: This flow only runs if the calendar feature flag is enabled. If the flag is disabled, skip this flow with a note: SKIPPED — calendar feature flag is off.
browser_navigate to http://localhost:$FRONTEND_PORT/admin
- Check if the "Holidays" tab is visible. If not, return early with
SKIPPED — Holidays tab not visible (calendar flag disabled).
browser_click on the "Holidays" tab
browser_screenshot — confirm the holidays list is visible
browser_click on "Add Holiday" or "+ New Holiday" button
- Fill the holiday creation form:
browser_type into title field: Test Holiday [timestamp]
browser_click on the date picker and select a date (e.g., next week)
browser_click on country dropdown and select a country (e.g., "United States")
browser_click "Create" / "Save" button
browser_screenshot — confirm the new holiday appears in the list
- Locate the newly created holiday row and
browser_click "Edit" button
browser_type into the title field to modify it (append " (edited)") and confirm the field cleared before typing
browser_click "Save"
browser_screenshot — confirm the updated title is displayed in the list
- Locate the edited holiday row and
browser_click "Delete" button
- If a confirmation dialog appears,
browser_click "Confirm" / "Yes"
browser_screenshot — confirm the holiday is removed from the list
Project Members Flow (if requested)
Purpose: Test project-level admin member management.
browser_navigate to http://localhost:$FRONTEND_PORT/projects/1/admin
browser_screenshot — confirm Project Admin panel loaded with Members tab active
browser_screenshot — confirm the members table shows existing rows
browser_click on "Add Member" or "+ Add Member" button
- A search/select modal should appear.
browser_type into the search field to find a user (e.g., type "admin" to find admin@flow.local, or pick any available user)
browser_click on a user from the search results to select it
browser_click on the role dropdown and select contributor
browser_click "Add" / "Save" button
browser_screenshot — confirm the new member appears in the members table with role contributor
- Locate the newly added member row and
browser_click on the role dropdown
- Select
reader from the dropdown
browser_screenshot — confirm the role changed to reader in the table
- Locate the member row and
browser_click "Remove" button
- If a confirmation dialog appears,
browser_click "Confirm" / "Yes"
browser_screenshot — confirm the member is removed from the table
Project Settings Flow (if requested)
Purpose: Test project metadata editing.
browser_navigate to http://localhost:$FRONTEND_PORT/projects/1/admin
browser_click on the "Settings" tab
browser_screenshot — confirm the project name and description fields are visible
- Locate the project name input field and
browser_type to append " (edited)" to the existing name (use Ctrl+End or Cmd+End to move to end of field, then type)
browser_click "Save" button
browser_screenshot — confirm the project name in the page header or breadcrumb updated to show " (edited)"
- Locate the project description input field and
browser_type to modify it (e.g., append " — Updated")
browser_click "Save" button
browser_screenshot — confirm the description updated
- Edit the name again to remove " (edited)" and revert to the original
browser_click "Save"
browser_screenshot — confirm the name reverted
Project Lanes Flow (if requested)
Purpose: Test swim lane CRUD and done-column configuration.
browser_navigate to http://localhost:$FRONTEND_PORT/projects/1/admin
browser_click on the "Lanes" tab
browser_screenshot — confirm the lanes list is visible with existing lanes (e.g., "To Do", "In Progress", "Review", "Done")
- Scroll to the bottom to find the "Add Lane" input or button
browser_type into the lane name field: QA Review [timestamp]
browser_click the "Add" / "Create" button
browser_screenshot — confirm the new lane appears in the lanes list
- Locate the newly created lane row and
browser_click on the lane name (or an edit icon) to rename it
- Select all the text (Ctrl+A / Cmd+A) and
browser_type: QA Verification [timestamp]
- Press Enter or
browser_click outside the field to save the rename
browser_screenshot — confirm the lane name updated
- Locate the lane row and find the "Done" column toggle (e.g., a badge or toggle button)
browser_click to toggle the "Done" column status
browser_screenshot — confirm the badge changed (e.g., from "Normal" to "Done" or vice versa)
- Locate the lane row and
browser_click "Delete" button
- If a confirmation dialog appears,
browser_click "Confirm" / "Yes"
browser_screenshot — confirm the lane is removed from the list
Step 5 — Generate Report
Compile the results of each flow into a summary table and report:
## Admin Panel Verification Report
| Flow | Status | Notes |
|-------------------|-----------|----------------------------------------------|
| users | ✅ PASS | Created, role changed, deactivated, deleted |
| flags | ✅ PASS | Retrospective flag toggled; sidebar updated |
| holidays | ✅ PASS | Holiday created, edited, deleted |
| project-members | ✅ PASS | Member added, role changed, removed |
| project-settings | ✅ PASS | Name and description edited and reverted |
| project-lanes | ✅ PASS | Lane created, renamed, done-toggled, deleted |
For each flow, note:
- Status:
✅ PASS, ❌ FAIL, or ⏭ SKIPPED
- Notes: Brief description of what was verified or what went wrong (or why it was skipped)
Embed a representative screenshot from each flow for visual confirmation.
Step 6 — Artifact Cleanup
Screenshots are already inside $RUN_DIR (created there directly via the filename parameter). This step is a catch-all sweep for auto-generated artifacts the MCP server names itself — console logs (*.log), page snapshots (*.yml), and any stray screenshot from a missed filename:
mv .playwright-mcp/*.log "$RUN_DIR/" 2>/dev/null || true
mv .playwright-mcp/*.yml "$RUN_DIR/" 2>/dev/null || true
mv .playwright-mcp/*.png "$RUN_DIR/" 2>/dev/null || true
echo "All artifacts saved to $RUN_DIR"
Together with the per-screenshot filename rule, this keeps each run's screenshots, logs, and snapshots isolated in its own timestamped subfolder, preventing conflicts between concurrent or sequential runs.
Troubleshooting
| Issue | Cause | Fix |
|---|
| Health check fails | Dev server not running | Run npm run dev in another terminal |
| Login times out | Login form not found or incorrect selectors | Check that frontend is on $FRONTEND_PORT (5173 or 5174) and the login page loads |
| Admin panel doesn't load | User is not super_admin or feature flag is off | Verify using the admin@flow.local super_admin account |
| User creation fails | Form field selectors changed in code | Use browser_screenshot after each field to identify the correct selector |
| Member add dialog doesn't appear | Modal structure changed | Take screenshots after clicking "Add Member" to diagnose |
| Lanes tab not visible | Project structure changed | Verify that /projects/1/admin loads and "Lanes" tab is present |
| Feature flag toggle doesn't persist | DB not seeded or API error | Check server logs and re-seed database with /seed-db |
| Holidays tab missing | Calendar feature flag is disabled | This is expected; flow will be skipped with a note |
Session Notes:
- All flows share the same browser context (one login establishes the session for all subsequent flows)
- Mutations (users created, flags toggled, lanes added) persist in the dev database (
server/slateflow.db) — reset anytime with /seed-db
- Screenshots are embedded as base64; in the report, call out any visual anomalies (missing fields, broken buttons, layout breaks)
- If any flow fails, report the failure clearly and suggest next debugging steps
- Artifacts: Screenshots are written directly into
.playwright-mcp/run-<timestamp>/ during the run (via the filename parameter on every screenshot call); console logs (*.log) and page snapshots (*.yml) are swept into the same folder at the end — concurrent and sequential runs stay isolated