pst-explore

Installation
SKILL.md

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:

  1. Perform the action (navigate / click / fill / etc.)
  2. Immediately after the action:
    • Run playwright-cli snapshot --filename=step-NN-[description].yml to capture DOM state
    • Run playwright-cli screenshot --filename=step-NN-[description].png to capture a screenshot
    • Use playwright-cli eval to extract exact selector values for every element involved in the step and every element referenced in the expectations
  3. 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):

  1. ARIA role + name: getByRole('button', { name: 'Sign in' })
  2. Text content: a:has-text("Already a member? Sign In")
  3. Test ID: getByTestId('...')
  4. CSS selector: #email, .submit-btn
  5. 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.md must appear in insights.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())"
Related skills
Installs
4
First Seen
Apr 8, 2026