AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MIT Self-run

Cypress Ops

skill-0xdarkmatter-claude-mods-cypress-ops · by 0xDarkMatter

Cypress end-to-end and component testing operations - selector/retry-ability strategy, cy.intercept network stubbing, cy.session auth, component vs e2e, flake diagnosis, CI, Test Replay. Use for: cypress, e2e test, component test, cy.get, cy.intercept, cy.session, data-cy, data-test, retry-ability, flake, flaky test, cypress.config, cy.mount, Test Replay, custom commands, fixtures.

No reviews yet
0 installs
2 views
0.0% view→install

Install

$ agentstack add skill-0xdarkmatter-claude-mods-cypress-ops

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-0xdarkmatter-claude-mods-cypress-ops)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
1mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Cypress Ops? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Cypress Operations

Version context (verified against docs.cypress.io, 2026-06): Cypress 14.x, Test Replay (v13+), cy.session with cacheAcrossSpecs. APIs move — confirm against the live docs when a detail is load-bearing.

End-to-end and component testing with Cypress (cypress, TS/JS). The runner executes tests inside a real browser via the Cypress App (cypress open) or headlessly (cypress run). The defining mental model: cy.* commands are not promises — they enqueue onto an async command chain that Cypress drains for you. Internalise that and the agentic gotchas below disappear.

Quick Start

npm install -D cypress
npx cypress open                  # launch the Cypress App: pick E2E or Component, real browser
npx cypress run                   # headless run, all specs (CI default)
npx cypress run --spec "cypress/e2e/auth/*.cy.ts"
npx cypress run --component       # run component specs
npx cypress run --browser chrome --headed
npx cypress run --record --key   # upload to Cypress Cloud (enables Test Replay, v13+)

Specs live in cypress/e2e/**/*.cy.ts (E2E) and beside components or cypress/component/ (component). Config is a single cypress.config.ts at the repo root.

The Async Command Queue (read this first)

cy.get(...) returns a Chainer, not the element and not a Promise. Commands are scheduled, then run in order after the test function returns. This is the source of nearly every Cypress mistake an agent makes.

// WRONG — cy.get does not return a value; `el` is a Chainer, this is meaningless
const el = cy.get('[data-test=total]');
if (el.text() === '$0') { /* never works */ }

// WRONG — async/await does nothing useful; cy commands aren't awaitable promises
const text = await cy.get('[data-test=total]');   // do NOT do this

// RIGHT — yield the value into a callback; assertions inside .should() retry
cy.get('[data-test=total]').should('have.text', '$0');

// RIGHT — need the raw value? use .then() (but it does NOT retry — see below)
cy.get('[data-test=total]').invoke('text').then((text) => {
  // text is a string here; runs after the queue reaches this point
});

Rules that follow from this:

  • No const/let to "store" a command result. Use .as() aliases + cy.get('@alias').
  • No async/await on cy.*. The queue handles ordering. Mixing in real promises?

wrap them with cy.then(() => promise) or cy.wrap(promise).

  • No if/else on element state read synchronously. Conditional testing is an

anti-pattern in Cypress (the DOM may not have settled); make the app deterministic, or drive the branch off a server/cy.intercept state you control. Deep dive: [references/network-and-auth.md](references/network-and-auth.md).

Retry-ability (why you almost never need waits)

Cypress retries queries and assertions until they pass or the command times out (default 4s). It does not retry actions (.click(), .type(), .select()) — those fire once, though the queries leading up to them retry until the element is actionable (visible, not disabled, not animating).

| Construct | Retries? | Use for | |-----------|----------|---------| | cy.get / .find / .contains / .its / .invoke (queries) | Yes — whole chain re-queries | Locating/reading DOM that may not be ready | | .should(...) / expect inside it | Yes — the callback re-runs | Assertions; conditional waits on settled state | | .click / .type / .select (actions) | No — fire once | Interactions (leading queries still retry) | | .then(cb) | No — runs once, no retry protection | Extracting a value; NOT for assertions |

// .should(callback) retries the whole callback — safe for racy DOM
cy.get('[data-test=rows] li').should(($li) => {
  expect($li).to.have.length(3);
  expect($li.first()).to.contain('Alice');
});

// .then() does NOT retry — capturing $el here then asserting later races the render

If you reach for cy.wait(3000), you're missing an assertion or an aliased intercept. The only legitimate cy.wait takes an alias (cy.wait('@getUsers')), never a number.

Selector Strategy

Prefer a dedicated test attribute over CSS classes, IDs, or tag names — the latter are brittle and change with styling/refactors. Cypress recommends data-cy or data-test (the Cypress Real World App standardises on data-test); pick one and enforce it.

