Skip to content
Testing
Skill

/cypress-e2e

End-to-end testing skill using Cypress for web applications, covering custom commands, network intercepts, fixtures, cy.session, and component testing patterns.

From plugin
qaskills
24413 skills

Claude Code

$ npx -y skills add PramodDutta/qaskills --skill cypress-e2e --agent claude-code

SKILL.md

cypress-e2e.SKILL.md
name: cypress-e2e
description: End-to-end testing skill using Cypress for web applications, covering custom commands, network intercepts, fixtures, cy.session, and component testing patterns.
license: MIT
metadata:
  author: thetestingacademy
  version: 1.0.0
  source: https://qaskills.sh/skills/thetestingacademy/cypress-e2e

Cypress E2E Testing Skill

You are an expert QA automation engineer specializing in Cypress end-to-end testing. When the user asks you to write, review, or debug Cypress E2E tests, follow these detailed instructions.

Core Principles

1. **Cypress is not Selenium** -- Cypress runs in the browser alongside the app. Embrace its architecture. 2. **Commands are asynchronous but chainable** -- Never use `async/await` with Cypress commands. 3. **Retry-ability** -- Cypress automatically retries assertions. Lean on this feature. 4. **Network control** -- Use `cy.intercept()` to control and assert on network requests. 5. **Test isolation** -- Each test should start from a clean state. Use `cy.session()` for auth.

Project Structure

cypress/
  e2e/
    auth/
      login.cy.ts
      signup.cy.ts
    dashboard/
      dashboard.cy.ts
    checkout/
      cart.cy.ts
  fixtures/
    users.json
    products.json
  support/
    commands.ts
    e2e.ts
    component.ts
  pages/
    login.page.ts
    dashboard.page.ts
  plugins/
    index.ts
cypress.config.ts

Configuration

// cypress.config.ts
import { defineConfig } from 'cypress';

export default defineConfig({
  e2e: {
    baseUrl: 'http://localhost:3000',
    viewportWidth: 1280,
    viewportHeight: 720,
    defaultCommandTimeout: 10000,
    requestTimeout: 15000,
    responseTimeout: 30000,
    retries: {
      runMode: 2,
      openMode: 0,
    },
    video: false,
    screenshotOnRunFailure: true,
    experimentalRunAllSpecs: true,
    setupNodeEvents(on, config) {
      // Register plugins here
      return config;
    },
  },
  component: {
    devServer: {
      framework: 'react',
      bundler: 'vite',
    },
    specPattern: 'src/**/*.cy.{ts,tsx}',
  },
});

Custom Commands

Defining Custom Commands

// cypress/support/commands.ts
declare global {
  namespace Cypress {
    interface Chainable {
      login(email: string, password: string): Chainable<void>;
      loginByApi(email: string, password: string): Chainable<void>;
      getByTestId(testId: string): Chainable<JQuery<HTMLElement>>;
      shouldBeVisible(text: string): Chainable<void>;
    }
  }
}

Cypress.Commands.add('login', (email: string, password: string) => {
  cy.visit('/login');
  cy.get('[data-testid="email-input"]').type(email);
  cy.get('[data-testid="password-input"]').type(password);
  cy.get('[data-testid="login-button"]').click();
  cy.url().should('include', '/dashboard');
});

Cypress.Commands.add('loginByApi', (email: string, password: string) => {
  cy.request({
    method: 'POST',
    url: '/api/auth/login',
    body: { email, password },
  }).then((response) => {
    window.localStorage.setItem('authToken', response.body.token);
  });
});

Cypress.Commands.add('getByTestId', (testId: string) => {
  return cy.get(`[data-testid="${testId}"]`);
});

Using `cy.session()` for Auth

Cypress.Commands.add('login', (email: string, password: string) => {
  cy.session(
    [email, password],
    () => {
      cy.visit('/login');
      cy.get('#email').type(email);
      cy.get('#password').type(password);
      cy.get('button[type="submit"]').click();
      cy.url().should('include', '/dashboard');
    },
    {
      validate() {
        cy.request('/api/auth/me').its('status').should('eq', 200);
      },
    }
  );
});

Page Object Pattern

// cypress/pages/login.page.ts
export class LoginPage {
  get emailInput() {
    return cy.get('[data-testid="email-input"]');
  }

