selfcure
selfcure × WebdriverIO

WebdriverIO + a messy frontend?
Check your selector health.

Half your spec is $('.btn-primary') and $$('button')[1] because the app never exposed a stable hook. The selector isn't the problem — the frontend is. selfcure reads your source, scores every component for testability, finds the selectors that resolve to multiple elements, and ships data-testid fixes as a Pull Request — so your WebdriverIO suite stops guessing which node it grabbed.

Root cause

Flaky selectors mean an unstable frontend

WebdriverIO gives you great selector strategies — but none of them can invent a stable hook the markup doesn't have. Two patterns cause most flakiness:

Weak selector

No data-testid, id, or accessible name, so you fall back to $('.btn-primary') — broken by the next style change.

Ambiguous selector

The selector matches several elements; the test relies on $$() index order. selfcure detects this at the AST level and proposes a unique data-testid.

selfcure scores and fixes both before your WebdriverIO run.

Before / after

From index juggling to a stable contract

✗ Brittle — class- and index-dependent

// $$ index breaks when the DOM order shifts
await $('.btn-primary').click()
await $$('form input')[1].setValue('a@b.com')

✓ Stable — unique by contract

// data-testid added by a selfcure PR
await $('[data-testid="submit"]').click()
await $('[data-testid="email"]').setValue('a@b.com')

selfcure suggests the values, dedupes collisions across siblings, and opens the PR.

How it works

Three steps, no new test framework

01 · SCORE

Measure testability

Every interactive element gets a 0–100 stability score — a number you can show a tech lead.

02 · FLAG

Find ambiguity

selfcure detects selectors that resolve to multiple elements and proposes a unique data-testid.

03 · SHIP

Open a PR

Pick the fixes, click once. selfcure branches, commits, pushes, and opens a Pull Request on GitHub or GitLab.

Get going

Scan your frontend in two commands

# From your app's root — Node 20+
npx @selfcure/cli init
npx @selfcure/cli lint   # score + flag ambiguous selectors

Connect it to your AI editor (free)

# MCP server — Cursor, Claude Code, VS Code, Windsurf
npx @selfcure/cli mcp

Your AI assistant can query the testability score and ambiguity findings directly.

Team tier

The Team plan adds a web dashboard with score history, automatic PR comments, and branch comparison — proof your frontend is getting more testable over time.

Read the getting-started guide →

FAQ

WebdriverIO + selfcure

Does selfcure run or generate my WebdriverIO tests?

No. selfcure analyzes your frontend source. Your WebdriverIO suite stays as it is — it just gets stable data-testid selectors to target.

Will it work with my React / Vue / Angular app?

Yes. The crawler parses .tsx, .jsx, .vue, Angular .component.ts, and plain .html.

How is this different from using a $$() index?

An index hard-codes DOM order, which breaks on the next refactor. selfcure removes the ambiguity at the source so you target a unique data-testid instead.

Is it really free?

The CLI, testability score, and MCP server are free and open source. Auto-fix, PR opening, and the history dashboard are paid.