dist/plugins/web-testing-cypress-e2e/skills/web-testing-cypress-e2e/SKILL.md
Cypress E2E testing patterns - test structure, data-cy selectors, cy.intercept() mocking, custom commands, fixtures, component testing, accessibility testing with cypress-axe, and CI/CD integration
npx skillsauth add agents-inc/skills web-testing-cypress-e2eInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Quick Guide: Use Cypress for end-to-end tests that verify complete user workflows. Use data-cy attributes for resilient selectors, cy.intercept() with aliases for deterministic API mocking (never arbitrary cy.wait(ms)), and cy.session() to cache authentication. Each it() block must be independent. Cypress 15 is current stable; cy.origin() is mandatory for multi-origin tests.
<critical_requirements>
All code must follow project conventions in CLAUDE.md (kebab-case, named exports, import ordering,
import type, named constants)
(You MUST use data-cy attributes as your primary selector strategy - they are isolated from CSS/JS changes)
(You MUST use cy.intercept() with aliases and cy.wait("@alias") - NEVER use arbitrary cy.wait(ms) delays)
(You MUST isolate tests - each it() block runs independently without depending on other tests)
(You MUST use cy.origin() for any test that navigates across different origins - required since Cypress 14)
</critical_requirements>
Auto-detection: Cypress, cy.visit, cy.get, cy.intercept, cy.origin, cy.session, data-cy, describe, it, beforeEach, cy.fixture, cy.mount, cypress-axe, cy.env
When to use:
When NOT to use:
Key patterns covered:
Detailed Resources:
Cypress E2E tests verify that your application works correctly from the user's perspective. They run in the same run-loop as your application, providing reliable, fast feedback on user-visible behavior.
Core Principles:
When E2E tests provide the most value:
When E2E tests may not be the best choice:
Use describe to group related tests, context for different scenarios, and it for individual test cases. Named constants prevent magic strings. Each test starts fresh via beforeEach.
const LOGIN_URL = "/login";
const DASHBOARD_URL = "/dashboard";
const VALID_EMAIL = "[email protected]";
describe("Login Flow", () => {
beforeEach(() => {
cy.visit(LOGIN_URL);
});
context("with valid credentials", () => {
it("redirects to dashboard after successful login", () => {
cy.get("[data-cy=email-input]").type(VALID_EMAIL);
// ...
cy.url().should("include", DASHBOARD_URL);
});
});
});
Why good: Logical grouping with describe/context, beforeEach ensures isolation, named constants, data-cy selectors
See examples/core.md Pattern 1-2 for complete login flow and grouped test examples.
Use data-cy attributes for reliable element selection. They survive CSS refactoring and make test intent clear.
// BEST: data-cy attributes
cy.get("[data-cy=submit-button]").click();
// ACCEPTABLE: cy.contains() when text change should fail the test
cy.contains("button", "Submit").click();
// AVOID: CSS classes, IDs, DOM structure - all fragile
cy.get(".btn-primary").click(); // Breaks on styling changes
cy.get("div > button:nth-child(2)").click(); // Breaks on markup changes
Use cy.getBySel() custom command to reduce boilerplate. See examples/core.md Pattern 3 and examples/custom-commands.md Pattern 1 for implementation.
Mock API responses for deterministic, fast tests. Always alias intercepts and wait on the alias.
cy.intercept("GET", "/api/users", {
statusCode: 200,
body: MOCK_USER,
}).as("getUser");
cy.visit("/profile");
cy.wait("@getUser");
cy.getBySel("user-name").should("contain", MOCK_USER.name);
Why good: Tests are deterministic, alias + wait ensures request completed, no arbitrary delays
Test error states with status codes and forceNetworkError: true. See examples/intercept.md for error state testing, request verification, response modification, and pagination patterns.
Wrap common flows (login, selectors) in custom commands with type declarations for IDE autocomplete.
// cypress/support/commands.ts
Cypress.Commands.add("login", (email: string, password: string) => {
cy.session([email, password], () => {
cy.visit("/login");
cy.getBySel("email-input").type(email);
cy.getBySel("password-input").type(password);
cy.getBySel("submit-button").click();
cy.url().should("include", "/dashboard");
});
});
Type declarations go in cypress/support/index.d.ts. See examples/custom-commands.md for selector commands, auth commands with cacheAcrossSpecs, form commands, child/dual commands, database task commands, and cy.origin() commands.
Use fixtures for reusable test data, factories for dynamic data.
// Fixture: cy.intercept with fixture file
cy.intercept("GET", "/api/products", { fixture: "products.json" }).as(
"getProducts",
);
// Factory: dynamic data for specific scenarios
const users = createUsers(5);
cy.intercept("GET", "/api/users", { body: users }).as("getUsers");
Why good: Separates test data from test logic, fixtures are reusable, factories generate scenario-specific data
See examples/fixtures-data.md for organized fixture directories, factory patterns, and centralized test constants.
Cypress 14+ requires cy.origin() for any test that navigates across different origins (scheme + hostname + port). This is mandatory for OAuth, SSO, and cross-domain workflows.
cy.visit("/login");
cy.getBySel("oauth-button").click();
cy.origin(
"https://auth.provider.com",
{ args: { email, password } },
({ email, password }) => {
cy.get("#email").type(email);
cy.get("#password").type(password);
cy.get("#submit").click();
},
);
cy.url().should("include", "/dashboard"); // Back on original origin
Why required: Chrome deprecated document.domain, which Cypress previously used for cross-origin testing.
See examples/custom-commands.md Pattern 7 for reusable OAuth command with session caching.
</patterns><red_flags>
High Priority Issues:
cy.wait(5000) with arbitrary milliseconds - causes flaky or slow tests, use cy.intercept() aliases instead.btn-primary or #submit-btn - fragile and break on refactoring, use data-cyconst for later use - Cypress commands are async, use aliases with .as() insteadcy.origin() for multi-origin tests - required since Cypress 14 due to Chrome's deprecation of document.domainCypress.env() - use cy.env() for secrets, Cypress.expose() for public values (deprecated in v15.10.0, removed in 16)Medium Priority Issues:
Cypress.Commands.overwrite() for queries - use Cypress.Commands.overwriteQuery() since Cypress 14Common Mistakes:
after/afterEach for cleanup - no guarantee it runs, put cleanup in beforeEachGotchas & Edge Cases:
.then() for valuescy.session() caches login state but clears on spec file change - use cacheAcrossSpecs: true (Cypress 12.4+)--load-extension in branded Chrome - use Electron, Chrome for Testing, or Chromium for extensions</red_flags>
<critical_reminders>
All code must follow project conventions in CLAUDE.md
(You MUST use data-cy attributes as your primary selector strategy - they are isolated from CSS/JS changes)
(You MUST use cy.intercept() with aliases and cy.wait("@alias") - NEVER use arbitrary cy.wait(ms) delays)
(You MUST isolate tests - each it() block runs independently without depending on other tests)
(You MUST use cy.origin() for any test that navigates across different origins - required since Cypress 14)
Failure to follow these rules will result in flaky tests, false positives, and maintenance nightmares.
</critical_reminders>
development
Material Design component library for Vue 3
development
VitePress 1.x — Vue-powered static site generator for documentation sites, built on Vite
tools
Docusaurus 3.x documentation framework — site configuration, docs/blog plugins, sidebars, versioning, MDX, swizzling, and deployment
development
TanStack Form patterns - useForm, form.Field, validators, arrays, linked fields, createFormHook, type safety