selfcure
selfcure × TestCafe

TestCafe selectors keep breaking?
Map your frontend's maturity first.

Every release you patch another Selector('.btn-primary'). The Selector isn't wrong — the frontend gave it nothing stable to hold onto. 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 TestCafe suite stops chasing the DOM.

Root cause

A breaking Selector is an unstable frontend

TestCafe's smart Selectors are resilient — but they can't invent a stable hook that the markup doesn't have. Two patterns cause most breakage:

Weak Selector

No data-testid, id, or accessible name, so the Selector targets a class like .btn-primary that a refactor breaks.

Ambiguous Selector

The Selector matches several elements; the test relies on .nth() and document order. selfcure detects this at the AST level.

selfcure scores and fixes both before your TestCafe run.

Before / after

From class chasing to a stable contract

✗ Brittle — class- and order-dependent

// matches multiple buttons → relies on .nth()
await t.click(Selector('.btn-primary').nth(0))
await t.typeText(Selector('form input').nth(1), 'a@b.com')

✓ Stable — unique by contract

// data-testid added by a selfcure PR
await t.click(Selector('[data-testid="submit"]'))
await t.typeText(Selector('[data-testid="email"]'), '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

Each interactive element gets a 0–100 stability score — a metric you can take to 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

TestCafe + selfcure

Does selfcure run or generate my TestCafe tests?

No. selfcure analyzes your frontend source. Your TestCafe 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 .nth()?

.nth() hard-codes document order, which the next refactor breaks. selfcure removes the ambiguity at the source so you don't need .nth() at all.

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.