pst-explore
PST Explore
Manually execute a test case step-by-step in the live browser, capture every selector and observed value, and write an exhaustive insights.md to .pst/sessions/[name]/.
When to use
Invoke this skill when you have test case documentation (steps + expected results) and need to walk through it in the real app to capture the actual selectors, URLs, and DOM state at each step.
Inputs
The user pastes test case documentation inline in the chat. The skill asks for a session name to use as the folder slug.
Steps
1. Setup
Ask the user for a session name (short slug, e.g. sign-in). Then:
mkdir -p .pst/sessions/[name]/snapshots
Save the user's pasted test case content to .pst/sessions/[name]/input.md.
2. Open the browser
playwright-cli open
3. Execute each step
For every step in input.md:
- Perform the action (navigate / click / fill / etc.)
- Immediately after the action:
- Run
playwright-cli snapshot --filename=step-NN-[description].ymlto capture DOM state - Run
playwright-cli screenshot --filename=step-NN-[description].pngto capture a screenshot - Use
playwright-cli evalto extract exact selector values for every element involved in the step and every element referenced in the expectations
- Run
- Record: action type, selector used, URL after action, all observed element selectors and values, whether each expectation passed or failed
Selector priority (use the most stable first):
- ARIA role + name:
getByRole('button', { name: 'Sign in' }) - Text content:
a:has-text("Already a member? Sign In") - Test ID:
getByTestId('...') - CSS selector:
#email,.submit-btn - XPath (last resort)
For each element observed, capture:
- The selector
- Its visible text / value / href / placeholder (whichever applies)
- Its role and accessible name if relevant
# Example: extract href from a link
playwright-cli eval "el => el.getAttribute('href')" e5
# Example: extract all visible button texts on the page
playwright-cli eval "() => [...document.querySelectorAll('button')].map(b => b.textContent.trim())"
# Example: check if element is focused
playwright-cli eval "el => document.activeElement === el" e3
# Example: get input type
playwright-cli eval "el => el.type" e8
4. Close the browser
playwright-cli close
5. Move playwright-cli artifacts
mv .playwright-cli/* .pst/sessions/[name]/snapshots/ 2>/dev/null || true
6. Write insights.md
Write .pst/sessions/[name]/insights.md using the exhaustive format below. Do not summarize — include every selector, every observed value, every expectation result.
insights.md Format
# [Test Case Title] — Explore Insights
## Application Overview
[Narrative description of the flow observed during exploration — what the app does, how it behaves, any notable redirects or third-party pages encountered]
## Environment
- **Base URL:** [base URL]
- **Explored at:** [YYYY-MM-DD]
- **Snapshots:** `.pst/sessions/[name]/snapshots/`
## Test Scenarios
### [N]. [Scenario Group Title]
#### [N.N]. [Scenario Title]
**Step 1 — [Action description]**
- **Action:** navigate
- **URL:** [full URL navigated to]
- **URL after:** [full URL after navigation settled]
- **Selectors observed:**
- Page title: `document.title` → `"[actual title]"`
- [Element description]: `[selector]` → [observed value, href, text, placeholder]
- [Element description]: `[selector]` → [observed value]
- Snapshot: `snapshots/step-01-[description].yml`
- Screenshot: `snapshots/step-01-[description].png`
- **Expectations:**
- ✓ URL is `[expected URL]`
- ✓ [assertion description with actual observed value]
- ✗ [failed assertion — actual vs expected]
**Step 2 — [Action description]**
- **Action:** click
- **Selector used:** `[exact selector clicked]`
- **URL before:** [URL]
- **URL after:** [URL]
- **Selectors observed:**
- [Element description]: `[selector]` → [observed value]
- [All elements relevant to expectations for this step]
- Snapshot: `snapshots/step-02-[description].yml`
- Screenshot: `snapshots/step-02-[description].png`
- **Expectations:**
- ✓ [assertion]
- ✓ [assertion]
**Step 3 — [Action description]**
- **Action:** fill
- **Selector used:** `[selector]`
- **Value entered:** `[value]`
- **URL:** [URL]
- **Selectors observed:**
- [Input element]: `[selector]` → type=`[type]`, placeholder=`"[placeholder]"`, value after fill=`"[value]"`
- [Any validation elements that appeared or disappeared]
- Snapshot: `snapshots/step-03-[description].yml`
- Screenshot: `snapshots/step-03-[description].png`
- **Expectations:**
- ✓ [assertion]
[Continue for every step]
## Selector Quick Reference
| Element | Selector | Notes |
|---------|----------|-------|
| [Element description] | `[selector]` | [any notes] |
| [Element description] | `[selector]` | [any notes] |
Rules
- Never skip a step — every step in
input.mdmust appear ininsights.md - Never omit a selector — if an expectation references an element, its selector must be captured
- Mark failed expectations with ✗ and document the actual vs expected value
- If the page redirects unexpectedly or behaves differently from the test case, document it under the affected step
- Screenshots and snapshots must use the naming pattern
step-NN-[description] - The Selector Quick Reference table at the end must include every unique element interacted with or asserted against
Example: capturing a sign-in flow step
# Navigate
playwright-cli open https://www.goodreads.com
playwright-cli snapshot --filename=step-01-homepage.yml
playwright-cli screenshot --filename=step-01-homepage.png
# Capture title
playwright-cli eval "document.title"
# Find the sign-in link
playwright-cli eval "() => [...document.querySelectorAll('a')].filter(a => a.textContent.includes('Sign In')).map(a => ({ text: a.textContent.trim(), href: a.getAttribute('href') }))"
# Click the link
playwright-cli click "a:has-text('Already a member? Sign In')"
playwright-cli snapshot --filename=step-02-sign-in-page.yml
playwright-cli screenshot --filename=step-02-sign-in-page.png
# Capture heading and all visible auth options
playwright-cli eval "document.querySelector('h1')?.textContent"
playwright-cli eval "() => [...document.querySelectorAll('button')].map(b => b.textContent.trim())"
More from lautaroleonhardt/pst
analyze-codebase
Use when starting a Playwright testing session or when project structure is unknown. Scans the project for Playwright config, test conventions, routing, and tech stack. Writes output to docs/playwright-spec-testing/project-context.md.
9plan-tests
Use after explore-app to synthesize an exhaustive, human-reviewable test plan from exploration reports and project context. Reads all exploration/<slug>.md files, parsed-spec.md, and project-context.md. Outputs test-plan.md with full steps, assertions, and assigned test file paths.
9ingest-spec
Use when you have a Gherkin .feature file or plain-English test cases to parse into structured scenarios. Writes output to docs/playwright-spec-testing/parsed-spec.md.
9generate-tests
Use after plan-tests to write a Playwright test for one scenario by mechanically translating test-plan.md into Playwright API calls. Requires docs/playwright-spec-testing/test-plan.md. Writes the test file at the path assigned in the plan.
9debug-test
Use when a Playwright test is failing. Diagnoses the root cause and applies a minimal fix. Requires the failing test file path and the full error output.
9explore-app
Use after ingest-spec to walk through one scenario in the live app and capture real selectors and URLs. Requires a running app and a scenario from docs/playwright-spec-testing/parsed-spec.md. Writes output to docs/playwright-spec-testing/exploration/<scenario-slug>.md.
9