cypress/README.md
This directory contains end-to-end tests for Compiler Explorer using Cypress.
First, start a local Compiler Explorer instance with a clean configuration:
npm run dev -- --language c++ --no-local
The --no-local flag is important as it ensures your setup is clean of any local properties.
In another terminal:
# Run all Cypress tests
npm run cypress
# Run specific test file
npm run cypress -- run --spec "cypress/e2e/claude-explain.cy.ts"
# Open Cypress interactive UI (recommended for development)
npm run cypress:open
When using the interactive UI, choose "E2E Testing" and select your browser.
:visible SelectorsGoldenLayout creates template elements that exist in the DOM but aren't visible. Always use :visible to avoid selecting template elements:
// ❌ Bad - might select template elements
cy.get('.explain-content').should('contain', 'text');
// ✅ Good - only selects visible elements
cy.get('.explain-content:visible').should('contain', 'text');
afterEachCypress intercepts accumulate across tests causing O(n²) performance degradation. Always clear them:
import {clearAllIntercepts} from '../support/utils';
afterEach(() => {
// Use the utility function to clear intercepts
clearAllIntercepts();
// Or manually clear them:
cy.state('routes', []);
cy.state('aliases', {});
// ... other cleanup
});
Always set up API mocks BEFORE any action that might trigger requests:
// ❌ Bad - pane constructor might make requests before mocks are ready
openClaudeExplainPane();
mockClaudeExplainAPI();
// ✅ Good - mocks ready before pane opens
mockClaudeExplainAPI();
openClaudeExplainPane();
Don't just wait for API calls - wait for the actual DOM changes:
// ❌ Bad - API completes but DOM might not be updated yet
cy.wait('@getOptions');
cy.get('.dropdown').select('value');
// ✅ Good - wait for specific DOM state
cy.wait('@getOptions');
cy.get('.dropdown option[value="loading"]').should('not.exist');
cy.get('.dropdown').select('value');
Always use clearly fake test data to:
// Use values like: test_first, test_second, focus_a, focus_b
// Not: beginner, expert, assembly, optimization
Extract common test patterns to helpers, but keep them in the test file if they're specific to one feature:
// In test file for feature-specific helpers
function openClaudeExplainPaneWithOptions() {
mockClaudeExplainAPI();
openClaudeExplainPane();
cy.wait('@getOptions');
waitForDropdownsToLoad();
}
// In utils.ts for general helpers
export function setMonacoEditorContent(content: string) { ... }
Be aware that some state might be static (shared between instances) while other state is per-instance:
Always block production API calls in tests to catch configuration issues:
cy.intercept('https://api.compiler-explorer.com/**', {
statusCode: 500,
body: {error: 'BLOCKED PRODUCTION API'}
}).as('blockedProduction');
afterEach using clearAllIntercepts() from utils or manually with cy.state('routes', []):visible pseudo-selectorsupport/utils.tsdescribe blockscy.log() to debug what values you're actually getting.then() to inspect element state at specific points