# Chrome DevTools MCP Reference — Fluent Commerce UX Testing

> [!CAUTION]
> **🧪 EXPERIMENTAL — LABS PROJECT**
> This package is not production-ready. No stability guarantees, no support, no warranty. See [README](../README.md) for full disclaimer.

> **Version:** chrome-devtools-mcp@latest (v0.18.1+) | Last updated: 2026-03-04
>
> **Purpose:** Browser automation for Fluent Commerce UX app testing (Material UI React SPA with hash routing).

---

## Why Chrome DevTools MCP

Chrome DevTools MCP is the recommended browser automation for Fluent Commerce because:
- **DOM snapshots + screenshots** — deterministic element selection, no vision model needed, ~10x faster than pixel-based approaches
- **Token-optimized** — The `__fcTest` helper library (`content/dev/skills/fluent-ui-test/BROWSER_OPTIMIZATIONS.md`) replaces most `take_snapshot` calls (~30K tokens each) with `pageState()` (~150 tokens), `pageSummary()` (~500 tokens), MUI-aware finders (~50 tokens each), `diffState()` (~200 tokens for before/after), and programmatic login via `isLoggedIn()`/`loginForm()` — reducing browser interaction costs by ~90%. Login persistence via `--storage-state` eliminates re-login overhead entirely.
- **Material UI compatibility** — excellent accessibility markup means `take_snapshot` reliably finds elements
- **Hash routing support** — handles SPA routing correctly (no reload on hash change)
- **Headless mode** — CI/CD ready with `--headless`
- **Auto-configured** — installed by `npx @fluentcommerce/ai-skills install`

### Alternatives (Not Recommended)

| Feature | Chrome DevTools MCP | Puppeteer MCP | Chrome MCP Extension |
|---------|:---:|:---:|:---:|
| Tool Count | 22+ | 8 | 20+ |
| Headless Mode | Yes | Yes | No |
| Stability | High | Low (critical bugs) | Medium |
| CI/CD Ready | Yes | Yes | No |
| DOM Snapshots | Yes | No | No |
| Best For | Automated testing | (Not recommended) | Manual debugging |