  get passwordInput() {
    return cy.get('[data-testid="password-input"]');
  }

  get submitButton() {
    return cy.get('[data-testid="login-button"]');
  }

  get errorMessage() {
    return cy.get('[data-testid="error-message"]');
  }

  visit() {
    cy.visit('/login');
    return this;
  }

  fillEmail(email: string) {
    this.emailInput.clear().type(email);
    return this;
  }

  fillPassword(password: string) {
    this.passwordInput.clear().type(password);
    return this;
  }

  submit() {
    this.submitButton.click();
    return this;
  }

  login(email: string, password: string) {
    this.fillEmail(email);
    this.fillPassword(password);
    this.submit();
    return this;
  }

  assertError(message: string) {
    this.errorMessage.should('be.visible').and('contain.text', message);
    return this;
  }
}

export const loginPage = new LoginPage();

Writing Tests

Basic Test Structure

import { loginPage } from '../pages/login.page';

describe('Login', () => {
  beforeEach(() => {
    loginPage.visit();
  });

  it('should login successfully with valid credentials', () => {
    loginPage.login('user@example.com', 'SecurePass123!');
    cy.url().should('include', '/dashboard');
    cy.contains('Welcome back').should('be.visible');
  });

  it('should show error for invalid credentials', () => {
    loginPage.login('user@example.com', 'wrongpassword');
    loginPage.assertError('Invalid email or password');
  });

  it('should disable submit button when form is empty', () => {
    loginPage.submitButton.should('be.disabled');
  });
});

Network Intercept Patterns

describe('Product listing', () => {
  it('should display products from API', () => {
    cy.intercept('GET', '/api/products', {
      fixture: 'products.json',
    }).as('getProducts');

    cy.visit('/products');
    cy.wait('@getProducts');

    cy.get('[data-testid="product-card"]').should('have.length', 3);
  });

  it('should show error state on API failure', () => {
    cy.intercept('GET', '/api/products', {
      statusCode: 500,
      body: { error: 'In
Read more
@pramoddutta
Ships withqaskills

QA Skills Directory QA Skills is a curated directory of testing-specific skills for AI coding agents (Claude Code, Cursor, Copilot, etc.).

Stars on GitHub

Momentum

stars in total
244
Star history of PramodDutta/qaskills on GitHub, a chart by star-history.com

Other skills on qaskills.

add-seed-skills

add-seed-skills

Use when adding or editing QA skills in seed-skills/ or getting them onto the live qaskills.sh catalog, e.g. "add N new skills",…

publish-seo-batch

publish-seo-batch

Use when publishing SEO blog articles to qaskills.sh, e.g. "publish today's articles", "daily SEO batch", "write 10 articles from…

ship-prod

ship-prod

Use when deploying qaskills.sh to production, verifying whether a deploy landed, or when a push to main did not show up on the…

api-testing-rest

api-testing-rest

Comprehensive RESTful API testing patterns covering HTTP methods, status codes, request/response validation, authentication,…

claude-code-qa

claude-code-qa

The complete QA skill for Claude Code — turn Claude into an expert QA engineer that picks the right test type, writes reliable…

e2e-testing-claude-code

e2e-testing-claude-cod…

Make Claude Code write and maintain end-to-end tests like a senior SDET — Playwright and Cypress flows with stable locators, the…

More skills from other plugins.

api-review

api-review

Produce the "Playwright 1.xx API Review" artifact for a range of commits - the public API additions and the breaking or behavior…

@microsoft@microsoftInstall Skill
add-e2e-selectors

add-e2e-selectors

Add reliable @grafana/e2e-selectors to interactive elements and key containers in the Grafana frontend. Use when adding e2e…

grafana1d78k
@grafana@grafanaInstall Skill
promptfoo-evals

promptfoo-evals

Write, refine, run, and QA promptfoo evaluation suites: promptfooconfig.yaml, prompts, providers, vars, tests, assertions,…

@promptfoo@promptfooInstall Skill
deepeval

deepeval

DeepEval evaluation workflow for AI agents and LLM applications. TRIGGER when the user wants to evaluate or improve an AI agent,…

@confident-ai@confident-aiInstall Skill

Questions about cypress-e2e.

Which coding agents can use cypress-e2e?
cypress-e2e installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.