// GOOD — decoupled from styling and structure
cy.get('[data-test=submit]').click();

// AVOID — couples the test to CSS/markup that changes for non-test reasons
cy.get('.btn-primary').click();
cy.get('#submit').click();

Wrap the convention in a custom command so specs stay terse:

// cypress/support/commands.ts
Cypress.Commands.add('getBySel', (sel, ...args) =>
  cy.get(`[data-test=${sel}]`, ...args));
Cypress.Commands.add('getBySelLike', (sel, ...args) =>
  cy.get(`[data-test*=${sel}]`, ...args));  // substring match
// usage: cy.getBySel('submit').click();

Reserve cy.contains('Log In') for when the visible text itself is what you're asserting; otherwise it couples tests to copy.

Network Stubbing — cy.intercept

cy.intercept is the single API for spying on and stubbing network traffic. Set it up before the action that triggers the request, alias it, then wait on the alias.

// Stub with a fixture, alias, wait
cy.intercept('GET', '/api/users', { fixture: 'users.json' }).as('getUsers');
cy.visit('/users');
cy.wait('@getUsers');                       // resolves when the request fires

// Inline body / status
cy.intercept('POST', '/api/login', { statusCode: 401, body: { error: 'nope' } }).as('login');

// routeMatcher object (method + glob/regex url) + dynamic reply
cy.intercept({ method: 'GET', url: '/api/orders/*' }, (req) => {
  req.reply((res) => { res.body.hasMore = false; });   // tweak the real response
}).as('orders');

// Assert against the captured request/response
cy.wait('@login').its('response.statusCode').should('eq', 401);

// Wait on several at once
cy.wait(['@getUsers', '@orders']);

Stub what you don't own, exercise what you do. Stubbing third-party/slow endpoints makes tests fast and deterministic; hitting your real backend (seeded via cy.request) verifies the client↔server contract. Decide per endpoint. GraphQL, request modification, and seed-via-cy.request patterns: [references/network-and-auth.md](references/network-and-auth.md).

Authentication — cy.session

Log in once, cache the session, restore it across tests (and optionally specs). This is the biggest suite-speed win after stubbing.

// cypress/support/commands.ts
Cypress.Commands.add('login', (username: string, password: string) => {
  cy.session(
    [username, password],                   // cache key — array/object is stringified
    () => {                                  // setup: runs only on cache miss
      cy.visit('/login');
      cy.get('[data-test=name]').type(username);
      cy.get('[data-test=password]').type(password);
      cy.get('form').contains('Log In').click();
      cy.url().should('contain', '/dashboard');   // assert logged-in before caching!
    },
    {
      validate() {                           // runs after setup AND after each restore
        cy.getCookie('auth_token').should('exist');  // invalid -> setup re-runs
      },
      cacheAcrossSpecs: true,                // default false; true = reuse in every spec
    },
  );
});

Critical behaviour: cookies, localStorage, and sessionStorage across all domains are cleared before setup runs, regardless of testIsolation. Faster still: skip the UI and log in via cy.request inside setup, persisting the token. Patterns (API login, token priming, cy.origin for cross-origin SSO): [references/network-and-auth.md](references/network-and-auth.md).

Component vs E2E Testing

Same runner, two testing types. E2E drives a deployed app through cy.visit. Component mounts a single component in a real browser via cy.mount — no server, no navigation, props/events under direct control.

| | E2E | Component | |---|---|---| | Entry | cy.visit('/path') | cy.mount() | | Needs running app server | Yes | No (bundler dev server only) | | Spec location | cypress/e2e/**/*.cy.ts | beside the component / cypress/component/ | | Support file | cypress/support/e2e.ts | cypress/support/component.ts (registers cy.mount) | | Best for | User flows, integration, auth | Props/events/slots, edge states, visual |

// cypress/support/component.ts  (React example)
import { mount } from 'cypress/react';
Cypress.Commands.add('mount', mount);

// Button.cy.tsx
cy.mount();
cy.get('[data-test=button]').click();
cy.get('@onClick').should('have.been.calledOnce');

Frameworks: React 18–19, Vue 3, Angular 18–21, Svelte 5. Bundlers: Vite 5–8 (React/Vue/ Svelte) or webpack 5 (all + Next.js). Configured under component.devServer.{framework,bundler}. Mounting per framework, store/router mocking, slots: [references/component-testing.md](references/component-testing.md).

Test Isolation, Fixtures, Custom Commands

  • testIsolation: true (default, E2E) clears cookies/storage and resets to about:blank

before each test. Each test must pass run in isolation (it.only to verify) — never rely on a previous test's state. Reset server-side state in beforeEach, not afterEach (an after hook may not run if you refresh mid-test).

  • Multiple assertions per test are fine — don't split into one-assertion tests; state

