{"skill":{"slug":"cypress-agent-skill","displayName":"Cypress Agent Skill","summary":"Production-grade Cypress E2E and component testing — selectors, network stubbing, auth, CI parallelization, flake elimination, Page Object Model, and TypeScr...","description":"---\nname: cypress-agent-skill\ndescription: Production-grade Cypress E2E and component testing — selectors, network stubbing, auth, CI parallelization, flake elimination, Page Object Model, and TypeScript support. The complete Cypress skill for AI agents.\nuser-invocable: true\nmetadata: {\"openclaw\":{\"emoji\":\"🧪\",\"requires\":{\"anyBins\":[\"cypress\",\"npx\"]},\"install\":[{\"id\":\"npm\",\"kind\":\"node\",\"package\":\"cypress\",\"label\":\"Install Cypress (npm)\"}]}}\n---\n\n# Cypress Expert Skill\n\n## Quick Reference\n\n**When to use this skill:**\n- Writing or fixing Cypress E2E or component tests\n- Setting up Cypress in a new project\n- Debugging flaky tests\n- Adding network stubbing / API mocking\n- Configuring CI pipelines for Cypress\n- Implementing auth patterns (`cy.session`)\n- Building Page Object Model architecture\n\n**Quick start:**\n1. `npm install --save-dev cypress` — install\n2. `npx cypress open` — interactive mode (first run generates config)\n3. `npx cypress run` — headless CI mode\n4. Read full references in `{baseDir}/references/` for deep patterns\n\n---\n\n## Core Philosophy\n\nCypress runs **inside the browser**. It has native access to the DOM, network requests, and application state. Every command is automatically retried until it passes or times out. This means:\n\n- **Never use `cy.wait(3000)`** — use aliases + `cy.wait('@alias')` instead\n- **Never query DOM immediately after an action** — Cypress retries automatically\n- **Always assert on outcomes, not implementation** — test user-visible behavior\n- **Use `data-testid` attributes** — decouple tests from styling/structure\n\n---\n\n## 1. Installation & Configuration\n\n### Install\n\n```bash\nnpm install --save-dev cypress\n# or\nyarn add -D cypress\n# or\npnpm add -D cypress\n```\n\n### cypress.config.js (JavaScript)\n\n```js\nconst { defineConfig } = require('cypress')\n\nmodule.exports = defineConfig({\n  e2e: {\n    baseUrl: 'http://localhost:3000',\n    viewportWidth: 1280,\n    viewportHeight: 720,\n    video: false,\n    screenshotOnRunFailure: true,\n    defaultCommandTimeout: 8000,\n    requestTimeout: 10000,\n    responseTimeout: 10000,\n    retries: {\n      runMode: 2,\n      openMode: 0,\n    },\n    // v15.10.0+ — enforce new cy.env() / Cypress.expose() APIs\n    // set after migrating all Cypress.env() calls\n    allowCypressEnv: false,\n    // v15.x — faster visibility checks\n    experimentalFastVisibility: true,\n    // v15.9.0+ — run all specs without --parallel flag; now works for component tests too\n    experimentalRunAllSpecs: true,\n    setupNodeEvents(on, config) {\n      return config\n    },\n  },\n  component: {\n    devServer: {\n      framework: 'react',\n      bundler: 'vite',\n    },\n    experimentalRunAllSpecs: true,\n  },\n})\n```\n\n### cypress.config.ts (TypeScript)\n\n```ts\nimport { defineConfig } from 'cypress'\n\nexport default defineConfig({\n  e2e: {\n    baseUrl: 'http://localhost:3000',\n    specPattern: 'cypress/e2e/**/*.cy.ts',\n    setupNodeEvents(on, config) {\n      return config\n    },\n  },\n})\n```\n\n### tsconfig for Cypress\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"es5\",\n    \"lib\": [\"es5\", \"dom\"],\n    \"types\": [\"cypress\", \"node\"]\n  },\n  \"include\": [\"**/*.ts\"]\n}\n```\n\n---\n\n## 2. Selectors (Stability Hierarchy)\n\nUse the most stable selector available. Prefer in this order:\n\n```js\n// ✅ BEST — semantic, decoupled from style/structure\ncy.get('[data-testid=\"submit-button\"]')\ncy.get('[data-cy=\"login-form\"]')\ncy.get('[data-test=\"user-email\"]')\n\n// ✅ GOOD — ARIA/accessibility selectors\ncy.get('[role=\"dialog\"]')\ncy.get('[aria-label=\"Close modal\"]')\ncy.get('button[type=\"submit\"]')\n\n// ✅ GOOD — cy.contains for text-driven queries\ncy.contains('button', 'Submit')\ncy.contains('[data-testid=\"nav\"]', 'Dashboard')\n\n// ⚠️ FRAGILE — CSS classes tied to styling\ncy.get('.btn-primary')         // avoid\ncy.get('.MuiButton-root')      // avoid\n\n// ❌ WORST — absolute XPath / positional\ncy.get('div > ul > li:nth-child(3) > a')  // never\n```\n\n### Scoped Queries\n\n```js\ncy.get('[data-testid=\"user-card\"]').within(() => {\n  cy.get('[data-testid=\"user-name\"]').should('contain', 'Alice')\n  cy.get('[data-testid=\"user-role\"]').should('contain', 'Admin')\n})\n\ncy.get('table').find('tr').should('have.length', 5)\n```\n\n---\n\n## 3. Assertions\n\n### Should / Expect\n\n```js\n// Chainable assertions\ncy.get('[data-testid=\"title\"]').should('be.visible')\ncy.get('[data-testid=\"title\"]').should('have.text', 'Dashboard')\ncy.get('[data-testid=\"title\"]').should('contain.text', 'Dash')\n\n// Multiple assertions (all retry together)\ncy.get('[data-testid=\"btn\"]')\n  .should('be.visible')\n  .and('not.be.disabled')\n  .and('have.attr', 'type', 'submit')\n\n// Value\ncy.get('input[name=\"email\"]').should('have.value', 'user@example.com')\n\n// Length assertions\ncy.get('[data-testid=\"item\"]').should('have.length', 3)\ncy.get('[data-testid=\"item\"]').should('have.length.greaterThan', 0)\n\n// Negative assertions (use carefully — can pass too early)\ncy.get('[data-testid=\"error\"]').should('not.exist')\ncy.get('[data-testid=\"spinner\"]').should('not.be.visible')\n\n// BDD expect style\ncy.get('[data-testid=\"count\"]').invoke('text').then((text) => {\n  expect(parseInt(text)).to.be.greaterThan(0)\n})\n\n// URL assertions\ncy.url().should('include', '/dashboard')\ncy.url().should('eq', 'http://localhost:3000/dashboard')\n\n// Alias + should\ncy.get('[data-testid=\"price\"]').invoke('text').as('price')\ncy.get('@price').should('match', /\\$\\d+\\.\\d{2}/)\n```\n\n### Async State Assertions\n\n```js\n// Wait for element to appear (retries automatically)\ncy.get('[data-testid=\"success-message\"]', { timeout: 10000 })\n  .should('be.visible')\n\n// Wait for element to disappear\ncy.get('[data-testid=\"loading-spinner\"]').should('not.exist')\n```\n\n---\n\n## 4. Network Stubbing with cy.intercept\n\n```js\n// Basic stub\ncy.intercept('GET', '/api/users', {\n  statusCode: 200,\n  body: [\n    { id: 1, name: 'Alice', role: 'admin' },\n    { id: 2, name: 'Bob', role: 'user' },\n  ],\n}).as('getUsers')\n\ncy.visit('/users')\ncy.wait('@getUsers')\ncy.get('[data-testid=\"user-row\"]').should('have.length', 2)\n\n// Fixture file\ncy.intercept('GET', '/api/users', { fixture: 'users.json' }).as('getUsers')\n\n// Glob/regex patterns\ncy.intercept('GET', '/api/users/*').as('getUser')\ncy.intercept('GET', /\\/api\\/products\\/\\d+/).as('getProduct')\n\n// Dynamic handler\ncy.intercept('POST', '/api/orders', (req) => {\n  req.reply({ statusCode: 201, body: { id: 999, ...req.body } })\n}).as('createOrder')\n\n// Modify real server response (spy + transform)\ncy.intercept('GET', '/api/config', (req) => {\n  req.reply((res) => {\n    res.body.featureFlag = true\n    return res\n  })\n}).as('getConfig')\n\n// Error simulation\ncy.intercept('GET', '/api/critical', { forceNetworkError: true }).as('networkError')\ncy.intercept('GET', '/api/data', { statusCode: 500, body: { error: 'Server Error' } }).as('serverError')\n\n// Delay (for loading state tests)\ncy.intercept('GET', '/api/data', (req) => {\n  req.reply({ delay: 1000, body: { data: [] } })\n}).as('slowRequest')\n\n// Assert request details\ncy.wait('@createOrder').then((interception) => {\n  expect(interception.request.body).to.deep.include({ quantity: 2 })\n  expect(interception.response.statusCode).to.equal(201)\n})\n```\n\n---\n\n## 5. Authentication Patterns\n\n### cy.session — Cache Auth State (Recommended)\n\n```js\nCypress.Commands.add('loginByUI', (email, password) => {\n  cy.session(\n    [email, password],\n    () => {\n      cy.visit('/login')\n      cy.get('[data-testid=\"email\"]').type(email)\n      cy.get('[data-testid=\"password\"]').type(password)\n      cy.get('[data-testid=\"submit\"]').click()\n      cy.url().should('include', '/dashboard')\n    },\n    {\n      validate() {\n        cy.getCookie('session_token').should('exist')\n      },\n      cacheAcrossSpecs: true,\n    }\n  )\n})\n```\n\n### API-Based Auth (Faster)\n\n```js\nCypress.Commands.add('loginByApi', (email, password) => {\n  cy.session(\n    ['api', email, password],\n    () => {\n      cy.request({\n        method: 'POST',\n        url: '/api/auth/login',\n        body: { email, password },\n      }).then(({ body }) => {\n        window.localStorage.setItem('auth_token', body.token)\n        cy.setCookie('session', body.sessionId)\n      })\n    },\n    {\n      validate() {\n        cy.window().its('localStorage').invoke('getItem', 'auth_token').should('exist')\n      },\n    }\n  )\n})\n\n// Usage — cy.env() for secrets (v15.10.0+, replaces deprecated Cypress.env())\nbeforeEach(() => {\n  cy.env(['adminPassword']).then(({ adminPassword }) => {\n    cy.loginByApi('admin@example.com', adminPassword)\n    cy.visit('/dashboard')\n  })\n})\n```\n\n---\n\n## 6. Custom Commands\n\n```js\n// cypress/support/commands.js\nCypress.Commands.add('getByTestId', (testId, options) => {\n  return cy.get(`[data-testid=\"${testId}\"]`, options)\n})\n\nCypress.Commands.add('waitForToast', (message) => {\n  const selector = '[data-testid=\"toast\"], [role=\"status\"]'\n  if (message) {\n    cy.get(selector, { timeout: 10000 }).should('contain', message)\n  } else {\n    cy.get(selector, { timeout: 10000 }).should('be.visible')\n  }\n})\n\nCypress.Commands.add('fillForm', (data) => {\n  Object.entries(data).forEach(([field, value]) => {\n    cy.get(`[name=\"${field}\"]`).clear().type(String(value))\n  })\n})\n\n// TypeScript — cypress/support/index.d.ts\ndeclare global {\n  namespace Cypress {\n    interface Chainable {\n      getByTestId(testId: string, options?: Partial<Loggable & Timeoutable>): Chainable<JQuery>\n      loginByApi(email: string, password: string): Chainable<void>\n      loginByUI(email: string, password: string): Chainable<void>\n      waitForToast(message?: string): Chainable<void>\n      fillForm(data: Record<string, string | number>): Chainable<void>\n    }\n  }\n}\n```\n\n---\n\n## 7. Page Object Model\n\n```js\n// cypress/pages/LoginPage.js\nclass LoginPage {\n  visit() { cy.visit('/login'); return this }\n  getEmailInput() { return cy.get('[data-testid=\"email-input\"]') }\n  getPasswordInput() { return cy.get('[data-testid=\"password-input\"]') }\n  getSubmitButton() { return cy.get('[data-testid=\"submit-button\"]') }\n  getErrorMessage() { return cy.get('[data-testid=\"error-message\"]') }\n\n  login(email, password) {\n    this.getEmailInput().clear().type(email)\n    this.getPasswordInput().clear().type(password)\n    this.getSubmitButton().click()\n    return this\n  }\n\n  assertLoggedIn() { cy.url().should('include', '/dashboard'); return this }\n  assertError(message) { this.getErrorMessage().should('contain', message); return this }\n}\n\nexport default new LoginPage()\n\n// Usage\nimport loginPage from '../pages/LoginPage'\n\nit('logs in successfully', () => {\n  loginPage.visit().login('admin@example.com', 'password123').assertLoggedIn()\n})\n```\n\n---\n\n## 8. Component Testing\n\n```js\n// cypress/component/Button.cy.jsx\nimport { mount } from 'cypress/react'\nimport Button from '../../src/components/Button'\n\ndescribe('Button', () => {\n  it('calls onClick when clicked', () => {\n    const onClick = cy.stub().as('clickHandler')\n    mount(<Button label=\"Submit\" onClick={onClick} />)\n    cy.get('button').click()\n    cy.get('@clickHandler').should('have.been.calledOnce')\n  })\n\n  it('is disabled when loading', () => {\n    mount(<Button label=\"Submit\" loading={true} />)\n    cy.get('button').should('be.disabled')\n  })\n})\n\n// Run component tests\n// npx cypress open --component\n// npx cypress run --component\n```\n\n---\n\n## 9. Common Patterns\n\n```js\n// Forms\ncy.get('input[name=\"email\"]').clear().type('new@example.com')\ncy.get('select[name=\"country\"]').select('United States')\ncy.get('[data-testid=\"agree\"]').check()\ncy.get('[data-testid=\"file-input\"]').selectFile('cypress/fixtures/doc.pdf')\n\n// File drag & drop\ncy.get('[data-testid=\"drop-zone\"]').selectFile('cypress/fixtures/image.png', {\n  action: 'drag-drop',\n})\n\n// Modal handling\ncy.get('[data-testid=\"open-modal\"]').click()\ncy.get('[role=\"dialog\"]').should('be.visible')\ncy.get('[role=\"dialog\"]').within(() => {\n  cy.get('[data-testid=\"confirm-btn\"]').click()\n})\ncy.get('[role=\"dialog\"]').should('not.exist')\n\n// Window alerts\ncy.on('window:alert', (text) => { expect(text).to.contain('Success') })\ncy.on('window:confirm', () => true)\n\n// LocalStorage / Cookies\ncy.window().then((win) => { win.localStorage.setItem('key', 'value') })\ncy.setCookie('session', 'abc123')\ncy.clearAllCookies()\ncy.clearAllLocalStorage()\n\n// Date/Time control\ncy.clock(new Date('2024-03-15'))\ncy.tick(25 * 60 * 1000)  // advance 25 minutes\n\n// Spy on methods\ncy.visit('/checkout', {\n  onBeforeLoad(win) { cy.spy(win.analytics, 'track').as('track') },\n})\ncy.get('@track').should('have.been.calledWith', 'Purchase Completed')\n```\n\n---\n\n## 10. Flake Prevention\n\n```js\n// ❌ FLAKY\ncy.wait(2000)\ncy.get('[data-testid=\"result\"]').should('exist')\n\n// ✅ STABLE — wait for network alias\ncy.intercept('GET', '/api/results').as('getResults')\ncy.get('[data-testid=\"search-btn\"]').click()\ncy.wait('@getResults')\ncy.get('[data-testid=\"result\"]').should('have.length.greaterThan', 0)\n\n// Test isolation — reset state between tests\nbeforeEach(() => {\n  cy.clearAllCookies()\n  cy.clearAllLocalStorage()\n  cy.clearAllSessionStorage()\n})\n\n// Retries config\nretries: { runMode: 2, openMode: 0 }\n\n// Per-test retry\nit('critical path', { retries: 3 }, () => { ... })\n```\n\n---\n\n## 11. CI / Parallelization\n\n### GitHub Actions (Parallel Matrix)\n\n```yaml\nname: Cypress Tests\non: [push, pull_request]\n\njobs:\n  cypress-run:\n    runs-on: ubuntu-latest\n    strategy:\n      fail-fast: false\n      matrix:\n        containers: [1, 2, 3, 4]\n    steps:\n      - uses: actions/checkout@v4\n      - uses: actions/setup-node@v4\n        with: { node-version: 22, cache: 'npm' }\n      - run: npm ci\n      - run: npm start &\n      - run: npx wait-on http://localhost:3000 --timeout 60000\n      - uses: cypress-io/github-action@v6\n        with:\n          record: true\n          parallel: true\n          group: 'UI Tests'\n          tag: ${{ github.ref_name }}\n        env:\n          CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}\n          CYPRESS_ADMIN_PASSWORD: ${{ secrets.ADMIN_PASSWORD }}   # accessed via cy.env()\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n      - uses: actions/upload-artifact@v4\n        if: failure()\n        with:\n          name: cypress-screenshots\n          path: cypress/screenshots\n```\n\n### New CLI flags (v15.11.0)\n\n```bash\n# Don't fail the run when no tests are found (useful for conditional spec discovery)\nnpx cypress run --pass-with-no-tests\n\n# Run component tests with experimentalRunAllSpecs (now works for component testing too, v15.9.0+)\nnpx cypress run --component\n```\n\n### Smoke Test Tags\n\n```js\n// Run subset of tests in CI\nconst isSmoke = Cypress.expose('SMOKE') === 'true'\n;(isSmoke ? describe.only : describe)('Checkout', () => { ... })\n// Run: CYPRESS_SMOKE=true npx cypress run\n```\n\n### Docker Compose for CI\n\n```yaml\nversion: '3.8'\nservices:\n  app:\n    build: .\n    ports:\n      - \"3000:3000\"\n  cypress:\n    image: cypress/included:15.11.0   # updated from 13.x\n    depends_on:\n      - app\n    environment:\n      - CYPRESS_baseUrl=http://app:3000\n      - CYPRESS_ADMIN_PASSWORD=${ADMIN_PASSWORD}   # passed via cy.env()\n    volumes:\n      - ./:/e2e\n    working_dir: /e2e\n    command: cypress run --browser chrome\n```\n\n---\n\n## 12. Environment Variables\n\n> ⚠️ **Breaking change in v15.10.0:** `Cypress.env()` is deprecated and will be removed in Cypress 16.  \n> Migrate to `cy.env()` for secrets and `Cypress.expose()` for public config values.\n\n### New API (v15.10.0+)\n\n```js\n// cy.env() — for SECRETS (API keys, passwords, tokens)\n// Async, only exposes the values you explicitly request\n// Values are NOT serialized into browser state\ncy.env(['apiKey', 'adminPassword']).then(({ apiKey, adminPassword }) => {\n  cy.request({\n    method: 'POST',\n    url: '/api/auth/login',\n    body: { email: 'admin@test.com', password: adminPassword },\n    headers: { Authorization: `Bearer ${apiKey}` },\n  })\n})\n\n// Cypress.expose() — for NON-SENSITIVE public config\n// Synchronous, safe to appear in browser state\n// Use for: feature flags, API versions, env labels, base URLs\nconst apiUrl = Cypress.expose('apiUrl')\ncy.visit(apiUrl + '/dashboard')\n```\n\n### cypress.config.js (v15.10.0+)\n\n```js\nconst { defineConfig } = require('cypress')\n\nmodule.exports = defineConfig({\n  // Enforce migration — disables legacy Cypress.env() API entirely\n  allowCypressEnv: false,\n\n  env: {\n    apiUrl: 'http://localhost:3001',       // non-sensitive — use Cypress.expose()\n    adminEmail: 'admin@test.com',          // non-sensitive — use Cypress.expose()\n    // secrets (apiKey, adminPassword) come from cypress.env.json or CYPRESS_* OS vars\n    // never hardcode secrets here\n  },\n})\n```\n\n### cypress.env.json — secrets only (gitignore this file)\n\n```json\n{\n  \"adminPassword\": \"secret123\",\n  \"apiKey\": \"test-key\"\n}\n```\n\n### CI environment variables (prefix CYPRESS\\_)\n\n```bash\n# Set secrets as CI env vars — accessed via cy.env()\nCYPRESS_API_KEY=abc123 npx cypress run\nCYPRESS_ADMIN_PASSWORD=secret npx cypress run\n```\n\n### Migration cheatsheet\n\n| Old (deprecated) | New | When |\n|---|---|---|\n| `Cypress.env('apiKey')` | `cy.env(['apiKey']).then(...)` | Secrets, inside hooks/tests |\n| `Cypress.env('apiUrl')` | `Cypress.expose('apiUrl')` | Public config, synchronous access needed |\n| `Cypress.env()` (all) | Never use — intentional explicit access only | — |\n\n### Plugin migration note\n\nPopular plugins require updates to drop `Cypress.env()`:\n- `@cypress/grep` → upgrade to latest major\n- `@cypress/code-coverage` → upgrade to latest major\n- Review all custom plugins for `Cypress.env()` usage before setting `allowCypressEnv: false`\n\n---\n\n## 13. Fixtures and Data Management\n\n```js\n// cypress/fixtures/user.json\n{\n  \"id\": 1,\n  \"name\": \"Test User\",\n  \"email\": \"test@example.com\",\n  \"role\": \"admin\"\n}\n\n// Load fixture\ncy.fixture('user.json').then((user) => {\n  cy.get('[data-testid=\"name\"]').should('contain', user.name)\n})\n\n// Use fixture as stub (shorthand)\ncy.intercept('GET', '/api/user', { fixture: 'user.json' }).as('getUser')\n\n// Dynamic data generation\nconst generateUser = (overrides = {}) => ({\n  id: Math.random(),\n  name: 'Test User',\n  email: `test+${Date.now()}@example.com`,\n  role: 'user',\n  ...overrides,\n})\n\ncy.intercept('GET', '/api/user', generateUser({ role: 'admin' })).as('getUser')\n\n// Seed DB via API task (faster than UI)\nbeforeEach(() => {\n  cy.request('POST', '/api/test/reset', { scenario: 'clean-slate' })\n})\n```\n\n---\n\n## 14. Accessibility Testing\n\n```js\n// Install: npm install --save-dev cypress-axe axe-core\n// Add to cypress/support/e2e.js: import 'cypress-axe'\n\ndescribe('Accessibility', () => {\n  beforeEach(() => {\n    cy.visit('/')\n    cy.injectAxe()\n  })\n\n  it('has no detectable a11y violations on load', () => {\n    cy.checkA11y()\n  })\n\n  it('has no violations in the modal', () => {\n    cy.get('[data-testid=\"open-modal\"]').click()\n    cy.get('[role=\"dialog\"]').should('be.visible')\n    cy.checkA11y('[role=\"dialog\"]', {\n      rules: {\n        'color-contrast': { enabled: false },  // disable specific rules\n      },\n    })\n  })\n\n  it('reports violations with details', () => {\n    cy.checkA11y(null, null, (violations) => {\n      violations.forEach((violation) => {\n        cy.log(`${violation.id}: ${violation.description}`)\n        violation.nodes.forEach((node) => cy.log(node.html))\n      })\n    })\n  })\n})\n```\n\n---\n\n## 15. Best Practices Summary\n\n| Pattern | Do | Don't |\n|---|---|---|\n| Selectors | `data-testid` attributes | CSS classes, XPath |\n| Waiting | `cy.wait('@alias')` | `cy.wait(3000)` |\n| Auth | `cy.session()` | Login via UI every test |\n| Assertions | Chain `.should()` | Implicit `then()` checks |\n| Data | API seeding | UI-based test data setup |\n| Isolation | `beforeEach` resets | Shared state between tests |\n| Network | `cy.intercept()` stubs | Real API calls in unit tests |\n\n---\n\n## 16. Debugging\n\n```js\n// Pause execution — opens interactive debugger in Cypress UI\ncy.pause()\n\n// Debug current subject — logs to console\ncy.get('[data-testid=\"el\"]').debug()\n\n// Log custom messages\ncy.log('Current step: submitting checkout form')\n\n// Take screenshot at specific point\ncy.screenshot('before-submit')\n\n// Inspect DOM state\ncy.get('[data-testid=\"form\"]').then(($el) => {\n  console.log('Form HTML:', $el.html())\n  debugger  // opens DevTools when running in interactive mode\n})\n\n// Time travel debugging: Cypress UI → click any command in the log → DOM snapshot appears\n```\n\n### cy.prompt() — Experimental Natural Language Tests (v15.x)\n\n```js\n// cy.prompt() lets you write tests in plain English\n// Cypress AI interprets intent and generates the necessary commands\n// Enable: set experimentalCyPrompt: true in cypress.config.js\n\ncy.prompt('Click the submit button and verify the success message appears')\ncy.prompt('Fill in the login form with admin credentials and sign in')\ncy.prompt('Verify the product list shows 3 items and the first one is selected')\n```\n\n> Enable with: `experimentalCyPrompt: true` in `cypress.config.js`. Self-healing: if a selector changes, Cypress attempts to re-locate the element by intent rather than failing immediately.\n\n---\n\n## References\n\nAll detailed references in `{baseDir}/references/`:\n\n- `selectors.md` — Selector strategies and anti-patterns\n- `commands.md` — Full cy.* command cheatsheet\n- `network.md` — cy.intercept advanced patterns\n- `assertions.md` — Complete assertion reference\n- `config.md` — Full cypress.config.js options\n- `ci.md` — CI/CD setup guides (GitHub Actions, GitLab, CircleCI, Jenkins)\n- `component-testing.md` — React/Vue/Angular component testing\n- `patterns.md` — Visual regression, API testing, multi-tab, drag/drop\n\n## Examples\n\nWorking test files in `{baseDir}/examples/`:\n\n- `auth-flow.cy.js` — Full auth with cy.session\n- `api-intercept.cy.js` — Network stubbing patterns\n- `page-objects.cy.js` — POM implementation\n- `custom-commands.js` — Custom command library","tags":{"latest":"0.1.0"},"stats":{"comments":0,"downloads":816,"installsAllTime":2,"installsCurrent":2,"stars":0,"versions":1},"createdAt":1772862033259,"updatedAt":1778996223862},"latestVersion":{"version":"0.1.0","createdAt":1772862033259,"changelog":"Cypress Agent Skill v0.1.0 — initial release\n\n- Adds quick-start guidance for Cypress E2E and component testing, including installation, configuration, and best practices.\n- Covers robust selectors, retryable assertions, and best practices for test stability.\n- Provides comprehensive recipes for stubbing network requests with cy.intercept.\n- Documents authentication strategies, including cy.session and API-based login.\n- Offers CI pipeline configuration tips and deep references for advanced patterns.\n- User-invocable with built-in metadata for easy setup and integration.","license":null},"metadata":{"setup":[],"os":null,"systems":null},"owner":{"handle":"kahlilr23","userId":"s1705ksy0zmwx2h3g2zjqqched885bfe","displayName":"KahlilR23","image":"https://avatars.githubusercontent.com/u/68018485?v=4"},"moderation":{"isSuspicious":false,"isMalwareBlocked":false,"verdict":"clean","reasonCodes":["review.llm_review"],"summary":"Review: review.llm_review","engineVersion":"v2.4.24","updatedAt":1780089791418}}