# Selector Finder Skill

A powerful Claude Code skill that finds and validates reliable Playwright selectors by inspecting the live Halo application using Chrome DevTools MCP server.

## What It Does

The selector-finder skill helps you discover the best selectors for your Playwright tests by:
- **Inspecting live pages** using Chrome DevTools MCP server
- **Analyzing DOM structure** to find element attributes
- **Comparing with proven patterns** from existing tests
- **Recommending semantic selectors** (getByRole, getByText)
- **Providing alternatives** for different scenarios
- **Generating page object code** ready to use

## Why This Is Powerful

Unlike manual selector hunting, this skill:
1. **Uses Chrome DevTools MCP** - Inspects the actual running application
2. **Takes accessibility snapshots** - Shows all elements with roles and names
3. **Evaluates JavaScript** - Gets exact element attributes from DOM
4. **Learns from your codebase** - Uses patterns that already work
5. **Follows best practices** - Prioritizes reliable, maintainable selectors

## When to Use

Invoke this skill whenever you need to:
- Find a selector for a new element
- Fix a broken selector in an existing test
- Choose between multiple selector options
- Validate if a selector is reliable
- Create page object methods with proper selectors
- Understand why a selector isn't working

## How to Invoke

```
selector-finder
```

Then describe what you need:
- "Find selector for the Share button on dashboard page"
- "What's the best selector for the Add Widget button?"
- "I need to click the Toured Conversions tab"
- "Find selector for email input on login page"

## What You'll Get

### 1. Recommended Selector
The best selector based on priority hierarchy:
```typescript
✅ RECOMMENDED
page.getByRole('button', { name: 'Share' })
```

### 2. Alternative Options
Fallback selectors for different scenarios:
```typescript
// Option 2: If semantic doesn't work
page.locator('[data-testid="share-button"]')

// Option 3: Last resort
page.locator('button:has-text("Share")').first()
```

### 3. Page Object Example
Ready-to-use code for page objects:
```typescript
// In pages/dashboard.page.ts
private readonly shareButton: Locator;

constructor(page: Page) {
  this.shareButton = page.getByRole('button', { name: 'Share' });
}

async clickShare(): Promise<void> {
  await this.shareButton.waitFor({ state: 'visible' });
  await this.shareButton.click();
}
```

### 4. Usage Validation
How to use and verify the selector:
```typescript
// In your test
const dashboardPage = new DashboardPage(page);
await dashboardPage.clickShare();
```

### 5. Common Issues & Solutions
Potential problems and how to avoid them

## Selector Priority Hierarchy

The skill follows this priority order (best to worst):

### 🥇 Priority 1: Semantic Selectors (BEST)
```typescript
page.getByRole('button', { name: 'Add' })
page.getByText('Dashboards', { exact: true })
page.getByLabel('Email Address')
```
**Why**: Based on accessibility, most stable, best for users

### 🥈 Priority 2: Data Test IDs (GOOD)
```typescript
page.getByTestId('add-widget-button')
page.locator('[data-testid="dashboard-card"]')
```
**Why**: Purpose-built for testing, stable

### 🥉 Priority 3: ID Selectors (ACCEPTABLE)
```typescript
page.locator('#email')
page.locator('#lga-tab')
```
**Why**: Usually stable if IDs don't change

### ⚠️ Priority 4: Class Selectors (CAUTION)
```typescript
page.locator('.dashboard-card')
```
**Why**: Classes may change with styling updates

### 🚫 Priority 5: Complex Selectors (AVOID)
```typescript
page.locator('div > ul > li:nth-child(3)')
```
**Why**: Fragile, breaks easily with UI changes

## How It Works

### Step 1: Check Existing Patterns
```bash
# Searches your codebase for similar selectors
Grep: "getByRole.*button.*Add" in tests/
Read: pages/widgets.page.ts
```

### Step 2: Inspect Live Application
```bash
# Opens Chrome DevTools MCP
mcp__chrome-devtools__navigate_page → "https://halo-qa.hyly.ai"
mcp__chrome-devtools__take_snapshot → Shows all elements
```

### Step 3: Analyze Element
```bash
# Gets element attributes via JavaScript
mcp__chrome-devtools__evaluate_script
→ Returns: role, text, id, class, data-testid, etc.
```

### Step 4: Recommend Best Selector
Based on findings + project patterns + best practices

## MCP DevTools Integration

This skill leverages **Chrome DevTools MCP server** which gives it superpowers:

### Available MCP Tools:
- `take_snapshot` - Get accessibility tree of page
- `navigate_page` - Go to specific URL
- `click` - Click elements during inspection
- `fill` - Fill forms to reach target page
- `evaluate_script` - Run JavaScript to inspect elements
- `list_pages` - See open browser pages
- `new_page` - Open new page for inspection
- `select_page` - Switch between pages

