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
19813 skills
Install
$ npx -y skills add PramodDutta/qaskills --skill cypress-e2e --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/cypress-e2e

Context preview

The summary Claude sees to decide when to auto-load this skill.

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

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
Ships withqaskills

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

Get the whole plugin

Other skills on qaskills.