reset between tests costs more than extra assertions.

  • Fixtures are static JSON in cypress/fixtures/, loaded by cy.fixture('users.json')

or referenced directly in cy.intercept(..., { fixture: 'users.json' }).

  • Custom commands (Cypress.Commands.add) live in cypress/support/commands.ts; add

the cypress/react (etc.) types and a declare global block for TS autocomplete.

CI

# GitHub Actions — the official cypress-io/github-action handles install + cache + run
- uses: actions/checkout@v5
- uses: cypress-io/github-action@v6
  with:
    build: npm run build
    start: npm start                 # boots app, waits on baseUrl before running
    wait-on: 'http://localhost:3000'
    browser: chrome
    record: true                     # upload to Cypress Cloud (Test Replay)
  env:
    CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}

| Decision | Guidance | |----------|----------| | Start the app | Start it before Cypress (start + wait-on), kill after — never cy.exec a server mid-test | | Parallelism | cypress run --record --parallel splits specs across machines — requires Cypress Cloud (paid). Free alternative: shard specs manually across matrix jobs with --spec | | Retries | Config retries: { runMode: 2, openMode: 0 } — surface flakes as a queue, don't paper over them | | Debugging CI failures | Test Replay (v13+, Chromium-only) over video: captures DOM, network, console, errors for time-travel debugging in Cloud |

Full workflows (matrix sharding, containers, artifact upload): [references/ci-and-flake.md](references/ci-and-flake.md).

Flake Diagnosis

Most Cypress flake traces to one of: an action chained where a query/assertion belonged, a missing aliased cy.wait, conditional logic on un-settled DOM, or leaked state between tests.

| Symptom | Likely cause | Fix | |---------|-------------|-----| | "element detached from DOM" | re-render between query and action | split the chain; let the action's leading query retry | | passes alone, fails in suite | inter-test state coupling | reset server state in beforeEach; it.only to confirm | | cy.wait(number) "fixes" it | racing the network | replace with cy.intercept(...).as() + cy.wait('@alias') | | value read with .then() is stale | .then doesn't retry | move the assertion into .should(cb) |

Diagnosis tooling (Test Replay, cypress run --headed, time-travel in the App, screenshots/ video), retry config, and a systematic playbook: [references/ci-and-flake.md](references/ci-and-flake.md).

Cypress vs Playwright (one-table decision)

| Factor | Cypress | Playwright | |--------|---------|-----------| | Execution model | In-browser, async command queue (no await) | Out-of-process, real async/await | | Browsers | Chrome-family, Firefox, Electron; WebKit experimental | Chromium, Firefox, WebKit (real Safari) | | Parallelism | Cypress Cloud (paid) or manual sharding | Free, built-in, shardable | | Multi-tab / multi-origin | Constrained (cy.origin for cross-origin) | Native | | Component testing | Mature, first-class | Experimental | | Interactive DX | The original benchmark (Cypress App, time-travel) | UI mode (excellent) | | API testing | cy.request / cy.intercept | Built-in request context |

Reach for Cypress when component-testing maturity, an existing Cypress investment, or its in-browser DX dominate. Default to Playwright for new E2E needing WebKit, free parallelism, or heavy multi-tab/multi-origin work. Sibling skill: playwright-ops.

Config Skeleton

Full commented production template: [assets/cypress.config.template.ts](assets/cypress.config.template.ts)

import { defineConfig } from 'cypress';

export default defineConfig({
  e2e: {
    baseUrl: 'http://localhost:3000',        // cy.visit('/path') resolves against this
    specPattern: 'cypress/e2e/**/*.cy.{ts,tsx}',
    retries: { runMode: 2, openMode: 0 },    // retry in CI only
    setupNodeEvents(on, config) { return config; },
  },
  component: {
    devServer: { framework: 'react', bundler: 'vite' },
  },
  // testIsolation defaults true; viewportWidth/Height, defaultCommandTimeout tunable here
});

References

| File | Contents | |------|----------| | [references/network-and-auth.md](references/network-and-auth.md) | cy.intercept matching/modifying/GraphQL, cy.session deep dive, API login, cy.origin, seed-via-request | | [references/component-testing.md](references/component-testing.md) | Per-framework cy.mount, store/router/context mocking, slots/events, Vite vs webpack config | | [references/ci-and-flake.md](references/ci-and-flake.md) | Full GH Actions workflows, sharding, Test Replay, retry config, systematic flake playbook | | [assets/cypress.config.template.ts](assets/cypress.config.template.ts) | Commented production config template (E2E + component) |

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.