Verifies a web UI in a running browser by measuring the live DOM with bundled scripts — visibility, clickability, alignment, overflow, and the state a click leaves behind — instead of reading screenshots. Use when a change to a web UI needs verifying in the running app, when a UI bug is reported (something on screen is missing, misplaced, clipped, or unclickable), or when acceptance criteria describe on-screen behaviour. Prefer this over writing custom Playwright page.evaluate code. Not for visual appearance (colors, fonts, spacing), cross-browser behaviour, or accessibility checks.
94%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
Passed
No findings from the security scan
Verify: $ARGUMENTS
This skill runs in its own context and never sees the conversation that launched it, so the line above is the whole brief. If it is empty, or names no feature, route, or URL, say what is missing and stop — there is no page to open and guessing at one wastes a browser session.
Every browser action goes through playwright:browser_run_code_unsafe. Its
code argument is an async (page) => ... function, and every page.* call in
this document belongs inside that function:
playwright:browser_run_code_unsafe({
code: `async (page) => page.locator('.submit-button').click()`
})Stick to this one tool and this one vocabulary throughout. page.* calls do not
exist in the other Playwright MCP tools, so mixing them produces "not a
function" errors.
Follow this process for every verification. Use the bundled scripts — do not
write custom page.evaluate code unless the scripts cannot answer the question.
Read the minimum source code to identify:
Stop once you have those three. Exploring the full component tree costs a lot of context and rarely changes which selectors you measure.
Target elements by CSS selector, role, or text. A [ref=...] value belongs to
the snapshot that produced it and does not resolve anywhere else, so if you have
a ref, map it back to a class, role, or text selector before using it.
page.locator('selector').click() for all interactionsFor EVERY measurement, follow this exact sequence:
This is a 3-stage check: setup observer, perform click with Playwright, collect results.
Read ${CLAUDE_SKILL_DIR}/scripts/check-after-action.jspage.evaluate(scriptContent) — scriptContent is the file text
as a JSON string literal (see "How to inject scripts")page.evaluate((opts) => setupAfterAction(opts), { scope: '[role="dialog"]', expect: [{ selector: '.success-message', visible: true }, { selector: '.loading-spinner', visible: false }], timeout: 5000 })page.locator('.submit-button').click()page.evaluate(() => collectAfterAction())pass and each result's reasonUse this for: selection state changes, popup open/close, tab switching, form submission results — any click that should change the UI permanently. Use checkVisibilityTransition instead when tracking temporary elements (spinners, toasts, animations).
Read ${CLAUDE_SKILL_DIR}/scripts/check-alignment.jspage.evaluate(scriptContent) where scriptContent is the
full file you just read, as a JSON string literal (see "How to inject scripts")page.evaluate(() => checkAlignment({ containerSelector: '...', scopeSelector: '...' }))behavior, alignment, gaps.uniform, gaps.valueOptions:
containerSelector: the container whose children to compareselectors: compare these specific elements instead of a container's childrenscopeSelector: search within this element rather than the whole documenttolerance: how many pixels apart two edges can sit and still count as
aligned (default: 1). Browsers report fractional pixels, so exact equality
would flag an aligned row as behavior: "unknown". Raise it to 2-3 for
layouts inside a CSS transform; drop it to 0 to assert exact pixel equality.A behavior: "unknown" result reports the tolerance it used — before calling
the layout broken, re-run with a larger one to see whether the elements were
merely a fraction of a pixel apart. A tolerance that is not a non-negative
number returns { error } instead of a result.
Read ${CLAUDE_SKILL_DIR}/scripts/check-clickable.jspage.evaluate(() => checkClickable({ selectors: [...], scope: '...' }))clickable and reasonThis is a 3-stage check: setup observer, perform click with Playwright, collect results.
Read ${CLAUDE_SKILL_DIR}/scripts/check-visibility-transition.jspage.evaluate(scriptContent) — scriptContent is the file text
as a JSON string literal (see "How to inject scripts")page.evaluate((opts) => setupVisibilityTransition(opts), { target: '.spinner', scope: '[role="dialog"]', expected: [false, true, false], timeout: 5000 })page.locator('.submit-button').click()page.evaluate(() => collectVisibilityTransition())matches and reasonUse this after opening a popover, dialog, or dropdown to discover everything inside in one call instead of writing custom discovery code each time.
Read ${CLAUDE_SKILL_DIR}/scripts/check-inventory.jspage.evaluate(() => checkInventory({ scope: '[data-example]', // e.g.: [data-popover-content], [data-radix-popper-content-wrapper], [role="dialog"] include: ['button', '[role="option"]', '[role="radio"]', '[role="group"]'] }))summary for counts, sections for labeled groups, scrollState for scroll info,
and elements for the full list with text/role/ariaState/visible/inViewport per element.Options:
scope (required): CSS selector for the container to inventoryinclude: array of selectors to search for (defaults to all common interactive roles)exclude: array of selectors to skipmaxDepth: limit DOM traversal depthUse this to check whether a container or its children overflow the viewport, whether footer content is clipped, and whether interactive elements are still reachable.
Read ${CLAUDE_SKILL_DIR}/scripts/check-overflow.jspage.evaluate(() => checkOverflow({ scope: '[data-side]', checkFooter: true }))summary for the quick verdict (overflows, scrollable, footerClipped,
unreachableCount), overflow/overflowPx for directional detail, footer for
last-child clipping, and unreachable for any interactive elements that can't be clicked.Options:
scope (required): CSS selector for the container to checkcheckFooter: check if the last visible child is clipped (default: true)checkInteractive: hit-test all interactive elements for reachability (default: true)margin: pixel tolerance for overflow detection (default: 0)maxDepth: how many levels down to look for clipped descendants (default: 6).
Six levels reaches the panels, sections, and controls a user can see; raise
it only when the tree under test is genuinely deeper.Scripts live on disk, NOT accessible from the browser. To inject:
Read ${CLAUDE_SKILL_DIR}/scripts/check-alignment.jspage.evaluate(<fileContent as a JSON string literal>) — this defines
the function in browser scope. Build the literal with JSON.stringify of the
file text (every script contains backticks and ${…}, so pasting the text
into a template literal fails to parse before anything runs)page.evaluate(() => checkAlignment({...}))
Do not use fetch() or import() to load scripts — the browser cannot read local filesReport every check in a Markdown table with the columns "Elements", "Check", "Result", "Details", "Suggested fix" for instance:
| Elements | Check | Result | Details | Suggested fix |
|----------|-------|--------|---------|---------------|
| .search-input | visible | ✅ | Visible at the very top on the search form | N/A |
| .search-input | clickable | ✅ | elementFromPoint returns self | N/A |
| .dropdown | appears on focus | ❌ | MutationObserver: element never became visible within 3s | Add visibility state change on search input focus |Instead of providing numeric information, explain what is going on semantically. Imagine that user does not see the skill at all and you have to explain to him being in complete blindness
Write custom page.evaluate code only once the scripts above have been tried and still leave the question open.
playwright:browser_snapshot is the one exception to the single-tool
rule. Use it to discover structure, then translate what you find into CSS,
role, or text selectors and measure with those; the refs it returns are not
usable anywhere else.provectus/awos-recruitment
8d9332c
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.