Claude-skill-registry cypress
Writes E2E and component tests with Cypress including selectors, commands, fixtures, and API testing. Use when testing web applications end-to-end, testing user flows, or writing integration tests.
install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/cypress" ~/.claude/skills/majiayu000-claude-skill-registry-cypress-5d91b6 && rm -rf "$T"
manifest:
skills/data/cypress/SKILL.mdsource content
Cypress
Fast, reliable testing for anything that runs in a browser.
Quick Start
Install:
npm install cypress --save-dev
Open Cypress:
npx cypress open
Run headless:
npx cypress run
Project Structure
cypress/ e2e/ # E2E test files home.cy.ts auth.cy.ts fixtures/ # Test data users.json support/ commands.ts # Custom commands e2e.ts # E2E support file component.ts # Component support file downloads/ # Downloaded files cypress.config.ts # Configuration
Configuration
// cypress.config.ts import { defineConfig } from 'cypress'; export default defineConfig({ e2e: { baseUrl: 'http://localhost:3000', viewportWidth: 1280, viewportHeight: 720, defaultCommandTimeout: 10000, video: false, screenshotOnRunFailure: true, setupNodeEvents(on, config) { // Node event listeners }, }, component: { devServer: { framework: 'react', bundler: 'vite', }, }, env: { apiUrl: 'http://localhost:3001', }, });
Basic Test
// cypress/e2e/home.cy.ts describe('Home Page', () => { beforeEach(() => { cy.visit('/'); }); it('displays the welcome message', () => { cy.contains('h1', 'Welcome').should('be.visible'); }); it('navigates to about page', () => { cy.get('a[href="/about"]').click(); cy.url().should('include', '/about'); cy.contains('About Us').should('be.visible'); }); });
Selectors
Best Practices
// Prefer data-* attributes cy.get('[data-testid="submit-button"]'); cy.get('[data-cy="user-name"]'); // By role (accessibility) cy.get('button').contains('Submit'); cy.get('input[type="email"]'); // By text content cy.contains('Sign In'); cy.contains('button', 'Submit'); // Avoid brittle selectors // Bad: cy.get('.btn-primary-lg-submit') // Bad: cy.get('#form > div:nth-child(3) > button')
Chaining
cy.get('[data-cy="user-form"]') .find('input[name="email"]') .type('test@example.com'); cy.get('[data-cy="user-list"]') .children() .first() .click();
Commands
Navigation
cy.visit('/'); cy.visit('/users/123'); cy.go('back'); cy.go('forward'); cy.reload();
Interactions
// Click cy.get('button').click(); cy.get('button').dblclick(); cy.get('button').rightclick(); // Type cy.get('input').type('Hello World'); cy.get('input').type('test@email.com{enter}'); cy.get('input').clear().type('New value'); // Select cy.get('select').select('Option 1'); cy.get('select').select(['opt1', 'opt2']); // Checkbox/Radio cy.get('input[type="checkbox"]').check(); cy.get('input[type="checkbox"]').uncheck(); cy.get('input[type="radio"]').check('value'); // File upload cy.get('input[type="file"]').selectFile('cypress/fixtures/image.png'); // Scroll cy.scrollTo('bottom'); cy.get('.container').scrollTo(0, 500); // Focus/Blur cy.get('input').focus(); cy.get('input').blur();
Assertions
// Visibility cy.get('button').should('be.visible'); cy.get('.modal').should('not.exist'); cy.get('.loading').should('not.be.visible'); // Content cy.get('h1').should('contain', 'Welcome'); cy.get('h1').should('have.text', 'Welcome Home'); cy.get('p').should('include.text', 'partial'); // Attributes cy.get('input').should('have.value', 'test'); cy.get('a').should('have.attr', 'href', '/about'); cy.get('button').should('be.disabled'); cy.get('input').should('be.enabled'); // CSS cy.get('div').should('have.class', 'active'); cy.get('div').should('have.css', 'display', 'flex'); // Length cy.get('li').should('have.length', 5); cy.get('li').should('have.length.greaterThan', 3); // Chained cy.get('input') .should('be.visible') .and('have.value', '') .and('be.enabled');
Fixtures
Load Fixture Data
// cypress/fixtures/users.json { "users": [ { "id": 1, "name": "John", "email": "john@example.com" }, { "id": 2, "name": "Jane", "email": "jane@example.com" } ] }
// In test cy.fixture('users').then((data) => { const user = data.users[0]; cy.get('[data-cy="email"]').type(user.email); }); // Or with alias beforeEach(() => { cy.fixture('users').as('usersData'); }); it('uses fixture data', function() { cy.get('[data-cy="email"]').type(this.usersData.users[0].email); });
API Testing
cy.request
describe('API Tests', () => { it('fetches users', () => { cy.request('GET', '/api/users').then((response) => { expect(response.status).to.eq(200); expect(response.body).to.have.length.greaterThan(0); }); }); it('creates a user', () => { cy.request({ method: 'POST', url: '/api/users', body: { name: 'John Doe', email: 'john@example.com', }, }).then((response) => { expect(response.status).to.eq(201); expect(response.body).to.have.property('id'); }); }); it('handles auth', () => { cy.request({ method: 'POST', url: '/api/login', body: { email: 'test@example.com', password: 'password' }, }).then((response) => { expect(response.body).to.have.property('token'); // Use token in subsequent requests cy.request({ method: 'GET', url: '/api/profile', headers: { Authorization: `Bearer ${response.body.token}`, }, }); }); }); });
Intercept Network Requests
describe('Mocking API', () => { it('mocks API response', () => { cy.intercept('GET', '/api/users', { statusCode: 200, body: [ { id: 1, name: 'Mocked User' }, ], }).as('getUsers'); cy.visit('/users'); cy.wait('@getUsers'); cy.contains('Mocked User').should('be.visible'); }); it('mocks with fixture', () => { cy.intercept('GET', '/api/users', { fixture: 'users.json' }).as('getUsers'); cy.visit('/users'); cy.wait('@getUsers'); }); it('spies on requests', () => { cy.intercept('POST', '/api/users').as('createUser'); cy.get('[data-cy="create-user-form"]').within(() => { cy.get('input[name="name"]').type('John'); cy.get('button[type="submit"]').click(); }); cy.wait('@createUser').its('request.body').should('deep.equal', { name: 'John', }); }); it('delays response', () => { cy.intercept('GET', '/api/data', { delay: 2000, body: { data: 'slow response' }, }); cy.visit('/data'); cy.get('.loading').should('be.visible'); cy.get('.data').should('be.visible'); }); });
Custom Commands
// cypress/support/commands.ts declare global { namespace Cypress { interface Chainable { login(email: string, password: string): Chainable<void>; getByCy(selector: string): Chainable<JQuery<HTMLElement>>; } } } Cypress.Commands.add('login', (email, password) => { cy.session([email, password], () => { cy.visit('/login'); cy.get('[data-cy="email"]').type(email); cy.get('[data-cy="password"]').type(password); cy.get('[data-cy="submit"]').click(); cy.url().should('include', '/dashboard'); }); }); Cypress.Commands.add('getByCy', (selector) => { return cy.get(`[data-cy="${selector}"]`); }); export {};
// Usage describe('Dashboard', () => { beforeEach(() => { cy.login('test@example.com', 'password'); }); it('shows dashboard', () => { cy.visit('/dashboard'); cy.getByCy('welcome-message').should('be.visible'); }); });
Component Testing
// cypress/component/Button.cy.tsx import Button from '../../src/components/Button'; describe('Button Component', () => { it('renders with text', () => { cy.mount(<Button>Click me</Button>); cy.contains('Click me').should('be.visible'); }); it('handles click', () => { const onClick = cy.stub().as('onClick'); cy.mount(<Button onClick={onClick}>Click me</Button>); cy.get('button').click(); cy.get('@onClick').should('have.been.calledOnce'); }); it('shows disabled state', () => { cy.mount(<Button disabled>Disabled</Button>); cy.get('button').should('be.disabled'); }); });
Waiting
// Wait for element cy.get('.loading').should('not.exist'); cy.get('.data').should('be.visible'); // Wait for network cy.intercept('GET', '/api/data').as('getData'); cy.visit('/'); cy.wait('@getData'); // Wait for multiple cy.wait(['@getUsers', '@getPosts']); // Explicit wait (avoid when possible) cy.wait(1000);
Best Practices
- Use data- attributes* - Stable selectors
- Don't use cy.wait(ms) - Use assertions instead
- Reset state between tests - Use beforeEach
- Use cy.session - Cache authentication
- Use intercept for mocking - Control network
Common Mistakes
| Mistake | Fix |
|---|---|
| Using arbitrary waits | Use assertions that retry |
| Brittle CSS selectors | Use data-testid attributes |
| Not cleaning up state | Use beforeEach/afterEach |
| Testing implementation | Test user behavior |
| Flaky tests | Use proper waiting strategies |
Reference Files
- references/commands.md - All commands
- references/assertions.md - Assertion types
- references/ci.md - CI/CD integration