UNPKG

vineguard-mcp-server-standalone

Version:

VineGuard MCP Server v2.1 - Intelligent QA Workflow System with advanced test generation for Jest/RTL, Cypress, and Playwright. Features smart project analysis, progressive testing strategies, and comprehensive quality patterns for React/Vue/Angular proje

550 lines (461 loc) 17.3 kB
/** * Cypress E2E test generator * Supports user flows, API testing, and visual testing patterns */ export class CypressGenerator { /** * Generate Cypress test based on test type */ static generateTest(options) { const { testType } = options; switch (testType) { case 'user-flow': return this.generateUserFlowTest(options); case 'api': return this.generateApiTest(options); case 'smoke': return this.generateSmokeTest(options); case 'visual': return this.generateVisualTest(options); case 'accessibility': return this.generateAccessibilityTest(options); default: return this.generateBasicTest(options); } } /** * Generate comprehensive user flow test */ static generateUserFlowTest(options) { const { featureName, hasAuth = false, hasApi = false, baseUrl = 'http://localhost:3000' } = options; return `describe('${featureName} - User Flow', () => { beforeEach(() => { // Setup before each test cy.visit('${baseUrl}'); ${hasAuth ? ` // Setup authentication cy.login('test@example.com', 'password123');` : ''} ${hasApi ? ` // Setup API interceptors cy.intercept('GET', '/api/users', { fixture: 'users.json' }).as('getUsers'); cy.intercept('POST', '/api/users', { statusCode: 201, body: { success: true } }).as('createUser');` : ''} // Set viewport for consistent testing cy.viewport(1280, 720); }); afterEach(() => { // Cleanup after each test ${hasAuth ? `cy.logout();` : ''} // Clear any stored data cy.clearAllLocalStorage(); cy.clearAllSessionStorage(); }); describe('Happy Path', () => { it('should complete the main user journey successfully', () => { // Step 1: Navigate to feature cy.get('[data-testid="nav-${featureName.toLowerCase()}"]').click(); cy.url().should('include', '/${featureName.toLowerCase()}'); // Step 2: Verify page loads correctly cy.get('[data-testid="${featureName.toLowerCase()}-page"]').should('be.visible'); cy.get('h1').should('contain.text', '${featureName}'); ${hasApi ? ` // Wait for API calls to complete cy.wait('@getUsers');` : ''} // Step 3: Interact with main feature cy.get('[data-testid="primary-action-button"]').click(); // Step 4: Fill out form (if applicable) cy.get('[data-testid="name-input"]').type('Test User'); cy.get('[data-testid="email-input"]').type('test@example.com'); // Step 5: Submit and verify success cy.get('[data-testid="submit-button"]').click(); ${hasApi ? ` cy.wait('@createUser');` : ''} // Step 6: Verify success state cy.get('[data-testid="success-message"]') .should('be.visible') .and('contain.text', 'Success'); // Step 7: Verify redirect or state change cy.url().should('include', '/success'); }); it('should handle navigation between pages', () => { // Test multi-page flows cy.get('[data-testid="step-1"]').click(); cy.url().should('include', '/step-1'); cy.get('[data-testid="next-button"]').click(); cy.url().should('include', '/step-2'); cy.get('[data-testid="back-button"]').click(); cy.url().should('include', '/step-1'); }); }); describe('Error Handling', () => { it('should handle form validation errors', () => { cy.get('[data-testid="nav-${featureName.toLowerCase()}"]').click(); // Submit form without required fields cy.get('[data-testid="submit-button"]').click(); // Verify validation errors cy.get('[data-testid="name-error"]') .should('be.visible') .and('contain.text', 'Name is required'); cy.get('[data-testid="email-error"]') .should('be.visible') .and('contain.text', 'Email is required'); }); ${hasApi ? ` it('should handle API errors gracefully', () => { // Mock API error cy.intercept('POST', '/api/users', { statusCode: 500, body: { error: 'Server error' } }).as('serverError'); cy.get('[data-testid="nav-${featureName.toLowerCase()}"]').click(); cy.get('[data-testid="name-input"]').type('Test User'); cy.get('[data-testid="email-input"]').type('test@example.com'); cy.get('[data-testid="submit-button"]').click(); cy.wait('@serverError'); // Verify error handling cy.get('[data-testid="error-message"]') .should('be.visible') .and('contain.text', 'Something went wrong'); });` : ''} it('should handle network failures', () => { // Simulate offline behavior cy.intercept('**', { forceNetworkError: true }); cy.get('[data-testid="nav-${featureName.toLowerCase()}"]').click(); cy.get('[data-testid="submit-button"]').click(); cy.get('[data-testid="network-error"]') .should('be.visible') .and('contain.text', 'Network error'); }); }); describe('Edge Cases', () => { it('should handle empty states', () => { // Mock empty data response cy.intercept('GET', '/api/users', { body: [] }).as('emptyUsers'); cy.get('[data-testid="nav-${featureName.toLowerCase()}"]').click(); cy.wait('@emptyUsers'); cy.get('[data-testid="empty-state"]') .should('be.visible') .and('contain.text', 'No items found'); }); it('should handle long loading times', () => { // Mock slow API response cy.intercept('GET', '/api/users', { delay: 3000, fixture: 'users.json' }).as('slowUsers'); cy.get('[data-testid="nav-${featureName.toLowerCase()}"]').click(); // Verify loading state cy.get('[data-testid="loading-spinner"]').should('be.visible'); cy.wait('@slowUsers'); // Verify loading state disappears cy.get('[data-testid="loading-spinner"]').should('not.exist'); }); it('should handle browser back/forward navigation', () => { cy.get('[data-testid="nav-${featureName.toLowerCase()}"]').click(); cy.get('[data-testid="step-1"]').click(); cy.go('back'); cy.url().should('include', '/${featureName.toLowerCase()}'); cy.go('forward'); cy.url().should('include', '/step-1'); }); }); describe('Mobile Responsive', () => { it('should work on mobile viewport', () => { cy.viewport('iphone-x'); cy.get('[data-testid="nav-${featureName.toLowerCase()}"]').click(); // Verify mobile-specific elements cy.get('[data-testid="mobile-menu"]').should('be.visible'); cy.get('[data-testid="desktop-menu"]').should('not.be.visible'); // Test mobile interactions cy.get('[data-testid="mobile-menu-toggle"]').click(); cy.get('[data-testid="mobile-nav"]').should('be.visible'); }); it('should work on tablet viewport', () => { cy.viewport('ipad-2'); cy.get('[data-testid="nav-${featureName.toLowerCase()}"]').click(); // Verify tablet-specific layout cy.get('[data-testid="tablet-layout"]').should('be.visible'); }); }); });`; } /** * Generate API test */ static generateApiTest(options) { const { featureName, hasAuth = false } = options; return `describe('${featureName} - API Tests', () => { let authToken: string; before(() => { ${hasAuth ? ` // Get authentication token cy.request({ method: 'POST', url: '/api/auth/login', body: { email: 'test@example.com', password: 'password123' } }).then((response) => { expect(response.status).to.eq(200); authToken = response.body.token; });` : ''} }); beforeEach(() => { // Set base URL for API requests cy.intercept('**').as('apiRequest'); }); describe('CRUD Operations', () => { it('should create a new record via API', () => { const newRecord = { name: 'Test Record', description: 'Test Description', category: 'test' }; cy.request({ method: 'POST', url: '/api/${featureName.toLowerCase()}', body: newRecord, ${hasAuth ? `headers: { Authorization: \`Bearer \${authToken}\` },` : ''} }).then((response) => { expect(response.status).to.eq(201); expect(response.body).to.have.property('id'); expect(response.body.name).to.eq(newRecord.name); }); }); it('should retrieve records via API', () => { cy.request({ method: 'GET', url: '/api/${featureName.toLowerCase()}', ${hasAuth ? `headers: { Authorization: \`Bearer \${authToken}\` },` : ''} }).then((response) => { expect(response.status).to.eq(200); expect(response.body).to.be.an('array'); expect(response.body.length).to.be.greaterThan(0); }); }); it('should update a record via API', () => { const recordId = 1; const updatedData = { name: 'Updated Record', description: 'Updated Description' }; cy.request({ method: 'PUT', url: \`/api/${featureName.toLowerCase()}/\${recordId}\`, body: updatedData, ${hasAuth ? `headers: { Authorization: \`Bearer \${authToken}\` },` : ''} }).then((response) => { expect(response.status).to.eq(200); expect(response.body.name).to.eq(updatedData.name); }); }); it('should delete a record via API', () => { const recordId = 1; cy.request({ method: 'DELETE', url: \`/api/${featureName.toLowerCase()}/\${recordId}\`, ${hasAuth ? `headers: { Authorization: \`Bearer \${authToken}\` },` : ''} }).then((response) => { expect(response.status).to.eq(204); }); }); }); describe('Error Handling', () => { it('should handle 404 errors', () => { cy.request({ method: 'GET', url: '/api/${featureName.toLowerCase()}/999999', failOnStatusCode: false, ${hasAuth ? `headers: { Authorization: \`Bearer \${authToken}\` },` : ''} }).then((response) => { expect(response.status).to.eq(404); expect(response.body).to.have.property('error'); }); }); it('should handle validation errors', () => { cy.request({ method: 'POST', url: '/api/${featureName.toLowerCase()}', body: {}, // Empty body to trigger validation failOnStatusCode: false, ${hasAuth ? `headers: { Authorization: \`Bearer \${authToken}\` },` : ''} }).then((response) => { expect(response.status).to.eq(400); expect(response.body).to.have.property('errors'); }); }); ${hasAuth ? ` it('should handle unauthorized requests', () => { cy.request({ method: 'GET', url: '/api/${featureName.toLowerCase()}', failOnStatusCode: false, // No authorization header }).then((response) => { expect(response.status).to.eq(401); }); });` : ''} }); describe('Performance', () => { it('should respond within acceptable time limits', () => { const startTime = Date.now(); cy.request({ method: 'GET', url: '/api/${featureName.toLowerCase()}', ${hasAuth ? `headers: { Authorization: \`Bearer \${authToken}\` },` : ''} }).then((response) => { const endTime = Date.now(); const responseTime = endTime - startTime; expect(response.status).to.eq(200); expect(responseTime).to.be.lessThan(2000); // 2 second threshold }); }); }); });`; } /** * Generate smoke test */ static generateSmokeTest(options) { const { featureName, baseUrl = 'http://localhost:3000' } = options; return `describe('${featureName} - Smoke Tests', () => { it('should load the application successfully', () => { cy.visit('${baseUrl}'); // Verify basic page elements load cy.get('body').should('be.visible'); cy.title().should('not.be.empty'); // Check for critical navigation elements cy.get('[data-testid="main-nav"]').should('be.visible'); cy.get('[data-testid="logo"]').should('be.visible'); }); it('should navigate to ${featureName} page', () => { cy.visit('${baseUrl}'); cy.get('[data-testid="nav-${featureName.toLowerCase()}"]').click(); cy.url().should('include', '/${featureName.toLowerCase()}'); // Verify page loaded cy.get('h1').should('be.visible'); }); it('should not have JavaScript errors', () => { cy.visit('${baseUrl}'); cy.window().then((win) => { expect(win.console.error).to.not.have.been.called; }); }); it('should have working links', () => { cy.visit('${baseUrl}'); // Test critical links don't return 404 cy.get('a[href]').each(($link) => { const href = $link.attr('href'); if (href && !href.startsWith('http') && !href.startsWith('mailto:')) { cy.request(href).its('status').should('eq', 200); } }); }); });`; } /** * Generate visual regression test */ static generateVisualTest(options) { const { featureName, viewport = { width: 1280, height: 720 } } = options; return `describe('${featureName} - Visual Tests', () => { beforeEach(() => { cy.viewport(${viewport.width}, ${viewport.height}); }); it('should match visual baseline for desktop', () => { cy.visit('/${featureName.toLowerCase()}'); // Wait for page to fully load cy.get('[data-testid="${featureName.toLowerCase()}-page"]').should('be.visible'); // Take visual snapshot cy.matchImageSnapshot('${featureName.toLowerCase()}-desktop'); }); it('should match visual baseline for mobile', () => { cy.viewport('iphone-x'); cy.visit('/${featureName.toLowerCase()}'); cy.get('[data-testid="${featureName.toLowerCase()}-page"]').should('be.visible'); cy.matchImageSnapshot('${featureName.toLowerCase()}-mobile'); }); it('should match visual baseline for different states', () => { cy.visit('/${featureName.toLowerCase()}'); // Test loading state cy.get('[data-testid="loading-trigger"]').click(); cy.get('[data-testid="loading-spinner"]').should('be.visible'); cy.matchImageSnapshot('${featureName.toLowerCase()}-loading'); // Test error state cy.get('[data-testid="error-trigger"]').click(); cy.get('[data-testid="error-message"]').should('be.visible'); cy.matchImageSnapshot('${featureName.toLowerCase()}-error'); // Test empty state cy.get('[data-testid="empty-trigger"]').click(); cy.get('[data-testid="empty-state"]').should('be.visible'); cy.matchImageSnapshot('${featureName.toLowerCase()}-empty'); }); });`; } /** * Generate accessibility test */ static generateAccessibilityTest(options) { const { featureName } = options; return `describe('${featureName} - Accessibility Tests', () => { beforeEach(() => { cy.visit('/${featureName.toLowerCase()}'); cy.injectAxe(); // Inject axe-core for accessibility testing }); it('should not have accessibility violations', () => { cy.checkA11y(); }); it('should be navigable with keyboard only', () => { // Test tab navigation cy.get('body').tab(); cy.focused().should('be.visible'); // Navigate through all interactive elements cy.get('[data-testid="interactive-element"]').each(($el) => { cy.wrap($el).focus().should('have.focus'); }); }); it('should work with screen reader', () => { // Test ARIA labels and descriptions cy.get('[data-testid="main-content"]') .should('have.attr', 'aria-label') .and('not.be.empty'); // Test heading hierarchy cy.get('h1').should('exist'); cy.get('h2').should('exist'); // Test form labels cy.get('input').each(($input) => { cy.wrap($input).should('have.attr', 'aria-label').or('have.attr', 'aria-labelledby'); }); }); it('should have sufficient color contrast', () => { cy.checkA11y(null, { rules: { 'color-contrast': { enabled: true } } }); }); it('should support high contrast mode', () => { // Simulate high contrast mode cy.get('body').invoke('addClass', 'high-contrast'); // Verify elements are still visible and usable cy.get('[data-testid="main-nav"]').should('be.visible'); cy.get('button').should('be.visible'); cy.checkA11y(); }); });`; } /** * Generate basic test (fallback) */ static generateBasicTest(options) { const { featureName, baseUrl = 'http://localhost:3000' } = options; return `describe('${featureName}', () => { beforeEach(() => { cy.visit('${baseUrl}'); }); it('should load the page successfully', () => { cy.get('[data-testid="${featureName.toLowerCase()}-page"]').should('be.visible'); cy.title().should('contain', '${featureName}'); }); it('should have working interactions', () => { cy.get('[data-testid="primary-button"]').click(); cy.get('[data-testid="result"]').should('be.visible'); }); });`; } } //# sourceMappingURL=cypress-generator.js.map