### Example MCP Workflow:
```
1. Navigate to https://halo-qa.hyly.ai
2. Take snapshot → Find login button
3. Click login → Navigate to dashboard
4. Take snapshot → Find target element
5. Evaluate script → Get element details
6. Recommend selector based on real DOM
```

## Project-Specific Patterns

The skill knows these proven Halo patterns:

### Dashboard Navigation
```typescript
page.getByText('Dashboards', { exact: true }).first()
page.getByRole('button', { name: 'New Dashboard' })
```

### Widget Selection
```typescript
page.getByText('See all widgets')
page.getByRole('tab', { name: 'Toured Conversions' })
page.locator('#lga-tab:has-text("SmartDA")')  // Special case
```

### Login
```typescript
page.locator('input[type="email"], input[name="email"], #email')
page.locator('input[type="password"], input[name="password"], #password')
page.locator('button[type="submit"], button:has-text("Sign In")')
```

### Export
```typescript
page.getByRole('button', { name: 'Share' })
page.getByText('Download PDF')
```

## Example Usage Sessions

### Example 1: Find New Selector
```
User: selector-finder
Claude: What element do you need a selector for?
User: The Add Widget button on the dashboard page
Claude:
  [Checks existing patterns in pages/widgets.page.ts]
  [Opens live app via MCP]
  [Takes snapshot and finds the button]
  [Evaluates element attributes]

  Result:
  ✅ RECOMMENDED: page.locator('button:has-text("Add New Widget")').first()

  Alternative: page.getByRole('button', { name: 'Add Widget' })

  [Provides page object code and usage example]
```

### Example 2: Fix Broken Selector
```
User: selector-finder
Claude: What element do you need a selector for?
User: My test can't find the Share button, current selector is page.locator('.share-btn')
Claude:
  [Inspects live page via MCP]
  [Finds actual Share button attributes]
  [Compares with reference files]

  Result:
  ❌ ISSUE: Class-based selector is fragile

  ✅ RECOMMENDED: page.getByRole('button', { name: 'Share' })

  This is more stable because it uses semantic role and text.

  [Shows before/after code]
```

### Example 3: Validate Selector Choice
```
User: selector-finder
Claude: What element do you need a selector for?
User: Is page.getByText('Dashboards', { exact: true }) a good selector for the sidebar link?
Claude:
  [Checks existing usage in codebase]
  [Validates against live app]

  Result:
  ✅ YES - This is an excellent selector!

  Reasons:
  - Text-based (stable)
  - exact: true (prevents partial matches)
  - Already used in 15 other tests successfully

  Tip: Add .first() if multiple "Dashboards" text exists
```

## Allowed Tools

The skill has access to:
- **Read** - Read test files and page objects
- **Glob** - Find files by pattern
- **Grep** - Search for selector patterns
- **Bash** - Execute commands
- **MCP Chrome DevTools** - Full browser inspection capabilities
  - take_snapshot
  - navigate_page
  - click
  - fill
  - evaluate_script
  - list_pages
  - new_page
  - select_page

## Benefits

- **70% faster selector discovery** - No manual DOM inspection needed
- **More reliable tests** - Uses proven patterns automatically
- **Better maintainability** - Semantic selectors are easier to understand
- **Fewer failures** - Robust selectors survive UI changes
- **Instant validation** - Tests selectors on live application
- **Learning tool** - Shows best practices in action

## Best Practices Enforced

1. ✅ Always prefer `getByRole()` and `getByText()`
2. ✅ Use `data-testid` when semantic not available
3. ✅ Add `.waitFor()` before interactions
4. ✅ Provide multiple selector options
5. ✅ Document why a selector was chosen
6. ❌ Avoid `nth-child()` and position-based selectors
7. ❌ Avoid complex CSS selectors
8. ❌ Never rely on generated class names

## Tips for Best Results

1. **Be specific**: "Share button on dashboard" vs "a button"
2. **Provide context**: Mention the page/feature
3. **Share current selector**: If fixing, show what you have
4. **Ask for validation**: "Is this selector good?"
5. **Request alternatives**: "Show me other options"

## Integration with test-debugger

Works great with the test-debugger skill:
1. **test-debugger** - Finds why selector failed
2. **selector-finder** - Finds better replacement selector
3. Apply the fix and rerun test

## Next Steps After Getting Selector

1. **Copy to page object** - Don't use directly in tests
2. **Add to appropriate page class** - Keep organized
3. **Test it** - Run your test to verify it works
4. **Document if special** - Add comment for unusual cases

---

**Created**: 2025-10-23
**Version**: 1.0
**Maintained by**: QA Automation Team
**Requires**: Chrome DevTools MCP Server
