Simplify and standardize testing structure
This commit is contained in:
@@ -0,0 +1,208 @@
|
||||
## Testing Guide
|
||||
|
||||
### Philosophy
|
||||
|
||||
- **Test behaviour, not implementation**: Focus on what the user can see and do, not internal details.
|
||||
- **Single source of truth per component**: Each component should have **one consolidated test file**.
|
||||
- **Accessibility is mandatory**: Basic a11y checks run as part of every component suite.
|
||||
- **E2E is sparse**: Only cover critical user journeys that span pages or systems.
|
||||
|
||||
### Test Structure
|
||||
|
||||
The test directory structure is organized as follows:
|
||||
|
||||
```text
|
||||
tests/
|
||||
components/ # All component-focused tests (Vitest + RTL)
|
||||
Button.test.tsx
|
||||
Input.test.tsx
|
||||
Checkbox.test.tsx
|
||||
Select.test.tsx
|
||||
Switch.test.tsx
|
||||
pages/ # Page-level tests (home, blog, etc.)
|
||||
home.test.jsx
|
||||
blog.test.jsx
|
||||
e2e/ # True end‑to‑end flows + visual regression (Playwright)
|
||||
homepage.spec.ts
|
||||
user-journeys.spec.ts
|
||||
visual-regression.spec.ts
|
||||
performance.spec.ts
|
||||
utils/ # Shared test utilities
|
||||
componentTestSuite.tsx
|
||||
msw/ # MSW server setup for mocking
|
||||
server.ts
|
||||
accessibility/
|
||||
e2e/ # E2E accessibility checks (WCAG compliance)
|
||||
wcag-compliance.spec.ts
|
||||
```
|
||||
|
||||
**Component tests** (`tests/components/`) use the standard `componentTestSuite` utility to ensure consistent baseline coverage for all UI components. **Page tests** (`tests/pages/`) cover page-level rendering and flows. **E2E tests** (`tests/e2e/`) focus on critical user journeys, visual regression, and performance. **Accessibility E2E** (`tests/accessibility/e2e/`) provides high-level WCAG compliance checks.
|
||||
|
||||
### Standard Component Test Suite
|
||||
|
||||
Use the shared suite in `tests/utils/componentTestSuite.tsx` to get a consistent baseline:
|
||||
|
||||
```ts
|
||||
import Component from "../../app/components/Component";
|
||||
import {
|
||||
componentTestSuite,
|
||||
type ComponentTestSuiteConfig,
|
||||
} from "../utils/componentTestSuite";
|
||||
|
||||
type Props = React.ComponentProps<typeof Component>;
|
||||
|
||||
const config: ComponentTestSuiteConfig<Props> = {
|
||||
component: Component,
|
||||
name: "Component",
|
||||
props: {
|
||||
/* default props */
|
||||
} as Props,
|
||||
requiredProps: ["label"],
|
||||
optionalProps: {
|
||||
disabled: true,
|
||||
},
|
||||
queries: {
|
||||
getPrimaryElement: (s) => s.getByRole("button"),
|
||||
},
|
||||
variants: {
|
||||
disabled: {
|
||||
props: { disabled: true },
|
||||
assert: (el) => {
|
||||
expect(el).toBeDisabled();
|
||||
},
|
||||
},
|
||||
error: {
|
||||
props: { error: true } as Partial<Props>,
|
||||
assert: (el) => {
|
||||
expect(el).toHaveClass("border-[var(--color-border-default-utility-negative)]");
|
||||
},
|
||||
},
|
||||
},
|
||||
testCases: {
|
||||
renders: true,
|
||||
accessibility: true,
|
||||
keyboardNavigation: true,
|
||||
disabledState: true,
|
||||
errorState: true,
|
||||
},
|
||||
};
|
||||
|
||||
componentTestSuite<Props>(config);
|
||||
```
|
||||
|
||||
#### What the Standard Suite Covers
|
||||
|
||||
- **Rendering**
|
||||
- Component renders without throwing using the provided `props`.
|
||||
- Required props are present and do not break rendering.
|
||||
- Optional props can be applied without breaking.
|
||||
|
||||
- **Accessibility**
|
||||
- Runs `axe` against the rendered output.
|
||||
- Fails on common WCAG 2.1 issues (roles, labels, contrast, etc.).
|
||||
|
||||
- **Keyboard Navigation**
|
||||
- Ensures the primary element can receive focus.
|
||||
- Smoke‑tests basic keyboard activation (`Enter`, `Space`) without runtime errors.
|
||||
|
||||
- **Disabled State**
|
||||
- Uses `variants.disabled` to verify disabled behaviour (e.g., `aria-disabled`, `disabled` attribute, tab index).
|
||||
|
||||
- **Error State**
|
||||
- Uses `variants.error` to verify error styling/attributes when applicable.
|
||||
|
||||
### When to Add Custom Tests
|
||||
|
||||
Use the standard suite for **baseline coverage**, then add custom `describe` blocks in the same file when:
|
||||
|
||||
- The component has **important variants** (different sizes, modes, label variants).
|
||||
- There is **non‑trivial interaction** (menus, dropdowns, complex keyboard behaviour).
|
||||
- You need to exercise **stateful flows** (forms, validation, error messages).
|
||||
|
||||
Example (inside the same `*.test.tsx` file):
|
||||
|
||||
```ts
|
||||
describe("Input – behaviour specifics", () => {
|
||||
it("calls onChange when user types", async () => {
|
||||
// ...
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### Test Commands
|
||||
|
||||
- **All component tests** (Vitest + RTL):
|
||||
|
||||
```bash
|
||||
npm test
|
||||
```
|
||||
|
||||
- **Component-only tests** (faster inner loop, focused on `tests/components/`):
|
||||
|
||||
```bash
|
||||
npm run test:component
|
||||
# filter by name:
|
||||
npm run test:component -- --run tests/components/Button.test.tsx
|
||||
```
|
||||
|
||||
- **E2E tests only** (Playwright):
|
||||
|
||||
```bash
|
||||
npm run test:e2e
|
||||
# or, equivalently:
|
||||
npm run e2e
|
||||
```
|
||||
|
||||
### What to Test vs. What Not to Test
|
||||
|
||||
- **Do test**
|
||||
- Public behaviour: visible text, roles, labels, ARIA, keyboard paths.
|
||||
- State transitions that users rely on (error -> success, disabled -> enabled).
|
||||
- Critical component interactions (clicks, form submissions, dropdown selection).
|
||||
- Accessibility invariants (no axe violations, basic keyboard support).
|
||||
|
||||
- **Avoid testing**
|
||||
- Pure styling details that are likely to change frequently (exact shadow radius, minor spacing).
|
||||
- Internal implementation details (private helpers, hook internals, memoisation specifics).
|
||||
- Responsive visibility in JSDOM (use Playwright visual / responsive tests instead).
|
||||
|
||||
### Adding Tests for a New Component (≈5 minutes)
|
||||
|
||||
1. **Create the component file** in `app/components/`.
|
||||
2. **Create a test file** in `tests/components/ComponentName.test.tsx`.
|
||||
3. **Wire the standard suite** using `componentTestSuite`.
|
||||
4. **Add 1–3 custom tests** for any unique behaviours.
|
||||
5. Run:
|
||||
|
||||
```bash
|
||||
npm run test:component -- --run tests/components/ComponentName.test.tsx
|
||||
```
|
||||
|
||||
### E2E and Visual Regression
|
||||
|
||||
- Use **Playwright** for:
|
||||
- Critical user journeys (e.g., create rule, navigate blog, key flows).
|
||||
- Responsive behaviour and cross‑browser checks.
|
||||
- Visual regression (`tests/e2e/visual-regression.spec.ts`).
|
||||
|
||||
```bash
|
||||
npm run test:e2e
|
||||
npm run visual:test
|
||||
```
|
||||
|
||||
### Accessibility Testing
|
||||
|
||||
Accessibility is tested at two levels:
|
||||
|
||||
1. **Component-level accessibility** (`tests/components/*.test.tsx`):
|
||||
- Automatically covered by `componentTestSuite` using `jest-axe`
|
||||
- Tests roles, labels, ARIA attributes, keyboard navigation
|
||||
- Runs as part of every component test suite
|
||||
|
||||
2. **Full-page accessibility** (`tests/accessibility/e2e/wcag-compliance.spec.ts`):
|
||||
- E2E tests using Playwright and `@axe-core/playwright`
|
||||
- Validates WCAG 2.1 AA compliance across entire pages
|
||||
- Tests complete user journeys for accessibility barriers
|
||||
|
||||
This two-tier approach ensures both individual components and full page experiences meet accessibility standards.
|
||||
|
||||
@@ -1,391 +0,0 @@
|
||||
# Performance Optimization Guide
|
||||
|
||||
## 📋 Table of Contents
|
||||
|
||||
- [Overview](#overview)
|
||||
- [Performance Targets](#performance-targets)
|
||||
- [Frontend Optimizations](#frontend-optimizations)
|
||||
- [Performance Monitoring](#performance-monitoring)
|
||||
- [Bundle Analysis](#bundle-analysis)
|
||||
- [Web Vitals Tracking](#web-vitals-tracking)
|
||||
- [Performance Testing](#performance-testing)
|
||||
- [Troubleshooting](#troubleshooting)
|
||||
- [Best Practices](#best-practices)
|
||||
|
||||
## 🎯 Overview
|
||||
|
||||
This guide covers the comprehensive performance optimization strategy implemented in Community Rule 3.0 to achieve sub-2-second load times across all platform features.
|
||||
|
||||
### Performance Philosophy
|
||||
|
||||
- **Measure First**: Comprehensive monitoring before optimization
|
||||
- **Performance Budgets**: Enforce limits to prevent regression
|
||||
- **Real User Monitoring**: Track actual user experience
|
||||
- **Continuous Optimization**: Regular monitoring and improvement
|
||||
|
||||
## 🎯 Performance Targets
|
||||
|
||||
### Core Web Vitals
|
||||
|
||||
- **LCP (Largest Contentful Paint)**: < 2.5s (Good)
|
||||
- **FID (First Input Delay)**: < 100ms (Good)
|
||||
- **CLS (Cumulative Layout Shift)**: < 0.1 (Good)
|
||||
- **FCP (First Contentful Paint)**: < 1.8s (Good)
|
||||
- **TTFB (Time to First Byte)**: < 800ms (Good)
|
||||
|
||||
### Bundle Size Targets
|
||||
|
||||
- **Initial JavaScript Bundle**: < 250KB gzipped (currently 101KB)
|
||||
- **Total Bundle Size**: < 2MB
|
||||
- **Individual Component Bundles**: < 50KB
|
||||
- **Image Assets**: Optimized with WebP/AVIF formats
|
||||
|
||||
### Lighthouse Scores
|
||||
|
||||
- **Performance**: > 90
|
||||
- **Accessibility**: > 90
|
||||
- **Best Practices**: > 90
|
||||
- **SEO**: > 90
|
||||
|
||||
## ⚡ Frontend Optimizations
|
||||
|
||||
### 1. Code Splitting
|
||||
|
||||
Dynamic imports for non-critical components to reduce initial bundle size:
|
||||
|
||||
```javascript
|
||||
// Dynamic imports for non-critical components
|
||||
const NumberedCards = dynamic(() => import("./components/NumberedCards"), {
|
||||
loading: () => <div className="loading-placeholder">Loading...</div>,
|
||||
});
|
||||
|
||||
const LogoWall = dynamic(() => import("./components/LogoWall"), {
|
||||
loading: () => <div className="loading-placeholder">Loading...</div>,
|
||||
});
|
||||
```
|
||||
|
||||
### 2. React.memo Optimization
|
||||
|
||||
Applied to all 30+ components to prevent unnecessary re-renders:
|
||||
|
||||
```javascript
|
||||
import React, { memo } from "react";
|
||||
|
||||
const MyComponent = memo(({ prop1, prop2 }) => {
|
||||
return <div>{/* Component content */}</div>;
|
||||
});
|
||||
|
||||
MyComponent.displayName = "MyComponent";
|
||||
export default MyComponent;
|
||||
```
|
||||
|
||||
### 3. useMemo and useCallback
|
||||
|
||||
Optimized expensive computations and event handlers:
|
||||
|
||||
```javascript
|
||||
import React, { memo, useMemo, useCallback } from "react";
|
||||
|
||||
const OptimizedComponent = memo(({ data, onAction }) => {
|
||||
// Memoize expensive computations
|
||||
const processedData = useMemo(() => {
|
||||
return data.map((item) => expensiveOperation(item));
|
||||
}, [data]);
|
||||
|
||||
// Memoize event handlers
|
||||
const handleClick = useCallback(
|
||||
(id) => {
|
||||
onAction(id);
|
||||
},
|
||||
[onAction],
|
||||
);
|
||||
|
||||
return <div onClick={handleClick}>{/* Component content */}</div>;
|
||||
});
|
||||
```
|
||||
|
||||
### 4. Image Optimization
|
||||
|
||||
Enhanced `next/image` with lazy loading and blur placeholders:
|
||||
|
||||
```javascript
|
||||
import Image from "next/image";
|
||||
|
||||
<Image
|
||||
src="/assets/image.jpg"
|
||||
alt="Description"
|
||||
width={300}
|
||||
height={200}
|
||||
sizes="(max-width: 768px) 100vw, 50vw"
|
||||
loading="lazy"
|
||||
placeholder="blur"
|
||||
blurDataURL="data:image/jpeg;base64,..."
|
||||
/>;
|
||||
```
|
||||
|
||||
### 5. Font Optimization
|
||||
|
||||
Preloading and fallbacks for all fonts:
|
||||
|
||||
```javascript
|
||||
import { Inter, Bricolage_Grotesque, Space_Grotesk } from "next/font/google";
|
||||
|
||||
const inter = Inter({
|
||||
subsets: ["latin"],
|
||||
preload: true,
|
||||
fallback: ["system-ui", "arial"],
|
||||
});
|
||||
|
||||
const bricolageGrotesque = Bricolage_Grotesque({
|
||||
subsets: ["latin"],
|
||||
preload: true,
|
||||
fallback: ["system-ui", "arial"],
|
||||
});
|
||||
```
|
||||
|
||||
### 6. Error Boundaries
|
||||
|
||||
Comprehensive error handling to prevent cascade failures:
|
||||
|
||||
```javascript
|
||||
import React, { Component } from "react";
|
||||
|
||||
class ErrorBoundary extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = { hasError: false, error: null };
|
||||
}
|
||||
|
||||
static getDerivedStateFromError(error) {
|
||||
return { hasError: true };
|
||||
}
|
||||
|
||||
componentDidCatch(error, errorInfo) {
|
||||
console.error("ErrorBoundary caught an error:", error, errorInfo);
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.state.hasError) {
|
||||
return <div>Something went wrong.</div>;
|
||||
}
|
||||
return this.props.children;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 📊 Performance Monitoring
|
||||
|
||||
### Available Scripts
|
||||
|
||||
```bash
|
||||
# Individual monitoring tools
|
||||
npm run bundle:analyze # Analyze bundle sizes and budgets
|
||||
npm run performance:monitor # Performance metrics and Lighthouse CI
|
||||
npm run web-vitals:track # Core Web Vitals tracking
|
||||
|
||||
# Comprehensive testing
|
||||
npm run test:performance # All performance tests
|
||||
npm run monitor:all # All monitoring tools
|
||||
```
|
||||
|
||||
### Performance Dashboard
|
||||
|
||||
Access the performance monitoring dashboard at `/monitor` to view:
|
||||
|
||||
- Real-time Web Vitals metrics
|
||||
- Historical performance data
|
||||
- Bundle analysis results
|
||||
- Performance budget status
|
||||
- Optimization recommendations
|
||||
|
||||
## 📦 Bundle Analysis
|
||||
|
||||
### Bundle Analyzer Script
|
||||
|
||||
The bundle analyzer provides comprehensive analysis of bundle sizes:
|
||||
|
||||
```bash
|
||||
npm run bundle:analyze
|
||||
```
|
||||
|
||||
**Features:**
|
||||
|
||||
- Analyzes static assets, chunks, and pages
|
||||
- Checks against performance budgets
|
||||
- Generates optimization recommendations
|
||||
- Saves results in JSON and Markdown formats
|
||||
|
||||
**Output Files:**
|
||||
|
||||
- `.next/analyze/bundle-analysis.json` - Detailed analysis data
|
||||
- `.next/analyze/bundle-report.md` - Human-readable report
|
||||
|
||||
### Performance Budgets
|
||||
|
||||
Defined in `performance-budgets.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"budgets": [
|
||||
{
|
||||
"name": "lcp",
|
||||
"maxValue": 2500,
|
||||
"description": "Largest Contentful Paint"
|
||||
},
|
||||
{
|
||||
"name": "bundle-size",
|
||||
"maxSizeKB": 250,
|
||||
"description": "Initial JavaScript bundle size"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## 📈 Web Vitals Tracking
|
||||
|
||||
### Real-time Monitoring
|
||||
|
||||
The Web Vitals tracking system collects and reports Core Web Vitals:
|
||||
|
||||
```bash
|
||||
npm run web-vitals:track
|
||||
```
|
||||
|
||||
**Features:**
|
||||
|
||||
- Collects LCP, FID, CLS, FCP, TTFB metrics
|
||||
- Stores historical data (last 100 entries per metric)
|
||||
- Generates summary reports
|
||||
- Provides optimization recommendations
|
||||
|
||||
**API Endpoint:**
|
||||
|
||||
- `POST /api/web-vitals` - Receives Web Vitals data
|
||||
- `GET /api/web-vitals` - Returns aggregated metrics
|
||||
|
||||
### Web Vitals Dashboard
|
||||
|
||||
The dashboard component displays real-time and historical metrics:
|
||||
|
||||
```javascript
|
||||
import WebVitalsDashboard from "./components/WebVitalsDashboard";
|
||||
|
||||
<WebVitalsDashboard />;
|
||||
```
|
||||
|
||||
## 🧪 Performance Testing
|
||||
|
||||
### Comprehensive Testing
|
||||
|
||||
Run all performance tests with a single command:
|
||||
|
||||
```bash
|
||||
npm run test:performance
|
||||
```
|
||||
|
||||
**Test Coverage:**
|
||||
|
||||
- Bundle analysis with budget checking
|
||||
- Performance monitoring with Lighthouse CI
|
||||
- Web Vitals tracking setup
|
||||
- Comprehensive reporting
|
||||
|
||||
### Individual Tests
|
||||
|
||||
```bash
|
||||
# Bundle analysis only
|
||||
npm run bundle:analyze
|
||||
|
||||
# Performance monitoring only
|
||||
npm run performance:monitor
|
||||
|
||||
# Web Vitals tracking only
|
||||
npm run web-vitals:track
|
||||
|
||||
# All monitoring tools
|
||||
npm run monitor:all
|
||||
```
|
||||
|
||||
## 🔧 Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
#### 1. Bundle Size Exceeds Budget
|
||||
|
||||
```bash
|
||||
# Check bundle analysis
|
||||
npm run bundle:analyze
|
||||
|
||||
# Review recommendations in .next/analyze/bundle-report.md
|
||||
# Consider code splitting or removing unused dependencies
|
||||
```
|
||||
|
||||
#### 2. Web Vitals Poor Performance
|
||||
|
||||
```bash
|
||||
# Check Web Vitals data
|
||||
npm run web-vitals:track
|
||||
|
||||
# Review dashboard at /monitor
|
||||
# Optimize images, fonts, or JavaScript
|
||||
```
|
||||
|
||||
#### 3. Performance Tests Failing
|
||||
|
||||
```bash
|
||||
# Run comprehensive performance test
|
||||
npm run test:performance
|
||||
|
||||
# Check individual components
|
||||
npm run bundle:analyze
|
||||
npm run performance:monitor
|
||||
```
|
||||
|
||||
### Debug Commands
|
||||
|
||||
```bash
|
||||
# Debug bundle analysis
|
||||
npm run bundle:analyze --verbose
|
||||
|
||||
# Debug performance monitoring
|
||||
npm run performance:monitor --debug
|
||||
|
||||
# Check Web Vitals data
|
||||
curl http://localhost:3000/api/web-vitals
|
||||
```
|
||||
|
||||
## 🎯 Best Practices
|
||||
|
||||
### Development
|
||||
|
||||
1. **Always use React.memo** for components that receive props
|
||||
2. **Implement useMemo/useCallback** for expensive operations
|
||||
3. **Use dynamic imports** for non-critical components
|
||||
4. **Optimize images** with proper sizing and formats
|
||||
5. **Preload critical fonts** and resources
|
||||
|
||||
### Monitoring
|
||||
|
||||
1. **Run bundle analysis** before major releases
|
||||
2. **Monitor Web Vitals** in production
|
||||
3. **Check performance budgets** in CI/CD
|
||||
4. **Review optimization recommendations** regularly
|
||||
|
||||
### Performance Budgets
|
||||
|
||||
1. **Set realistic budgets** based on user needs
|
||||
2. **Monitor budget violations** in CI/CD
|
||||
3. **Optimize when budgets are exceeded**
|
||||
4. **Update budgets** as requirements change
|
||||
|
||||
## 📚 Additional Resources
|
||||
|
||||
- **Next.js Performance**: https://nextjs.org/docs/advanced-features/measuring-performance
|
||||
- **Web Vitals**: https://web.dev/vitals/
|
||||
- **Lighthouse CI**: https://github.com/GoogleChrome/lighthouse-ci
|
||||
- **React Performance**: https://react.dev/learn/render-and-commit
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: December 2024
|
||||
**Maintained by**: CommunityRule Development Team
|
||||
@@ -1,810 +0,0 @@
|
||||
# Testing Framework Documentation
|
||||
|
||||
## 📋 Table of Contents
|
||||
|
||||
- [Overview](#overview)
|
||||
- [Testing Architecture](#testing-architecture)
|
||||
- [Quick Start](#quick-start)
|
||||
- [Test Types & Coverage](#test-types--coverage)
|
||||
- [Unit & Integration Testing](#unit--integration-testing)
|
||||
- [E2E Testing](#e2e-testing)
|
||||
- [Visual Regression Testing](#visual-regression-testing)
|
||||
- [Accessibility Testing](#accessibility-testing)
|
||||
- [Performance Testing](#performance-testing)
|
||||
- [CI/CD Pipeline](#cicd-pipeline)
|
||||
- [Development Workflow](#development-workflow)
|
||||
- [Best Practices](#best-practices)
|
||||
- [Troubleshooting](#troubleshooting)
|
||||
|
||||
## 🎯 Overview
|
||||
|
||||
The CommunityRule platform uses a comprehensive testing framework with multiple layers to ensure code quality, functionality, visual consistency, and accessibility across all browsers and devices.
|
||||
|
||||
### Testing Stack
|
||||
|
||||
- **Unit/Integration**: Vitest + JSDOM + React Testing Library
|
||||
- **E2E**: Playwright (Chromium, Firefox, WebKit, Mobile)
|
||||
- **Visual Regression**: Playwright Screenshots
|
||||
- **Performance**: Lighthouse CI
|
||||
- **Accessibility**: Axe-core + Playwright
|
||||
- **CI/CD**: Gitea Actions
|
||||
|
||||
### Current Status
|
||||
|
||||
- ✅ **428 Unit Tests** (94.88% coverage - exceeds 85% target)
|
||||
- ✅ **92 E2E Tests** across 4 browsers
|
||||
- ✅ **23 Visual Regression Tests** per browser
|
||||
- ✅ **Performance Budgets** with Lighthouse CI
|
||||
- ✅ **WCAG 2.1 AA Compliance** with automated testing
|
||||
- ✅ **Bundle Analysis** with automated monitoring
|
||||
- ✅ **Web Vitals Tracking** with real-time metrics
|
||||
- ✅ **Performance Optimization** with React.memo and code splitting
|
||||
|
||||
## 🏗 Testing Architecture
|
||||
|
||||
### Test Pyramid
|
||||
|
||||
- **Unit Tests**: Fast, focused, high coverage (94.88%)
|
||||
- **Integration Tests**: Component interactions, data flow
|
||||
- **E2E Tests**: Critical user journeys, cross-browser compatibility
|
||||
|
||||
### Testing Philosophy
|
||||
|
||||
**JSDOM Limitations**: Unit tests in JSDOM can't truly test responsive behavior since CSS media queries aren't evaluated. Therefore:
|
||||
|
||||
- **Unit/Integration Tests**: Test component structure, accessibility, and configuration
|
||||
- **E2E Tests**: Test real responsive behavior at actual viewport widths
|
||||
- **Visual Tests**: Capture visual consistency across breakpoints
|
||||
|
||||
## 🚀 Quick Start
|
||||
|
||||
### Prerequisites
|
||||
|
||||
```bash
|
||||
# Install dependencies
|
||||
npm install
|
||||
|
||||
# Install Playwright browsers
|
||||
npx playwright install
|
||||
```
|
||||
|
||||
### Essential Commands
|
||||
|
||||
```bash
|
||||
# Unit tests with coverage
|
||||
npm test
|
||||
|
||||
# E2E tests
|
||||
npm run e2e
|
||||
|
||||
# Visual regression tests
|
||||
npm run visual:test
|
||||
|
||||
# Performance tests
|
||||
npm run lhci
|
||||
|
||||
# Storybook tests
|
||||
npm run test:sb
|
||||
```
|
||||
|
||||
## 🧪 Test Types & Coverage
|
||||
|
||||
### Test Structure
|
||||
|
||||
```
|
||||
tests/
|
||||
├── unit/ # Component unit tests
|
||||
│ ├── Button.test.jsx # 12 tests
|
||||
│ ├── Logo.test.jsx # 12 tests
|
||||
│ ├── RuleCard.test.jsx # 18 tests
|
||||
│ ├── SectionHeader.test.jsx # 17 tests
|
||||
│ ├── NumberedCard.test.jsx # 18 tests
|
||||
│ └── accessibility.test.jsx # 18 tests
|
||||
├── integration/ # Component integration tests
|
||||
│ ├── component-interactions.integration.test.jsx
|
||||
│ ├── page-flow.integration.test.jsx
|
||||
│ ├── user-journey.integration.test.jsx
|
||||
│ ├── layout.integration.test.jsx
|
||||
│ └── ContentLockup.integration.test.jsx
|
||||
└── e2e/ # End-to-end tests
|
||||
├── homepage.spec.ts # Homepage functionality
|
||||
├── user-journeys.spec.ts # User workflows
|
||||
├── header.responsive.spec.js # Responsive header
|
||||
├── footer.responsive.spec.js # Responsive footer
|
||||
├── visual-regression.spec.ts # Visual consistency
|
||||
├── accessibility.spec.ts # Accessibility compliance
|
||||
└── performance.spec.ts # Performance metrics
|
||||
```
|
||||
|
||||
### Coverage Requirements
|
||||
|
||||
- **Statements**: >85% (Current: 94.88%) ✅
|
||||
- **Branches**: >80% (Current: 86.93%) ✅
|
||||
- **Functions**: >80% (Current: 88.67%) ✅
|
||||
- **Lines**: >85% (Current: 94.88%) ✅
|
||||
|
||||
## 🧩 Unit & Integration Testing
|
||||
|
||||
### Framework
|
||||
|
||||
- **Vitest**: Fast unit test runner
|
||||
- **JSDOM**: Browser environment simulation
|
||||
- **React Testing Library**: Component testing utilities
|
||||
- **MSW**: API mocking
|
||||
|
||||
### Configuration
|
||||
|
||||
```javascript
|
||||
// vitest.config.js
|
||||
export default defineConfig({
|
||||
plugins: [react({ jsxRuntime: "automatic" })],
|
||||
test: {
|
||||
environment: "jsdom",
|
||||
setupFiles: ["./vitest.setup.js"],
|
||||
coverage: {
|
||||
provider: "v8",
|
||||
thresholds: { lines: 85, functions: 85, statements: 85, branches: 80 },
|
||||
},
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
### Writing Unit Tests
|
||||
|
||||
```jsx
|
||||
// tests/unit/Component.test.jsx
|
||||
import { render, screen } from "@testing-library/react";
|
||||
import { describe, test, expect, afterEach } from "vitest";
|
||||
import { cleanup } from "@testing-library/react";
|
||||
import Component from "../../app/components/Component";
|
||||
|
||||
describe("Component", () => {
|
||||
afterEach(() => cleanup());
|
||||
|
||||
test("renders correctly", () => {
|
||||
render(<Component />);
|
||||
expect(screen.getByRole("button")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test("handles user interactions", async () => {
|
||||
const user = userEvent.setup();
|
||||
render(<Component />);
|
||||
|
||||
const button = screen.getByRole("button");
|
||||
await user.click(button);
|
||||
|
||||
expect(button).toHaveClass("clicked");
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### Testing Library Queries (Priority Order)
|
||||
|
||||
1. **`getByRole`**: Most accessible, tests user experience
|
||||
2. **`getByLabelText`**: For form inputs
|
||||
3. **`getByText`**: For content
|
||||
4. **`getByTestId`**: Last resort, avoid when possible
|
||||
|
||||
### Integration Testing
|
||||
|
||||
```jsx
|
||||
test("components work together", () => {
|
||||
render(
|
||||
<div>
|
||||
<Header />
|
||||
<MainContent />
|
||||
<Footer />
|
||||
</div>,
|
||||
);
|
||||
|
||||
// Test that components complement each other
|
||||
expect(screen.getByRole("banner")).toBeInTheDocument();
|
||||
expect(screen.getByRole("main")).toBeInTheDocument();
|
||||
expect(screen.getByRole("contentinfo")).toBeInTheDocument();
|
||||
});
|
||||
```
|
||||
|
||||
### Available Scripts
|
||||
|
||||
```bash
|
||||
npm test # Run all tests with coverage
|
||||
npm run test:watch # Run tests in watch mode
|
||||
npm run test:ui # Run tests with UI
|
||||
```
|
||||
|
||||
## 🌐 E2E Testing
|
||||
|
||||
### Framework
|
||||
|
||||
- **Playwright**: Cross-browser E2E testing
|
||||
- **Browsers**: Chromium, Firefox, WebKit, Mobile
|
||||
- **Accessibility**: Axe-core integration
|
||||
|
||||
### Configuration
|
||||
|
||||
```typescript
|
||||
// playwright.config.ts
|
||||
export default defineConfig({
|
||||
testDir: "./tests/e2e",
|
||||
projects: [
|
||||
{ name: "chromium", use: { ...devices["Desktop Chrome"] } },
|
||||
{ name: "firefox", use: { ...devices["Desktop Firefox"] } },
|
||||
{ name: "webkit", use: { ...devices["Desktop Safari"] } },
|
||||
{ name: "mobile", use: { ...devices["iPhone 13"] } },
|
||||
],
|
||||
use: {
|
||||
timezoneId: "UTC",
|
||||
locale: "en-US",
|
||||
headless: true,
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
### Test Categories
|
||||
|
||||
#### 1. Functional Tests
|
||||
|
||||
- Page loading and sections
|
||||
- Component functionality
|
||||
- Navigation and interactions
|
||||
- User workflows
|
||||
|
||||
#### 2. Responsive Tests
|
||||
|
||||
- Layout changes between breakpoints
|
||||
- Component visibility at different viewports
|
||||
- Interactive behavior across screen sizes
|
||||
|
||||
#### 3. Accessibility Tests
|
||||
|
||||
- WCAG 2.1 AA compliance
|
||||
- Screen reader compatibility
|
||||
- Keyboard navigation
|
||||
- Color contrast
|
||||
|
||||
### Writing E2E Tests
|
||||
|
||||
```typescript
|
||||
// tests/e2e/example.spec.ts
|
||||
import { test, expect } from "@playwright/test";
|
||||
|
||||
test.describe("Feature", () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto("/");
|
||||
});
|
||||
|
||||
test("should work correctly", async ({ page }) => {
|
||||
await expect(page).toHaveTitle(/CommunityRule/);
|
||||
await expect(page.locator("h1")).toBeVisible();
|
||||
});
|
||||
|
||||
test("responsive behavior", async ({ page }) => {
|
||||
// Test mobile viewport
|
||||
await page.setViewportSize({ width: 375, height: 667 });
|
||||
await expect(page.getByTestId("mobile-nav")).toBeVisible();
|
||||
|
||||
// Test desktop viewport
|
||||
await page.setViewportSize({ width: 1280, height: 800 });
|
||||
await expect(page.getByTestId("desktop-nav")).toBeVisible();
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### Available Scripts
|
||||
|
||||
```bash
|
||||
npm run e2e # Run all E2E tests
|
||||
npm run e2e:ui # Run E2E tests with UI
|
||||
npm run e2e:serve # Start dev server and run tests
|
||||
```
|
||||
|
||||
## 🎨 Visual Regression Testing
|
||||
|
||||
### Overview
|
||||
|
||||
Visual regression testing ensures UI consistency across browsers and prevents unintended visual changes by comparing screenshots against baseline images.
|
||||
|
||||
### Configuration
|
||||
|
||||
- **Snapshot Template**: `{testDir}/{testFileName}-snapshots/{arg}-{projectName}.png`
|
||||
- **Deterministic Rendering**: Fixed timezone (UTC), locale (en-US), viewport
|
||||
- **Tolerance**: 2% pixel difference or 500 pixels maximum
|
||||
- **Animation Handling**: Disabled during capture
|
||||
|
||||
### Screenshots Generated
|
||||
|
||||
- **Full page screenshots** (mobile, tablet, desktop)
|
||||
- **Component screenshots** (hero, logo wall, cards, etc.)
|
||||
- **Interactive states** (hover, focus, loading, error)
|
||||
- **Special modes** (dark mode, high contrast, reduced motion)
|
||||
|
||||
### Breakpoint Coverage
|
||||
|
||||
- **Mobile**: 375x667 (iPhone)
|
||||
- **Tablet**: 768x1024 (iPad)
|
||||
- **Desktop**: 1280x800 (Standard)
|
||||
- **Large Desktop**: 1920x1080 (Full HD)
|
||||
|
||||
### Managing Visual Changes
|
||||
|
||||
```bash
|
||||
# Update baselines after intentional changes
|
||||
npm run visual:update
|
||||
|
||||
# Run visual regression tests
|
||||
npm run visual:test
|
||||
|
||||
# Run with UI for debugging
|
||||
npm run visual:ui
|
||||
```
|
||||
|
||||
### Snapshot Management
|
||||
|
||||
```bash
|
||||
# Update snapshots for all projects
|
||||
PLAYWRIGHT_UPDATE_SNAPSHOTS=1 npx playwright test tests/e2e/visual-regression.spec.ts
|
||||
|
||||
# Update snapshots for specific project
|
||||
PLAYWRIGHT_UPDATE_SNAPSHOTS=1 npx playwright test tests/e2e/visual-regression.spec.ts --project=chromium
|
||||
|
||||
# View test results
|
||||
npx playwright show-report
|
||||
```
|
||||
|
||||
## ♿ Accessibility Testing
|
||||
|
||||
### Framework
|
||||
|
||||
- **Unit Level**: jest-axe with Vitest (`tests/accessibility/unit/`)
|
||||
- **E2E Level**: Playwright accessibility tests (`tests/accessibility/e2e/`)
|
||||
- **Standards**: WCAG 2.1 AA compliance
|
||||
|
||||
### Test Organization
|
||||
|
||||
Accessibility tests are organized in a dedicated `tests/accessibility/` folder:
|
||||
|
||||
```
|
||||
tests/accessibility/
|
||||
├── unit/ # Unit-level accessibility tests
|
||||
│ └── components.test.jsx # Component accessibility (jest-axe)
|
||||
└── e2e/ # E2E accessibility tests
|
||||
└── wcag-compliance.spec.ts # WCAG compliance (Playwright)
|
||||
```
|
||||
|
||||
### Unit-Level Accessibility Testing
|
||||
|
||||
```jsx
|
||||
// tests/accessibility/unit/components.test.jsx
|
||||
import { axe, toHaveNoViolations } from "jest-axe";
|
||||
|
||||
test("component has no accessibility violations", async () => {
|
||||
const { container } = render(<Component />);
|
||||
const results = await axe(container);
|
||||
expect(results).toHaveNoViolations();
|
||||
});
|
||||
```
|
||||
|
||||
### E2E Accessibility Testing
|
||||
|
||||
```typescript
|
||||
// tests/accessibility/e2e/wcag-compliance.spec.ts
|
||||
import { test, expect } from "@playwright/test";
|
||||
|
||||
test("WCAG 2.1 AA compliance - homepage", async ({ page }) => {
|
||||
await page.goto("/");
|
||||
|
||||
// Check for proper HTML structure
|
||||
const html = page.locator("html");
|
||||
const lang = await html.getAttribute("lang");
|
||||
expect(lang).toBeTruthy();
|
||||
|
||||
// Check for main heading
|
||||
const h1 = page.locator("h1").first();
|
||||
await expect(h1).toBeVisible();
|
||||
});
|
||||
```
|
||||
|
||||
### Running Accessibility Tests
|
||||
|
||||
```bash
|
||||
# Run all accessibility tests
|
||||
npm test tests/accessibility/
|
||||
|
||||
# Run unit accessibility tests only
|
||||
npm test tests/accessibility/unit/
|
||||
|
||||
# Run E2E accessibility tests only
|
||||
npx playwright test tests/accessibility/e2e/
|
||||
|
||||
# Run specific accessibility test
|
||||
npx playwright test tests/accessibility/e2e/wcag-compliance.spec.ts
|
||||
```
|
||||
|
||||
### Manual Testing Checklist
|
||||
|
||||
- [ ] Screen reader compatibility
|
||||
- [ ] Keyboard navigation
|
||||
- [ ] Color contrast (WCAG AA)
|
||||
- [ ] Focus management
|
||||
- [ ] ARIA attributes
|
||||
- [ ] Semantic HTML
|
||||
|
||||
### WCAG 2.1 AA Requirements
|
||||
|
||||
- **Perceivable**: Text alternatives, captions, adaptable content
|
||||
- **Operable**: Keyboard accessible, timing adjustable, navigation
|
||||
- **Understandable**: Readable, predictable, input assistance
|
||||
- **Robust**: Compatible with assistive technologies
|
||||
|
||||
## ⚡ Performance Testing
|
||||
|
||||
### Framework
|
||||
|
||||
- **Lighthouse CI**: Automated performance testing
|
||||
- **Bundle Analysis**: Real-time bundle size monitoring
|
||||
- **Web Vitals Tracking**: Core Web Vitals collection and reporting
|
||||
- **Performance Monitoring**: Comprehensive performance metrics
|
||||
- **Performance Budgets**: Defined thresholds with automated enforcement
|
||||
|
||||
### Configuration
|
||||
|
||||
```json
|
||||
// .lighthouserc.json
|
||||
{
|
||||
"ci": {
|
||||
"collect": {
|
||||
"url": ["http://localhost:3010"],
|
||||
"chromeFlags": [
|
||||
"--no-sandbox",
|
||||
"--disable-dev-shm-usage",
|
||||
"--disable-gpu",
|
||||
"--headless"
|
||||
]
|
||||
},
|
||||
"assert": {
|
||||
"assertions": {
|
||||
"categories:performance": ["warn", { "minScore": 0.8 }],
|
||||
"categories:accessibility": ["error", { "minScore": 0.8 }]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Performance Metrics
|
||||
|
||||
- **Core Web Vitals**: LCP < 2.5s, FID < 100ms, CLS < 0.1
|
||||
- **Performance Score**: >80
|
||||
- **Accessibility Score**: >80
|
||||
- **Best Practices**: >90
|
||||
- **Bundle Size**: <250KB gzipped (currently 101KB)
|
||||
|
||||
### Performance Budgets
|
||||
|
||||
- **First Contentful Paint**: <3000ms
|
||||
- **Largest Contentful Paint**: <5000ms
|
||||
- **First Input Delay**: <100ms
|
||||
- **TTFB**: <700ms
|
||||
- **Bundle Size**: <250KB gzipped
|
||||
- **Total Bundle Size**: <2MB
|
||||
|
||||
### Performance Optimizations
|
||||
|
||||
- **✅ Code Splitting**: Dynamic imports for non-critical components
|
||||
- **✅ React.memo**: Applied to all 30+ components
|
||||
- **✅ Image Optimization**: Enhanced `next/image` with lazy loading
|
||||
- **✅ Font Optimization**: Preloading and fallbacks
|
||||
- **✅ Bundle Analysis**: Real-time monitoring with budgets
|
||||
- **✅ Error Boundaries**: Comprehensive error handling
|
||||
|
||||
### Available Scripts
|
||||
|
||||
```bash
|
||||
# Individual monitoring tools
|
||||
npm run bundle:analyze # Analyze bundle sizes and budgets
|
||||
npm run performance:monitor # Performance metrics and Lighthouse CI
|
||||
npm run web-vitals:track # Core Web Vitals tracking
|
||||
|
||||
# Comprehensive testing
|
||||
npm run test:performance # All performance tests
|
||||
npm run monitor:all # All monitoring tools
|
||||
|
||||
# Traditional Lighthouse CI
|
||||
npm run lhci # Run Lighthouse CI
|
||||
npm run lhci:mobile # Run with mobile preset
|
||||
npm run lhci:desktop # Run with desktop preset
|
||||
```
|
||||
|
||||
### Performance Monitoring Dashboard
|
||||
|
||||
Access the performance monitoring dashboard at `/monitor` to view:
|
||||
|
||||
- Real-time Web Vitals metrics
|
||||
- Historical performance data
|
||||
- Bundle analysis results
|
||||
- Performance budget status
|
||||
- Optimization recommendations
|
||||
|
||||
## 🔄 CI/CD Pipeline
|
||||
|
||||
### Gitea Actions Workflow
|
||||
|
||||
Location: `.gitea/workflows/ci.yaml`
|
||||
|
||||
### Pipeline Jobs
|
||||
|
||||
#### 1. Unit Tests
|
||||
|
||||
- **Node.js versions**: 18, 20
|
||||
- **Coverage reporting**: Codecov integration
|
||||
- **Parallel execution**: Matrix strategy
|
||||
|
||||
#### 2. E2E Tests
|
||||
|
||||
- **Browsers**: Chromium, Firefox, WebKit
|
||||
- **Parallel execution**: Matrix strategy
|
||||
- **Artifact upload**: Test results and reports
|
||||
|
||||
#### 3. Visual Regression Tests
|
||||
|
||||
- **Screenshot comparison**: Baseline vs current
|
||||
- **Cross-browser validation**: All 4 browser projects
|
||||
|
||||
#### 4. Performance Tests
|
||||
|
||||
- **Lighthouse CI**: Performance budgets
|
||||
- **Core Web Vitals**: Monitoring
|
||||
- **Accessibility compliance**
|
||||
|
||||
#### 5. Storybook Tests
|
||||
|
||||
- **Component testing**: Automated tests
|
||||
- **Accessibility validation**: WCAG compliance
|
||||
- **Build verification**: Storybook compilation
|
||||
|
||||
#### 6. Lint & Format
|
||||
|
||||
- **ESLint**: Code quality
|
||||
- **Prettier**: Code formatting
|
||||
|
||||
#### 7. Build Verification
|
||||
|
||||
- **Next.js build**: Application compilation
|
||||
- **Storybook build**: Documentation compilation
|
||||
|
||||
### Triggers
|
||||
|
||||
```yaml
|
||||
on:
|
||||
push:
|
||||
branches: [main, develop]
|
||||
pull_request:
|
||||
branches: [main, develop]
|
||||
```
|
||||
|
||||
## 🛠 Development Workflow
|
||||
|
||||
### 1. Feature Development
|
||||
|
||||
```bash
|
||||
# Create feature branch
|
||||
git checkout -b feature/new-component
|
||||
|
||||
# Write tests first (TDD)
|
||||
npm run test:watch
|
||||
|
||||
# Implement feature
|
||||
# Ensure tests pass
|
||||
|
||||
# Run E2E tests
|
||||
npm run e2e
|
||||
|
||||
# Commit changes
|
||||
git add .
|
||||
git commit -m "feat: add new component with tests"
|
||||
```
|
||||
|
||||
### 2. Pull Request Process
|
||||
|
||||
1. **Create PR** → CI pipeline starts automatically
|
||||
2. **Review CI Results** → All 7 jobs must pass
|
||||
3. **Check Coverage** → Ensure >85% coverage
|
||||
4. **Review Visual Changes** → Check screenshot diffs
|
||||
5. **Merge** → Only if all checks pass
|
||||
|
||||
### 3. Visual Changes
|
||||
|
||||
```bash
|
||||
# Make visual changes
|
||||
# Run visual regression tests
|
||||
npm run visual:test
|
||||
|
||||
# If changes are intentional, update baselines
|
||||
npm run visual:update
|
||||
|
||||
# Review and commit updated snapshots
|
||||
git add tests/e2e/visual-regression.spec.ts-snapshots/
|
||||
git commit -m "Update visual regression snapshots for [describe changes]"
|
||||
```
|
||||
|
||||
### 4. Performance Monitoring
|
||||
|
||||
```bash
|
||||
# Check performance before deploying
|
||||
npm run lhci
|
||||
|
||||
# Review performance budgets
|
||||
# Update .lighthouserc.json if needed
|
||||
```
|
||||
|
||||
## 📋 Best Practices
|
||||
|
||||
### 1. Test-Driven Development
|
||||
|
||||
- Write tests before implementation
|
||||
- Use descriptive test names
|
||||
- Test edge cases and error scenarios
|
||||
- Maintain high test coverage
|
||||
|
||||
### 2. Component Testing
|
||||
|
||||
```jsx
|
||||
// ✅ Good: Test behavior, not implementation
|
||||
test("shows error message when form is invalid", () => {
|
||||
render(<Form />);
|
||||
fireEvent.click(screen.getByRole("button"));
|
||||
expect(screen.getByText("Please fill all fields")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
// ❌ Avoid: Testing implementation details
|
||||
test("calls onSubmit with form data", () => {
|
||||
const mockSubmit = vi.fn();
|
||||
render(<Form onSubmit={mockSubmit} />);
|
||||
// Implementation details...
|
||||
});
|
||||
```
|
||||
|
||||
### 3. E2E Testing
|
||||
|
||||
- Test user workflows, not technical details
|
||||
- Use semantic selectors (role, text, label)
|
||||
- Test accessibility features
|
||||
- Include error scenarios
|
||||
|
||||
### 4. Visual Regression
|
||||
|
||||
- Update baselines only for intentional changes
|
||||
- Review screenshot diffs carefully
|
||||
- Test across multiple viewports
|
||||
- Consider animation states
|
||||
|
||||
### 5. Performance Testing
|
||||
|
||||
- Set realistic performance budgets
|
||||
- Monitor Core Web Vitals
|
||||
- Test on different network conditions
|
||||
- Regular performance audits
|
||||
|
||||
### 6. Responsive Testing
|
||||
|
||||
```javascript
|
||||
// ✅ Good: Test real viewport sizes
|
||||
await page.setViewportSize({ width: 640, height: 700 });
|
||||
|
||||
// ✅ Good: Test visibility at breakpoints
|
||||
if (bp.name === "xs") {
|
||||
await expect(page.getByTestId("auth-xs")).toBeVisible();
|
||||
}
|
||||
|
||||
// ❌ Avoid: Testing responsive behavior in JSDOM
|
||||
// JSDOM doesn't evaluate CSS media queries
|
||||
```
|
||||
|
||||
## 🔧 Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
#### 1. Unit Tests Failing
|
||||
|
||||
```bash
|
||||
# Run tests locally
|
||||
npm test
|
||||
|
||||
# Check for:
|
||||
# - Missing imports
|
||||
# - Incorrect assertions
|
||||
# - Component changes
|
||||
# - Test environment issues
|
||||
```
|
||||
|
||||
#### 2. E2E Tests Failing
|
||||
|
||||
```bash
|
||||
# Run locally first
|
||||
npm run e2e
|
||||
|
||||
# Common issues:
|
||||
# - Selector changes
|
||||
# - Component structure changes
|
||||
# - Network issues
|
||||
# - Browser compatibility
|
||||
```
|
||||
|
||||
#### 3. Visual Regression Failing
|
||||
|
||||
```bash
|
||||
# Check if changes are intentional
|
||||
npm run visual:test
|
||||
|
||||
# Update baselines if needed
|
||||
npm run visual:update
|
||||
|
||||
# Review screenshot diffs in CI artifacts
|
||||
```
|
||||
|
||||
#### 4. Performance Tests Failing
|
||||
|
||||
```bash
|
||||
# Run locally
|
||||
npm run lhci
|
||||
|
||||
# Check performance budgets in .lighthouserc.json
|
||||
# Optimize slow components
|
||||
# Review bundle size
|
||||
```
|
||||
|
||||
#### 5. CI Pipeline Issues
|
||||
|
||||
```bash
|
||||
# Check Gitea Actions logs
|
||||
# Verify workflow configuration
|
||||
# Check for missing dependencies
|
||||
# Review environment variables
|
||||
```
|
||||
|
||||
### Debug Commands
|
||||
|
||||
```bash
|
||||
# Debug unit tests
|
||||
npm run test:ui
|
||||
|
||||
# Debug E2E tests
|
||||
npm run e2e:ui
|
||||
|
||||
# Debug with browser dev tools
|
||||
npx playwright test --debug
|
||||
|
||||
# Run specific test file
|
||||
npx playwright test tests/e2e/homepage.spec.ts
|
||||
|
||||
# Run tests in headed mode
|
||||
npx playwright test --headed
|
||||
```
|
||||
|
||||
## 📚 Additional Resources
|
||||
|
||||
### Documentation
|
||||
|
||||
- [Vitest Documentation](https://vitest.dev/)
|
||||
- [Playwright Documentation](https://playwright.dev/)
|
||||
- [React Testing Library](https://testing-library.com/docs/react-testing-library/intro/)
|
||||
- [Lighthouse CI](https://github.com/GoogleChrome/lighthouse-ci)
|
||||
- [Storybook Testing](https://storybook.js.org/docs/writing-tests/introduction)
|
||||
|
||||
### Tools
|
||||
|
||||
- [Codecov](https://codecov.io/) - Coverage reporting
|
||||
- [Axe-core](https://github.com/dequelabs/axe-core) - Accessibility testing
|
||||
- [MSW](https://mswjs.io/) - API mocking
|
||||
|
||||
### Best Practices
|
||||
|
||||
- [Testing Best Practices](https://kentcdodds.com/blog/common-mistakes-with-react-testing-library)
|
||||
- [E2E Testing Guide](https://playwright.dev/docs/best-practices)
|
||||
- [Visual Regression Testing](https://storybook.js.org/docs/writing-tests/visual-testing)
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: December 2024
|
||||
**Framework Version**: Next.js 15 + React 19 + Tailwind 4 + Storybook 9
|
||||
**Maintained by**: CommunityRule Development Team
|
||||
@@ -1,357 +0,0 @@
|
||||
# Testing Quick Reference
|
||||
|
||||
## 🚀 Essential Commands
|
||||
|
||||
### Daily Development
|
||||
|
||||
```bash
|
||||
# Run all tests with coverage
|
||||
npm test
|
||||
|
||||
# Watch mode (during development)
|
||||
npm run test:watch
|
||||
|
||||
# E2E tests
|
||||
npm run e2e
|
||||
|
||||
# Visual regression tests
|
||||
npm run visual:test
|
||||
|
||||
# Performance check
|
||||
npm run lhci
|
||||
|
||||
# Performance monitoring
|
||||
npm run test:performance # Comprehensive performance testing
|
||||
npm run bundle:analyze # Bundle size analysis
|
||||
npm run web-vitals:track # Web Vitals tracking
|
||||
npm run monitor:all # All monitoring tools
|
||||
|
||||
# Storybook tests
|
||||
npm run test:sb
|
||||
```
|
||||
|
||||
### Test UI & Debugging
|
||||
|
||||
```bash
|
||||
# Debug unit tests
|
||||
npm run test:ui
|
||||
|
||||
# Debug E2E tests
|
||||
npm run e2e:ui
|
||||
|
||||
# Debug with browser
|
||||
npx playwright test --debug
|
||||
|
||||
# Run tests in headed mode
|
||||
npx playwright test --headed
|
||||
```
|
||||
|
||||
## 📊 Current Test Status
|
||||
|
||||
- **Unit Tests**: 94.88% ✅ (Target: >85%)
|
||||
- **Integration Tests**: 5 comprehensive test suites ✅
|
||||
- **E2E Tests**: 92 tests across 4 browsers ✅
|
||||
- **Visual Regression**: 23 tests per browser ✅
|
||||
- **Accessibility Tests**: WCAG 2.1 AA compliance ✅
|
||||
- **Performance Tests**: Lighthouse CI with budgets ✅
|
||||
- **Bundle Analysis**: Real-time monitoring with budgets ✅
|
||||
- **Web Vitals Tracking**: Core Web Vitals collection ✅
|
||||
- **Performance Optimization**: React.memo + code splitting ✅
|
||||
|
||||
## 🔧 Common Test Commands
|
||||
|
||||
### Unit Testing
|
||||
|
||||
```bash
|
||||
# Run specific test file
|
||||
npm test -- --run tests/unit/Component.test.jsx
|
||||
|
||||
# Run tests matching pattern
|
||||
npm test -- --run Component
|
||||
|
||||
# Run with coverage report
|
||||
npm test -- --coverage
|
||||
|
||||
# Run in watch mode
|
||||
npm run test:watch
|
||||
```
|
||||
|
||||
### E2E Testing
|
||||
|
||||
```bash
|
||||
# Run specific test file
|
||||
npm run e2e -- tests/e2e/homepage.spec.ts
|
||||
|
||||
# Run specific project (browser)
|
||||
npm run e2e -- --project=chromium
|
||||
|
||||
# Run with headed browser
|
||||
npm run e2e -- --headed
|
||||
|
||||
# Run with debug mode
|
||||
npm run e2e -- --debug
|
||||
```
|
||||
|
||||
### Visual Regression
|
||||
|
||||
```bash
|
||||
# Update snapshots for all projects
|
||||
npm run visual:update
|
||||
|
||||
# Update snapshots for specific project
|
||||
PLAYWRIGHT_UPDATE_SNAPSHOTS=1 npx playwright test tests/e2e/visual-regression.spec.ts --project=chromium
|
||||
|
||||
# View test results
|
||||
npx playwright show-report
|
||||
```
|
||||
|
||||
### Performance Testing
|
||||
|
||||
```bash
|
||||
# Run mobile performance test
|
||||
npm run lhci:mobile
|
||||
|
||||
# Run desktop performance test
|
||||
npm run lhci:desktop
|
||||
|
||||
# Run with custom budget
|
||||
npm run performance:budget
|
||||
```
|
||||
|
||||
### Accessibility Testing
|
||||
|
||||
```bash
|
||||
# Run all accessibility tests
|
||||
npm test tests/accessibility/
|
||||
|
||||
# Run unit accessibility tests only
|
||||
npm test tests/accessibility/unit/
|
||||
|
||||
# Run E2E accessibility tests only
|
||||
npx playwright test tests/accessibility/e2e/
|
||||
|
||||
# Run specific accessibility test
|
||||
npx playwright test tests/accessibility/e2e/wcag-compliance.spec.ts
|
||||
```
|
||||
|
||||
## 📱 Browser Support
|
||||
|
||||
| Browser | Project Name | Status |
|
||||
| ----------- | ------------ | --------------- |
|
||||
| **Chrome** | `chromium` | ✅ Full Support |
|
||||
| **Firefox** | `firefox` | ✅ Full Support |
|
||||
| **Safari** | `webkit` | ✅ Full Support |
|
||||
| **Mobile** | `mobile` | ✅ Full Support |
|
||||
|
||||
## 🎯 Testing Best Practices
|
||||
|
||||
### 1. Test Structure (AAA Pattern)
|
||||
|
||||
```jsx
|
||||
test("should do something", () => {
|
||||
// Arrange: Set up test data
|
||||
const data = { name: "Test" };
|
||||
|
||||
// Act: Perform the action
|
||||
const result = processData(data);
|
||||
|
||||
// Assert: Verify the outcome
|
||||
expect(result).toBe("Processed Test");
|
||||
});
|
||||
```
|
||||
|
||||
### 2. Query Priority
|
||||
|
||||
1. **`getByRole`** - Most accessible, tests user experience
|
||||
2. **`getByLabelText`** - For form inputs
|
||||
3. **`getByText`** - For content
|
||||
4. **`getByTestId`** - Last resort, avoid when possible
|
||||
|
||||
### 3. Async Testing
|
||||
|
||||
```jsx
|
||||
test("async operation", async () => {
|
||||
const user = userEvent.setup();
|
||||
|
||||
render(<Component />);
|
||||
const button = screen.getByRole("button");
|
||||
|
||||
await user.click(button);
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText("Success")).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### 4. Responsive Testing
|
||||
|
||||
```javascript
|
||||
// ✅ Good: Test real viewport sizes
|
||||
await page.setViewportSize({ width: 640, height: 700 });
|
||||
|
||||
// ✅ Good: Test visibility at breakpoints
|
||||
if (bp.name === "xs") {
|
||||
await expect(page.getByTestId("auth-xs")).toBeVisible();
|
||||
}
|
||||
|
||||
// ❌ Avoid: Testing responsive behavior in JSDOM
|
||||
// JSDOM doesn't evaluate CSS media queries
|
||||
```
|
||||
|
||||
## 🔍 Common Issues & Solutions
|
||||
|
||||
### Visual Regression Failures
|
||||
|
||||
```bash
|
||||
# Regenerate snapshots
|
||||
npm run visual:update
|
||||
|
||||
# Check for environment differences
|
||||
# Ensure deterministic rendering in Playwright config
|
||||
```
|
||||
|
||||
### E2E Test Failures
|
||||
|
||||
```bash
|
||||
# Use waitFor instead of waitForTimeout
|
||||
await page.waitForSelector("button", { state: "visible" });
|
||||
|
||||
# Use role-based selectors
|
||||
await page.getByRole("button", { name: "Submit" }).click();
|
||||
|
||||
# Check for selector changes
|
||||
# Verify component structure hasn't changed
|
||||
```
|
||||
|
||||
### Performance Test Failures
|
||||
|
||||
```bash
|
||||
# Check Chrome path on macOS
|
||||
# Ensure arm64 Chrome for Apple Silicon
|
||||
# Verify performance budgets in .lighthouserc.json
|
||||
```
|
||||
|
||||
### Unit Test Failures
|
||||
|
||||
```bash
|
||||
# Check for missing imports
|
||||
# Verify component exports
|
||||
# Ensure test environment setup
|
||||
# Check for component changes
|
||||
```
|
||||
|
||||
## 📈 Performance Budgets
|
||||
|
||||
### Lighthouse CI Targets
|
||||
|
||||
- **Performance Score**: >80
|
||||
- **Accessibility Score**: >80
|
||||
- **Best Practices**: >90
|
||||
- **SEO Score**: >90
|
||||
|
||||
### Core Web Vitals
|
||||
|
||||
- **LCP**: <2.5s
|
||||
- **FID**: <100ms
|
||||
- **CLS**: <0.1
|
||||
|
||||
### Performance Budgets
|
||||
|
||||
- **First Contentful Paint**: <3000ms
|
||||
- **Largest Contentful Paint**: <5000ms
|
||||
- **First Input Delay**: <100ms
|
||||
- **TTFB**: <700ms
|
||||
|
||||
## 🔄 CI/CD Pipeline Jobs
|
||||
|
||||
1. **Unit Tests** (Node 18, 20) - Coverage reporting
|
||||
2. **E2E Tests** (Chromium, Firefox, WebKit) - Cross-browser testing
|
||||
3. **Visual Regression Tests** - Screenshot comparison
|
||||
4. **Performance Tests** - Lighthouse CI with budgets
|
||||
5. **Storybook Tests** - Component testing & accessibility
|
||||
6. **Lint & Format** - Code quality & formatting
|
||||
7. **Build Verification** - Next.js & Storybook builds
|
||||
|
||||
## 📁 Test File Structure
|
||||
|
||||
```
|
||||
tests/
|
||||
├── unit/ # Component tests
|
||||
│ ├── Button.test.jsx # 12 tests
|
||||
│ ├── Logo.test.jsx # 12 tests
|
||||
│ ├── RuleCard.test.jsx # 18 tests
|
||||
│ ├── SectionHeader.test.jsx # 17 tests
|
||||
│ ├── NumberedCard.test.jsx # 18 tests
|
||||
│ └── ... # Other component tests
|
||||
├── integration/ # Integration tests
|
||||
│ ├── component-interactions.integration.test.jsx
|
||||
│ ├── page-flow.integration.test.jsx
|
||||
│ ├── user-journey.integration.test.jsx
|
||||
│ ├── layout.integration.test.jsx
|
||||
│ └── ContentLockup.integration.test.jsx
|
||||
├── accessibility/ # Accessibility-focused tests
|
||||
│ ├── unit/ # Unit-level accessibility (jest-axe)
|
||||
│ │ └── components.test.jsx # Component accessibility tests
|
||||
│ └── e2e/ # E2E accessibility (Playwright + axe-core)
|
||||
│ └── wcag-compliance.spec.ts # WCAG compliance tests
|
||||
└── e2e/ # General E2E tests
|
||||
├── homepage.spec.ts # Homepage functionality
|
||||
├── user-journeys.spec.ts # User workflows
|
||||
├── header.responsive.spec.js # Responsive header
|
||||
├── footer.responsive.spec.js # Responsive footer
|
||||
├── visual-regression.spec.ts # Visual consistency
|
||||
├── accessibility.spec.ts # General accessibility tests
|
||||
└── performance.spec.ts # Performance metrics
|
||||
```
|
||||
|
||||
## 🎨 Visual Regression Screenshots
|
||||
|
||||
### Generated Screenshots
|
||||
|
||||
- Full page (mobile, tablet, desktop)
|
||||
- Component sections (hero, logo wall, cards)
|
||||
- Interactive states (hover, focus, loading)
|
||||
- Special modes (dark, high contrast, reduced motion)
|
||||
|
||||
### Managing Changes
|
||||
|
||||
```bash
|
||||
# Intentional changes
|
||||
npm run visual:update
|
||||
|
||||
# Review changes
|
||||
git diff tests/e2e/visual-regression.spec.ts-snapshots/
|
||||
|
||||
# Commit updated snapshots
|
||||
git add tests/e2e/visual-regression.spec.ts-snapshots/
|
||||
git commit -m "Update visual regression snapshots for [describe changes]"
|
||||
```
|
||||
|
||||
## 📈 Monitoring
|
||||
|
||||
### Test Metrics
|
||||
|
||||
- **Unit Tests**: 305 tests (94.88% coverage)
|
||||
- **E2E Tests**: 92 tests (4 browsers)
|
||||
- **Visual Screenshots**: 92 baselines per browser
|
||||
- **Coverage**: >85% target (exceeded)
|
||||
|
||||
### CI Metrics
|
||||
|
||||
- **Pipeline Jobs**: 7 parallel jobs
|
||||
- **Execution Time**: Monitor build performance
|
||||
- **Success Rate**: Track pipeline stability
|
||||
- **Artifacts**: Test results and screenshots
|
||||
|
||||
## 🔗 Useful Links
|
||||
|
||||
- **Full Testing Documentation**: [docs/guides/testing-framework.md](./testing-framework.md)
|
||||
- **Vitest Docs**: https://vitest.dev/
|
||||
- **Playwright Docs**: https://playwright.dev/
|
||||
- **React Testing Library**: https://testing-library.com/docs/react-testing-library/intro/
|
||||
- **Lighthouse CI**: https://github.com/GoogleChrome/lighthouse-ci
|
||||
|
||||
---
|
||||
|
||||
**Quick Reference Version**: December 2024
|
||||
**For detailed guidelines, see [testing-framework.md](./testing-framework.md)**
|
||||
@@ -1,258 +0,0 @@
|
||||
# Testing Strategy for CommunityRule
|
||||
|
||||
## Overview
|
||||
|
||||
This document outlines our comprehensive testing strategy that properly separates unit testing from responsive behavior testing, following best practices for JSDOM limitations and real browser testing.
|
||||
|
||||
## Current Test Status
|
||||
|
||||
- **236 total tests** across the project
|
||||
- **227 tests passing** (96.2% success rate)
|
||||
- **9 tests failing** (performance and interaction tests)
|
||||
- **15 test files** covering all major components
|
||||
- **Performance Monitoring**: Comprehensive regression detection and budget enforcement
|
||||
|
||||
## Testing Philosophy
|
||||
|
||||
### The Problem with JSDOM and Responsive Testing
|
||||
|
||||
**Short take: Unit tests in JSDOM can't truly "switch breakpoints."** JSDOM doesn't evaluate CSS media queries, so Tailwind's `hidden sm:block …` won't change visibility when you "resize" the window.
|
||||
|
||||
### Solution: Proper Test Separation
|
||||
|
||||
- **Unit / component tests (Vitest + RTL):** assert **structure and classes**, not responsive visibility.
|
||||
- **Responsive behavior:** verify with **browser-based tests** (Playwright) or **visual tests** (Chromatic/Storybook) at real viewport widths.
|
||||
|
||||
## Test Categories
|
||||
|
||||
### 1. Unit Tests (Vitest + React Testing Library)
|
||||
|
||||
**Purpose:** Test component structure, accessibility, and configuration data.
|
||||
|
||||
**What to test:**
|
||||
|
||||
- DOM roles/labels exist: `role="banner"`, nav landmark, menu items
|
||||
- The right **Tailwind classes** are present on wrappers (`block sm:hidden`, `hidden md:block`, etc.)
|
||||
- Data-driven bits produce the expected count/order (e.g., `navigationItems`, `avatarImages`, `logoConfig`)
|
||||
- Component configuration and exported data structures
|
||||
|
||||
**Example:**
|
||||
|
||||
```javascript
|
||||
// tests/unit/Header.structure.test.js
|
||||
test("logo wrappers include breakpoint classes", () => {
|
||||
render(<Header />);
|
||||
const logoWrappers = screen.getAllByTestId("logo-wrapper");
|
||||
|
||||
// Check first logo variant (xs only)
|
||||
expect(logoWrappers[0]).toHaveClass("block", "sm:hidden");
|
||||
|
||||
// Check second logo variant (sm only)
|
||||
expect(logoWrappers[1]).toHaveClass("hidden", "sm:block", "md:hidden");
|
||||
});
|
||||
```
|
||||
|
||||
### 2. Browser-Based Tests (Playwright)
|
||||
|
||||
**Purpose:** Test real responsive behavior at actual viewport widths.
|
||||
|
||||
**What to test:**
|
||||
|
||||
- **Visibility** at real breakpoints
|
||||
- **Layout changes** between breakpoints
|
||||
- **Interactive behavior** at different screen sizes
|
||||
- **Accessibility** across viewports
|
||||
|
||||
**Example:**
|
||||
|
||||
```javascript
|
||||
// tests/e2e/header.responsive.spec.js
|
||||
const breakpoints = [
|
||||
{ name: "xs", width: 360, height: 700 },
|
||||
{ name: "sm", width: 640, height: 700 },
|
||||
{ name: "md", width: 768, height: 700 },
|
||||
{ name: "lg", width: 1024, height: 700 },
|
||||
{ name: "xl", width: 1280, height: 700 },
|
||||
];
|
||||
|
||||
for (const bp of breakpoints) {
|
||||
test(`header layout at ${bp.name}`, async ({ page }) => {
|
||||
await page.setViewportSize({ width: bp.width, height: bp.height });
|
||||
await page.goto("/");
|
||||
|
||||
const nav = page.getByRole("navigation", { name: /main navigation/i });
|
||||
await expect(nav).toBeVisible();
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Visual Tests (Storybook + Chromatic)
|
||||
|
||||
**Purpose:** Visual regression testing and design system validation.
|
||||
|
||||
**What to test:**
|
||||
|
||||
- **Visual diffs** per breakpoint
|
||||
- **Design consistency** across viewports
|
||||
- **Component variations** and states
|
||||
|
||||
**Example:**
|
||||
|
||||
```javascript
|
||||
// stories/Header.responsive.stories.js
|
||||
export default {
|
||||
parameters: {
|
||||
chromatic: {
|
||||
viewports: [360, 640, 768, 1024, 1280],
|
||||
delay: 100,
|
||||
},
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
## Component Improvements
|
||||
|
||||
### Header Component Enhancements
|
||||
|
||||
1. **Added Test IDs** for easier testing:
|
||||
|
||||
```jsx
|
||||
<div data-testid="logo-wrapper" className={config.breakpoint}>
|
||||
{renderLogo(config.size, config.showText)}
|
||||
</div>
|
||||
```
|
||||
|
||||
2. **Exported Configuration** for testing:
|
||||
|
||||
```javascript
|
||||
export const navigationItems = [...];
|
||||
export const avatarImages = [...];
|
||||
export const logoConfig = [...];
|
||||
```
|
||||
|
||||
3. **Structured Breakpoint Containers**:
|
||||
```jsx
|
||||
<div data-testid="nav-xs" className="block sm:hidden">
|
||||
<div data-testid="nav-sm" className="hidden sm:block md:hidden">
|
||||
<div data-testid="nav-md" className="hidden md:block lg:hidden">
|
||||
```
|
||||
|
||||
## Test File Structure
|
||||
|
||||
```
|
||||
tests/
|
||||
├── unit/ # Unit tests (Vitest + RTL)
|
||||
│ ├── Header.test.jsx # CONSOLIDATED: Comprehensive Header tests
|
||||
│ ├── Footer.test.jsx
|
||||
│ ├── Layout.test.jsx
|
||||
│ └── Page.test.jsx
|
||||
├── integration/ # Integration tests
|
||||
│ └── ContentLockup.integration.test.jsx
|
||||
├── e2e/ # Browser tests (Playwright)
|
||||
│ └── header.responsive.spec.js # NEW: Responsive behavior tests
|
||||
└── stories/ # Storybook stories
|
||||
└── Header.responsive.stories.js # NEW: Visual testing
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
### Unit Testing (JSDOM)
|
||||
|
||||
1. **Test structure, not visibility**:
|
||||
|
||||
```javascript
|
||||
// ✅ Good: Test classes exist
|
||||
expect(element).toHaveClass("block", "sm:hidden");
|
||||
|
||||
// ❌ Bad: Test visibility (doesn't work in JSDOM)
|
||||
expect(element).toBeVisible();
|
||||
```
|
||||
|
||||
2. **Use test IDs for containers**:
|
||||
|
||||
```javascript
|
||||
// ✅ Good: Test specific containers
|
||||
const logoWrapper = screen.getByTestId("logo-wrapper");
|
||||
|
||||
// ❌ Bad: Query by complex class strings
|
||||
const logoWrapper = document.querySelector(".block.sm\\:hidden");
|
||||
```
|
||||
|
||||
3. **Test configuration data**:
|
||||
```javascript
|
||||
// ✅ Good: Test exported configuration
|
||||
expect(navigationItems).toHaveLength(3);
|
||||
expect(logoConfig).toHaveLength(5);
|
||||
```
|
||||
|
||||
### Browser Testing (Playwright)
|
||||
|
||||
1. **Test real viewport sizes**:
|
||||
|
||||
```javascript
|
||||
await page.setViewportSize({ width: 640, height: 700 });
|
||||
```
|
||||
|
||||
2. **Test visibility at breakpoints**:
|
||||
|
||||
```javascript
|
||||
if (bp.name === "xs") {
|
||||
await expect(page.getByTestId("auth-xs")).toBeVisible();
|
||||
}
|
||||
```
|
||||
|
||||
3. **Test accessibility across viewports**:
|
||||
|
||||
```javascript
|
||||
const interactiveElements = [
|
||||
page.getByRole("link", { name: /use cases/i }),
|
||||
page.getByRole("button", { name: /create rule/i }),
|
||||
];
|
||||
|
||||
for (const element of interactiveElements) {
|
||||
await expect(element).toBeVisible();
|
||||
await expect(element).toBeEnabled();
|
||||
}
|
||||
```
|
||||
|
||||
## Running Tests
|
||||
|
||||
### Unit Tests
|
||||
|
||||
```bash
|
||||
npm test # Run all unit tests
|
||||
npm test tests/unit/ # Run only unit tests
|
||||
npm test Header.structure # Run specific test file
|
||||
```
|
||||
|
||||
### Browser Tests
|
||||
|
||||
```bash
|
||||
npx playwright test # Run all browser tests
|
||||
npx playwright test header.responsive.spec.js # Run specific test
|
||||
```
|
||||
|
||||
### Visual Tests
|
||||
|
||||
```bash
|
||||
npm run storybook # Start Storybook
|
||||
npx chromatic --project-token=xxx # Run visual tests
|
||||
```
|
||||
|
||||
## Future Improvements
|
||||
|
||||
1. **Add more Playwright tests** for other components
|
||||
2. **Set up Chromatic** for visual regression testing
|
||||
3. **Add performance tests** for responsive behavior
|
||||
4. **Create component-specific test utilities**
|
||||
5. **Add accessibility testing** with axe-core
|
||||
|
||||
## Key Takeaways
|
||||
|
||||
1. **JSDOM limitations** require separating structure tests from visibility tests
|
||||
2. **Test IDs** make testing more reliable and maintainable
|
||||
3. **Exported configuration** enables better data structure testing
|
||||
4. **Real browser testing** is essential for responsive behavior
|
||||
5. **Visual testing** catches design regressions across breakpoints
|
||||
|
||||
This strategy provides comprehensive coverage while respecting the limitations of different testing environments.
|
||||
@@ -1,391 +0,0 @@
|
||||
# Visual Regression Testing Guide
|
||||
|
||||
## Overview
|
||||
|
||||
Visual regression testing ensures UI consistency across browsers and prevents unintended visual changes by comparing screenshots against baseline images. This guide covers the complete workflow for managing visual regression tests.
|
||||
|
||||
## 🚀 Quick Start
|
||||
|
||||
### First-Time Setup
|
||||
|
||||
```bash
|
||||
# 1. Generate baseline snapshots for all projects
|
||||
npm run visual:update
|
||||
|
||||
# 2. Verify snapshots were created
|
||||
ls tests/e2e/visual-regression.spec.ts-snapshots/
|
||||
|
||||
# 3. Commit the snapshots
|
||||
git add tests/e2e/visual-regression.spec.ts-snapshots/
|
||||
git commit -m "Add baseline visual regression snapshots"
|
||||
|
||||
# 4. Verify setup works
|
||||
npm run visual:test
|
||||
```
|
||||
|
||||
### Daily Workflow
|
||||
|
||||
```bash
|
||||
# Run visual regression tests
|
||||
npm run visual:test
|
||||
|
||||
# Run with UI for debugging
|
||||
npm run visual:ui
|
||||
|
||||
# Update snapshots after UI changes
|
||||
npm run visual:update
|
||||
```
|
||||
|
||||
## 📝 Managing Visual Changes
|
||||
|
||||
### When UI Changes Are Intentional
|
||||
|
||||
1. **Make your UI changes** (design updates, component modifications, etc.)
|
||||
|
||||
2. **Update snapshots to reflect new design:**
|
||||
|
||||
```bash
|
||||
npm run visual:update
|
||||
```
|
||||
|
||||
3. **Review changes:**
|
||||
|
||||
```bash
|
||||
git diff tests/e2e/visual-regression.spec.ts-snapshots/
|
||||
```
|
||||
|
||||
4. **Commit updated snapshots:**
|
||||
```bash
|
||||
git add tests/e2e/visual-regression.spec.ts-snapshots/
|
||||
git commit -m "Update snapshots for [describe changes]"
|
||||
```
|
||||
|
||||
### When UI Changes Are Unintentional
|
||||
|
||||
1. **Investigate the failure** - Check what changed and why
|
||||
2. **Fix the regression** - Revert or fix the unintended change
|
||||
3. **Re-run tests** - Ensure they pass without updating snapshots
|
||||
4. **Commit the fix** - Don't update snapshots for bug fixes
|
||||
|
||||
## ⚙️ Configuration
|
||||
|
||||
### Playwright Configuration
|
||||
|
||||
The visual regression tests use these key settings in `playwright.config.ts`:
|
||||
|
||||
```typescript
|
||||
export default defineConfig({
|
||||
expect: {
|
||||
toHaveScreenshot: {
|
||||
animations: "disabled",
|
||||
maxDiffPixelRatio: 0.02, // 2% tolerance
|
||||
maxDiffPixels: 500, // 500 pixel tolerance
|
||||
},
|
||||
},
|
||||
use: {
|
||||
timezoneId: "UTC", // Consistent timezone
|
||||
locale: "en-US", // Consistent locale
|
||||
headless: true, // Headless for CI
|
||||
},
|
||||
snapshotPathTemplate:
|
||||
"{testDir}/{testFileName}-snapshots/{arg}-{projectName}.png",
|
||||
});
|
||||
```
|
||||
|
||||
### Deterministic Rendering
|
||||
|
||||
To ensure consistent screenshots across environments:
|
||||
|
||||
- **Fixed timezone**: UTC
|
||||
- **Fixed locale**: en-US
|
||||
- **Fixed viewport**: 1280x800 (configurable per test)
|
||||
- **Disabled animations**: Prevents timing-related differences
|
||||
- **Browser-specific snapshots**: Separate baselines per browser
|
||||
|
||||
## 📱 Breakpoint Coverage
|
||||
|
||||
### Standard Viewports
|
||||
|
||||
| Breakpoint | Width | Height | Description |
|
||||
| ----------- | ------ | ------ | ---------------- |
|
||||
| **Mobile** | 375px | 667px | iPhone portrait |
|
||||
| **Tablet** | 768px | 1024px | iPad portrait |
|
||||
| **Desktop** | 1280px | 800px | Standard desktop |
|
||||
| **Large** | 1920px | 1080px | Full HD desktop |
|
||||
|
||||
### Custom Viewports
|
||||
|
||||
```typescript
|
||||
test("mobile layout", async ({ page }) => {
|
||||
await page.setViewportSize({ width: 375, height: 667 });
|
||||
await expect(page).toHaveScreenshot("mobile-layout.png");
|
||||
});
|
||||
|
||||
test("tablet layout", async ({ page }) => {
|
||||
await page.setViewportSize({ width: 768, height: 1024 });
|
||||
await expect(page).toHaveScreenshot("tablet-layout.png");
|
||||
});
|
||||
```
|
||||
|
||||
## 🎨 Screenshot Types
|
||||
|
||||
### Full Page Screenshots
|
||||
|
||||
```typescript
|
||||
test("homepage full page", async ({ page }) => {
|
||||
await expect(page).toHaveScreenshot("homepage-full.png", {
|
||||
fullPage: true,
|
||||
animations: "disabled",
|
||||
scale: "css",
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### Component Screenshots
|
||||
|
||||
```typescript
|
||||
test("hero section", async ({ page }) => {
|
||||
const hero = page.locator("[data-testid='hero-section']");
|
||||
await expect(hero).toHaveScreenshot("hero-section.png");
|
||||
});
|
||||
```
|
||||
|
||||
### Interactive States
|
||||
|
||||
```typescript
|
||||
test("button hover state", async ({ page }) => {
|
||||
const button = page.getByRole("button", { name: "Submit" });
|
||||
|
||||
// Normal state
|
||||
await expect(button).toHaveScreenshot("button-normal.png");
|
||||
|
||||
// Hover state
|
||||
await button.hover();
|
||||
await expect(button).toHaveScreenshot("button-hover.png");
|
||||
});
|
||||
```
|
||||
|
||||
### Special Modes
|
||||
|
||||
```typescript
|
||||
test("dark mode", async ({ page }) => {
|
||||
// Enable dark mode
|
||||
await page.evaluate(() => {
|
||||
document.documentElement.classList.add("dark");
|
||||
});
|
||||
|
||||
await expect(page).toHaveScreenshot("dark-mode.png");
|
||||
});
|
||||
|
||||
test("high contrast", async ({ page }) => {
|
||||
// Enable high contrast
|
||||
await page.evaluate(() => {
|
||||
document.body.style.filter = "contrast(200%)";
|
||||
});
|
||||
|
||||
await expect(page).toHaveScreenshot("high-contrast.png");
|
||||
});
|
||||
```
|
||||
|
||||
## 🔄 Snapshot Management
|
||||
|
||||
### Update Commands
|
||||
|
||||
```bash
|
||||
# Update all snapshots for all projects
|
||||
npm run visual:update
|
||||
|
||||
# Update snapshots for specific project
|
||||
PLAYWRIGHT_UPDATE_SNAPSHOTS=1 npx playwright test tests/e2e/visual-regression.spec.ts --project=chromium
|
||||
|
||||
# Update snapshots for specific test
|
||||
PLAYWRIGHT_UPDATE_SNAPSHOTS=1 npx playwright test tests/e2e/visual-regression.spec.ts --grep="homepage"
|
||||
```
|
||||
|
||||
### Snapshot Naming Convention
|
||||
|
||||
Snapshots follow this pattern:
|
||||
|
||||
```
|
||||
{testDir}/{testFileName}-snapshots/{arg}-{projectName}.png
|
||||
```
|
||||
|
||||
Examples:
|
||||
|
||||
- `tests/e2e/visual-regression.spec.ts-snapshots/homepage-full-chromium.png`
|
||||
- `tests/e2e/visual-regression.spec.ts-snapshots/hero-section-firefox.png`
|
||||
- `tests/e2e/visual-regression.spec.ts-snapshots/button-hover-webkit.png`
|
||||
- `tests/e2e/visual-regression.spec.ts-snapshots/mobile-layout-mobile.png`
|
||||
|
||||
### File Organization
|
||||
|
||||
```
|
||||
tests/e2e/visual-regression.spec.ts-snapshots/
|
||||
├── homepage-full-chromium.png
|
||||
├── homepage-full-firefox.png
|
||||
├── homepage-full-webkit.png
|
||||
├── homepage-full-mobile.png
|
||||
├── hero-section-chromium.png
|
||||
├── hero-section-firefox.png
|
||||
├── hero-section-webkit.png
|
||||
├── hero-section-mobile.png
|
||||
└── ... (92 total screenshots)
|
||||
```
|
||||
|
||||
## 🐛 Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
#### 1. "Snapshot doesn't exist" errors
|
||||
|
||||
**Cause**: Baseline snapshots haven't been generated or are missing
|
||||
|
||||
**Solution**:
|
||||
|
||||
```bash
|
||||
# Regenerate all snapshots
|
||||
npm run visual:update
|
||||
|
||||
# Or regenerate for specific project
|
||||
PLAYWRIGHT_UPDATE_SNAPSHOTS=1 npx playwright test tests/e2e/visual-regression.spec.ts --project=chromium
|
||||
```
|
||||
|
||||
#### 2. Platform differences (macOS vs Linux)
|
||||
|
||||
**Cause**: Different font rendering between platforms
|
||||
|
||||
**Solution**:
|
||||
|
||||
- Use CI-generated snapshots for consistency
|
||||
- Ensure deterministic rendering settings
|
||||
- Check font availability across platforms
|
||||
|
||||
#### 3. Minor pixel differences
|
||||
|
||||
**Cause**: Font rendering, anti-aliasing, scaling differences
|
||||
|
||||
**Solution**:
|
||||
|
||||
- Check tolerance settings in `playwright.config.ts`
|
||||
- Use `scale: "css"` for consistent scaling
|
||||
- Ensure deterministic CSS properties
|
||||
|
||||
#### 4. Animation-related failures
|
||||
|
||||
**Cause**: Animations not fully disabled
|
||||
|
||||
**Solution**:
|
||||
|
||||
- Ensure `animations: "disabled"` is set in test configuration
|
||||
- Wait for animations to complete before screenshots
|
||||
- Use `waitForTimeout` if necessary
|
||||
|
||||
#### 5. Height differences (especially WebKit)
|
||||
|
||||
**Cause**: WebKit may render elements with slightly different heights
|
||||
|
||||
**Solution**:
|
||||
|
||||
- Increase tolerance for height-sensitive tests
|
||||
- Use `maxDiffPixels: 1000` for specific tests
|
||||
- Consider using `ignoreSize: false` (default)
|
||||
|
||||
### Debug Commands
|
||||
|
||||
```bash
|
||||
# Run with UI for visual debugging
|
||||
npm run visual:ui
|
||||
|
||||
# Run specific test with debugging
|
||||
npx playwright test tests/e2e/visual-regression.spec.ts --grep="homepage" --debug
|
||||
|
||||
# Run with headed browser
|
||||
npx playwright test tests/e2e/visual-regression.spec.ts --headed
|
||||
|
||||
# View test results
|
||||
npx playwright show-report
|
||||
```
|
||||
|
||||
### Environment Consistency
|
||||
|
||||
To ensure consistent results:
|
||||
|
||||
1. **Use same Node.js version** across environments
|
||||
2. **Use same Playwright version** across environments
|
||||
3. **Use same browser versions** when possible
|
||||
4. **Set consistent environment variables** (timezone, locale)
|
||||
5. **Use deterministic CSS** (avoid random values, timestamps)
|
||||
|
||||
## 📊 CI/CD Integration
|
||||
|
||||
### CI Workflow
|
||||
|
||||
Visual regression tests run automatically in the CI pipeline:
|
||||
|
||||
- **Main branch**: Tests run against existing snapshots
|
||||
- **Feature branches**: Tests run against existing snapshots
|
||||
- **Artifacts**: Test results and screenshots uploaded for review
|
||||
|
||||
### CI Best Practices
|
||||
|
||||
1. **Don't regenerate snapshots in CI** for feature branches
|
||||
2. **Use CI-generated snapshots** as the source of truth
|
||||
3. **Review screenshot diffs** in CI artifacts
|
||||
4. **Fail fast** on visual regressions
|
||||
|
||||
### Artifact Management
|
||||
|
||||
```yaml
|
||||
# Example CI artifact configuration
|
||||
- name: Upload visual regression results
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: visual-regression-results
|
||||
path: |
|
||||
test-results/
|
||||
tests/e2e/visual-regression.spec.ts-snapshots/
|
||||
```
|
||||
|
||||
## 🎯 Best Practices
|
||||
|
||||
### 1. Snapshot Management
|
||||
|
||||
- **Update snapshots only for intentional changes**
|
||||
- **Review all changes** before committing
|
||||
- **Use descriptive names** for snapshot files
|
||||
- **Keep snapshots in version control**
|
||||
|
||||
### 2. Test Design
|
||||
|
||||
- **Test critical UI components** first
|
||||
- **Use consistent viewport sizes** across tests
|
||||
- **Test responsive breakpoints** systematically
|
||||
- **Include interactive states** when relevant
|
||||
|
||||
### 3. Performance
|
||||
|
||||
- **Limit snapshot count** to essential components
|
||||
- **Use appropriate timeouts** for slow operations
|
||||
- **Parallelize tests** when possible
|
||||
- **Cache browser installations** in CI
|
||||
|
||||
### 4. Maintenance
|
||||
|
||||
- **Regular cleanup** of outdated snapshots
|
||||
- **Update snapshots promptly** after UI changes
|
||||
- **Monitor test execution time** and optimize
|
||||
- **Review and update tolerance settings** as needed
|
||||
|
||||
## 📚 Additional Resources
|
||||
|
||||
- **Main Testing Documentation**: [testing-framework.md](./testing-framework.md) | [testing.md](./testing.md)
|
||||
- **Playwright Visual Testing**: https://playwright.dev/docs/screenshots
|
||||
- **Visual Regression Best Practices**: https://storybook.js.org/docs/writing-tests/visual-testing
|
||||
- **CI/CD Integration**: [testing-quick-reference.md](./testing-quick-reference.md)
|
||||
- **Performance Guide**: [performance.md](./performance.md)
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: December 2024
|
||||
**Maintained by**: CommunityRule Development Team
|
||||
Reference in New Issue
Block a user