**Puppeteer MCP** has critical communication bugs (#5 — server doesn't return data to client). Avoid.

**Chrome MCP Extension** (`mcp-chrome-bridge`) attaches to your existing Chrome with cookies/auth. Useful for manual debugging only. Add with `--with-chrome` flag.

---

## Setup

Your `.mcp.json` is auto-configured by the installer:

```json
{
  "chrome-devtools": {
    "command": "npx",
    "args": ["-y", "chrome-devtools-mcp@latest"],
    "env": {
      "FLUENT_UI_BASE_URL": "https://<account>.<env>.apps.engineering.fluentcommerce.com"
    }
  }
}
```

**First run:** Browser binaries auto-install (Chromium ~130MB).

### Installer flags

| Flag | Purpose |
|------|---------|
| `--browser-url <url>` | Set `FLUENT_UI_BASE_URL` for a specific environment |
| `--no-browser` | Skip Chrome DevTools MCP setup (backend-only workflows) |
| `--save-video [resolution]` | Enable continuous video recording (default: 1920x1080) |
| `--with-chrome` | Add Chrome MCP Extension alongside (manual debugging) |

### Hybrid setup (optional)

```bash
npx @fluentcommerce/ai-skills mcp-setup --profile YOUR_PROFILE --with-chrome
```

Adds `chrome-manual` server. Requires Chrome extension from https://github.com/hangwin/mcp-chrome.
- `mcp__chrome-devtools__*` tools for automated tests
- `mcp__chrome-manual__*` tools for exploratory testing with existing sessions

---

## Common Testing Workflows

### 1. Login to Fluent OMS

```typescript
navigate_page({ url: "https://<account>.test.apps.engineering.fluentcommerce.com/oms" })
take_snapshot()  // Find login form refs

fill_form({
  fields: [
    { ref: "username-input-ref", value: process.env.FLUENT_USERNAME },
    { ref: "password-input-ref", value: process.env.FLUENT_PASSWORD }
  ]
})
click({ ref: "login-button-ref" })
wait_for({ condition: "navigation complete" })
take_snapshot()  // Verify dashboard loaded
```

### 2. Navigate with Hash Routing

```typescript
// Direct URL navigation
navigate_page({ url: "https://<account>.test.apps.engineering.fluentcommerce.com/oms#/orders" })

// OR click navigation menu
click({ ref: "orders-menu-item-ref" })
take_snapshot()  // Verify orders list
```

### 3. Search and Verify

```typescript
take_snapshot()
type_text({ ref: "search-input-ref", text: "TEST-ORDER-001" })
press_key({ ref: "search-input-ref", key: "Enter" })
wait_for({ timeout: 5000 })
list_network_requests()  // Verify GraphQL query fired
```

### 4. Fill Complex Forms (Material UI)

```typescript
fill_form({
  fields: [
    { ref: "customer-autocomplete-ref", value: "John Doe" },
    { ref: "order-type-select-ref", value: "HD" },
    { ref: "order-ref-input-ref", value: "TEST-ORDER-123" }
  ]
})
select_option({ ref: "retailer-select-ref", value: "YOUR_RETAILER" })
click({ ref: "submit-button-ref" })
```

### 5. Verify GraphQL API Calls

```typescript
click({ ref: "refresh-button-ref" })
list_network_requests()
// Look for: url containing "graphql", method "POST", status 200
```

**POST payload capture workaround** (payloads may not appear in network log):

```typescript
evaluate_script({
  code: `
    window.__capturedRequests = [];
    const originalFetch = window.fetch;
    window.fetch = function(...args) {
      const [url, options] = args;
      if (options?.method === 'POST' && url.includes('graphql')) {
        window.__capturedRequests.push({ url, body: options.body });
      }
      return originalFetch.apply(this, args);
    };
  `
})
// Later: evaluate_script({ code: `JSON.stringify(window.__capturedRequests)` })
```

### 6. Check Console for React Errors

```typescript
list_console_messages()
click({ ref: "problematic-button-ref" })
list_console_messages()  // Returns array of { level: "error", text: "..." }
```

### 7. Screenshots for Visual Regression

```typescript
take_screenshot({ fullPage: true })          // Full page
take_screenshot({ ref: "order-card-ref" })   // Element-specific
```

### 8. Mobile Responsive Testing

```typescript
browser_resize({ width: 390, height: 844 })
take_snapshot()  // Verify mobile layout
```

Or configure in `.mcp.json`: `"args": ["-y", "chrome-devtools-mcp@latest", "--device=iPhone 15"]`

### 9. Persist Login Across Runs

Add `--storage-state` to `.mcp.json` args:
```
"--storage-state=./chrome-session.json"
```
First run: login saved to file. Subsequent runs: auto-logged in.

---

## Material UI Component Selectors

Chrome DevTools MCP uses **DOM snapshots**, not CSS selectors:

| Component | How to Select |
|-----------|---------------|
| TextField | Find by label: `"Order Reference"` |
| Button | Find by text: `"Submit"` |
| Select/Dropdown | Find by label: `"Order Type"` |
| Autocomplete | Find by input label: `"Customer"` |
| DataGrid | Find by role: `"grid"` |
| Dialog | Find by role: `"dialog"` |
| Menu | Find by role: `"menu"` |
| Tabs | Find by role: `"tab"` |

**Key insight:** Material UI has excellent accessibility markup, making `take_snapshot` highly reliable.

---

## Click Telemetry (Visual Click Highlights)

Chrome DevTools MCP clicks are programmatic — no visible cursor appears. Click Telemetry injects visual highlights around elements before interactions, making screenshots and screencasts self-documenting.

### Quick Setup

Inject once at session start via `evaluate_script`:

```javascript
(function() {
  if (!document.getElementById('__fc-click-keyframes')) {
    var s = document.createElement('style');
    s.id = '__fc-click-keyframes';
    s.textContent =
      '@keyframes fcClickPulse{0%{box-shadow:0 0 0 0 rgba(233,69,96,0.6)}' +
      '50%{box-shadow:0 0 0 8px rgba(233,69,96,0.2)}' +
      '100%{box-shadow:0 0 0 0 rgba(233,69,96,0)}}';
    document.head.appendChild(s);
  }
})();
```

### Highlight Before Click

```javascript
(function() {
  var prev = document.getElementById('__fc-click-highlight');
  if (prev) prev.remove();
  var elem = document.querySelector('SELECTOR');
  if (!elem) return 'not_found';
  var rect = elem.getBoundingClientRect();
  var h = document.createElement('div');
  h.id = '__fc-click-highlight';
  h.style.cssText = 'position:fixed;left:' + (rect.left-4) + 'px;top:' + (rect.top-4) +
    'px;width:' + (rect.width+8) + 'px;height:' + (rect.height+8) +
    'px;border:3px solid #e94560;border-radius:6px;z-index:2147483646;' +
    'pointer-events:none;animation:fcClickPulse 0.8s ease-in-out infinite';
  var b = document.createElement('span');
  b.style.cssText = 'position:absolute;top:-26px;left:0;background:#e94560;color:#fff;' +
    'padding:2px 10px;border-radius:4px;font:700 11px system-ui;text-transform:uppercase';
  b.textContent = 'LABEL';
  h.appendChild(b);
  document.body.appendChild(h);
})();
```

### Full Click Sequence

1. `evaluate_script` — inject highlight
2. `wait_for` 300ms — let animation render
3. `take_screenshot` — capture highlighted state
4. `click` the element
5. `wait_for` 500ms — let page settle
6. `evaluate_script` — remove highlight: `var el = document.getElementById('__fc-click-highlight'); if (el) el.remove();`
7. `take_screenshot` — capture post-click state

### Action Timeline Tracker

```javascript
window.__fcTimeline = {
  actions: [], startTime: Date.now(),
  log: function(action, target, label) {
    this.actions.push({ seq: this.actions.length + 1,
      elapsed: Date.now() - this.startTime,
      action: action, target: target, label: label });
  },
  getReport: function() {
    return JSON.stringify({ total: this.actions.length,
      durationMs: Date.now() - this.startTime, timeline: this.actions });
  }
};
```

| Skill | Usage |
|-------|-------|
| `/fluent-ui-test` | Highlights each user action button during Phase 4 verification |
| `/fluent-ui-record` | Full highlight sequence for every interaction during recording |

---

## Troubleshooting

### Common Issues

| Symptom | Cause | Fix |
|---------|-------|-----|
| "Element not found" | Element not in DOM yet (still loading) | `wait_for({ timeout: 5000 })` then `take_snapshot()` |
| Hash routing not working | Browser treated `#` as fragment | Use full URL: `https://...com/oms#/orders` (not just `#/orders`) |
| GraphQL mutation payload missing | POST bodies not always captured | Use `evaluate_script` with fetch interceptor (see above) |
| Flaky tests after navigation | No auto-wait after navigation | Always add `wait_for` after `navigate_page` |
| Bearer token truncated | Header parser limitation | Use `evaluate_script({ code: 'localStorage.getItem("authToken")' })` |
| Chrome DevTools MCP not starting | Stale browser lock file | `rm -rf ~/.cache/chrome-devtools-mcp/chrome-profile/SingletonLock` |
| Chrome DevTools MCP port conflict | Another Chrome instance using same profile | Use `--headless` or remove the full profile dir |

**NEVER use `taskkill //F //IM chrome.exe`** — this kills the user's personal browser tabs. Chrome DevTools MCP uses its own profile at `~/.cache/chrome-devtools-mcp/chrome-profile`. When the lock is stale, remove the `SingletonLock` file (not taskkill).

### Performance Tips

1. **Use `take_snapshot` not screenshots** — DOM snapshot (0.5s) is ~10x faster than screenshot + vision model (5-10s)
2. **Batch fill operations** — one `fill_form` call instead of multiple `type_text` calls
3. **Reuse storage state** — login once, save session (1s) vs login every run (10-15s)

---

## Advanced Configuration

### Headless for CI/CD

```json
{ "args": ["-y", "chrome-devtools-mcp@latest", "--headless"] }
```

### Restrict Allowed Hosts

```json
{ "args": ["-y", "chrome-devtools-mcp@latest", "--allowed-hosts=<account>.test.apps.engineering.fluentcommerce.com"] }
```

### Enable Screencast Recording

```json
{ "args": ["-y", "chrome-devtools-mcp@latest", "--experimentalScreencast"] }
```

FFmpeg optional — enables trim/convert `.webm` to `.mp4`, GIF previews.

### Use Proxy

```json
{ "args": ["-y", "chrome-devtools-mcp@latest", "--proxy-server=http://proxy.example.com:8080"] }
```

### CI/CD Example (GitHub Actions)

```yaml
name: Fluent UX E2E Tests
on: [push, pull_request]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: '20' }
      - name: Install browser binaries
        run: npx chrome-devtools-mcp@latest --headless --help
      - name: Run tests
        run: |
          echo '{ "chrome-devtools": { "command": "npx", "args": ["-y", "chrome-devtools-mcp@latest", "--headless"], "env": { "FLUENT_UI_BASE_URL": "${{ secrets.FLUENT_UI_BASE_URL }}" } } }' > .mcp.json
          claude-code run test-fluent-ux.ts
      - name: Upload screenshots
        if: failure()
        uses: actions/upload-artifact@v4
        with: { name: test-screenshots, path: ./screenshots/ }
```

---

## Tool Reference

| Tool | Purpose | Key Parameters |
|------|---------|----------------|
| `navigate_page` | Go to URL | `url` |
| `click` | Click element | `ref`, `button`, `modifiers` |
| `type_text` | Type text | `ref`, `text` |
| `press_key` | Press keyboard key | `ref`, `key` |
| `fill_form` | Fill multiple fields | `fields: [{ref, value}]` |
| `drag` | Drag and drop | `ref`, `targetRef` |
| `hover` | Hover over element | `ref` |
| `select_option` | Select dropdown value | `ref`, `value` |
| `file_upload` | Upload file | `ref`, `filePath` |
| `take_snapshot` | Get DOM snapshot | (returns structured JSON) |
| `take_screenshot` | Capture screenshot | `fullPage`, `ref` |
| `list_console_messages` | Get console logs | (returns array) |
| `list_network_requests` | Get network activity | (returns array) |
| `evaluate_script` | Run JavaScript | `code` |
| `handle_dialog` | Handle alert/confirm | `action`, `text` |
| `close_page` | Close browser tab | |
| `resize_page` | Change viewport | `width`, `height` |
| `wait_for` | Wait for condition | `timeout`, `condition` |

---

## References

- [Chrome DevTools MCP (npm)](https://www.npmjs.com/package/chrome-devtools-mcp)
- [Chrome MCP Extension (GitHub)](https://github.com/hangwin/mcp-chrome)
- [Model Context Protocol Docs](https://modelcontextprotocol.io)
