mirror of
https://github.com/BradGroux/veritas-kanban.git
synced 2026-10-06 19:57:50 +00:00
Merge 722cdeebe4 into ea352fcac9
This commit is contained in:
commit
ace0269f1e
4 changed files with 290 additions and 0 deletions
82
qa/mantine-migration-checklist.md
Normal file
82
qa/mantine-migration-checklist.md
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
# Mantine Migration QA Checklist
|
||||
|
||||
## Visual Coherence
|
||||
|
||||
- [ ] All components maintain consistent styling with existing design system
|
||||
- [ ] Typography hierarchy is preserved across all pages
|
||||
- [ ] Color palette matches brand guidelines
|
||||
- [ ] Spacing and alignment conform to design specifications
|
||||
- [ ] Responsive behavior works correctly on all screen sizes
|
||||
- [ ] Dark mode/light mode themes are properly implemented
|
||||
- [ ] Component states (hover, focus, active) display correctly
|
||||
- [ ] No visual regressions compared to previous implementation
|
||||
|
||||
## Accessibility
|
||||
|
||||
- [ ] All interactive elements have proper focus indicators
|
||||
- [ ] Keyboard navigation works seamlessly
|
||||
- [ ] ARIA labels and roles are correctly applied
|
||||
- [ ] Color contrast meets WCAG 2.1 AA standards
|
||||
- [ ] Screen reader compatibility verified
|
||||
- [ ] Form elements have proper labeling
|
||||
- [ ] Alt text provided for all relevant images
|
||||
- [ ] No accessibility violations in automated testing tools
|
||||
|
||||
## Performance
|
||||
|
||||
- [ ] Page load times are within acceptable thresholds
|
||||
- [ ] Bundle size does not exceed previous implementation
|
||||
- [ ] No new console errors or warnings
|
||||
- [ ] Memory usage remains stable during extended use
|
||||
- [ ] Component rendering performance is optimized
|
||||
- [ ] Lazy loading implemented where appropriate
|
||||
- [ ] Caching strategies are effective
|
||||
- [ ] Third-party dependencies do not impact performance negatively
|
||||
|
||||
## Cleanup Verification
|
||||
|
||||
- [ ] Deprecated code and components are removed
|
||||
- [ ] Unused CSS classes and styles are eliminated
|
||||
- [ ] Old component libraries are fully uninstalled
|
||||
- [ ] Configuration files updated to reflect new setup
|
||||
- [ ] Documentation updated to match current implementation
|
||||
- [ ] Test suites pass with new components
|
||||
- [ ] No breaking changes introduced to public APIs
|
||||
- [ ] Migration scripts execute successfully
|
||||
|
||||
## Cross-Browser Compatibility
|
||||
|
||||
- [ ] Chrome - latest version
|
||||
- [ ] Firefox - latest version
|
||||
- [ ] Safari - latest version
|
||||
- [ ] Edge - latest version
|
||||
- [ ] Mobile browsers (iOS Safari, Android Chrome)
|
||||
|
||||
## Integration Testing
|
||||
|
||||
- [ ] Authentication flows work correctly
|
||||
- [ ] Form submissions process without errors
|
||||
- [ ] API integrations maintain functionality
|
||||
- [ ] State management behaves as expected
|
||||
- [ ] Third-party service integrations remain stable
|
||||
|
||||
## User Acceptance Testing
|
||||
|
||||
- [ ] Core user workflows function as expected
|
||||
- [ ] Edge cases handled appropriately
|
||||
- [ ] Error states display helpful messages
|
||||
- [ ] User feedback incorporated where applicable
|
||||
|
||||
## Documentation
|
||||
|
||||
- [ ] Component usage documentation updated
|
||||
- [ ] Migration guide completed
|
||||
- [ ] Code examples reflect current implementation
|
||||
- [ ] Troubleshooting section includes common issues
|
||||
|
||||
## Final Verification
|
||||
|
||||
- [ ] Stakeholder review completed
|
||||
- [ ] All checklist items addressed
|
||||
- [ ] Sign-off obtained from product team
|
||||
- [ ] Release notes prepared
|
||||
87
scripts/cleanup-analysis.ts
Normal file
87
scripts/cleanup-analysis.ts
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
import fs from 'fs/promises';
|
||||
import path from 'path';
|
||||
import { glob } from 'glob';
|
||||
|
||||
interface AnalysisResult {
|
||||
unusedDependencies: string[];
|
||||
unusedCssVariables: string[];
|
||||
deadStyles: string[];
|
||||
}
|
||||
|
||||
async function analyzeDependencies(): Promise<AnalysisResult> {
|
||||
const result: AnalysisResult = {
|
||||
unusedDependencies: [],
|
||||
unusedCssVariables: [],
|
||||
deadStyles: []
|
||||
};
|
||||
|
||||
try {
|
||||
// Read package.json
|
||||
const packageJson = JSON.parse(await fs.readFile('package.json', 'utf-8'));
|
||||
const dependencies = { ...packageJson.dependencies, ...packageJson.devDependencies };
|
||||
|
||||
// Check for unused shadcn/Radix dependencies
|
||||
const shadcnDeps = Object.keys(dependencies).filter(dep =>
|
||||
dep.includes('shadcn') || dep.includes('@radix-ui')
|
||||
);
|
||||
|
||||
if (shadcnDeps.length > 0) {
|
||||
result.unusedDependencies = shadcnDeps;
|
||||
}
|
||||
|
||||
// Analyze CSS files for unused variables
|
||||
const cssFiles = await glob('src/**/*.css');
|
||||
|
||||
for (const file of cssFiles) {
|
||||
const content = await fs.readFile(file, 'utf-8');
|
||||
|
||||
// Find CSS variables
|
||||
const varMatches = content.match(/--[^:)]+:/g);
|
||||
if (varMatches) {
|
||||
result.unusedCssVariables.push(...varMatches.map(m => m.slice(0, -1)));
|
||||
}
|
||||
}
|
||||
|
||||
// Analyze for dead styles
|
||||
const tsFiles = await glob('src/**/*.{ts,tsx}');
|
||||
|
||||
for (const file of tsFiles) {
|
||||
const content = await fs.readFile(file, 'utf-8');
|
||||
|
||||
// Look for classNames that might be dead styles
|
||||
const classMatches = content.match(/className="[^"]*"/g);
|
||||
if (classMatches) {
|
||||
result.deadStyles.push(...classMatches);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.error('Analysis failed:', error);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
async function main() {
|
||||
console.log('Starting cleanup analysis...');
|
||||
|
||||
const results = await analyzeDependencies();
|
||||
|
||||
console.log('\n=== Cleanup Analysis Results ===');
|
||||
console.log('\nUnused Dependencies:');
|
||||
results.unusedDependencies.forEach(dep => console.log(` - ${dep}`));
|
||||
|
||||
console.log('\nPotential Unused CSS Variables:');
|
||||
results.unusedCssVariables.forEach(variable => console.log(` - ${variable}`));
|
||||
|
||||
console.log('\nPotential Dead Styles:');
|
||||
results.deadStyles.forEach(style => console.log(` - ${style}`));
|
||||
|
||||
console.log('\nAnalysis complete.');
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
main();
|
||||
}
|
||||
|
||||
export { analyzeDependencies, AnalysisResult };
|
||||
77
tests/e2e/accessibility-qc.spec.ts
Normal file
77
tests/e2e/accessibility-qc.spec.ts
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
import { test, expect } from '@playwright/test';
|
||||
import { AxeBuilder } from '@axe-core/playwright';
|
||||
|
||||
test.describe('Accessibility Quality Control', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/');
|
||||
});
|
||||
|
||||
test('should have no automatically detectable accessibility issues', async ({ page }) => {
|
||||
const accessibilityScanResults = await new AxeBuilder({ page })
|
||||
.withTags(['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa'])
|
||||
.analyze();
|
||||
|
||||
expect(accessibilityScanResults.violations).toEqual([]);
|
||||
});
|
||||
|
||||
test('should have proper keyboard navigation', async ({ page }) => {
|
||||
// Check focus management on interactive elements
|
||||
await page.keyboard.press('Tab');
|
||||
const firstFocusable = await page.locator('*:focus');
|
||||
await expect(firstFocusable).toBeVisible();
|
||||
|
||||
// Check that focus moves through interactive elements
|
||||
await page.keyboard.press('Tab');
|
||||
const secondFocusable = await page.locator('*:focus');
|
||||
await expect(secondFocusable).toBeVisible();
|
||||
});
|
||||
|
||||
test('should have sufficient color contrast', async ({ page }) => {
|
||||
const accessibilityScanResults = await new AxeBuilder({ page })
|
||||
.withTags(['wcag2a', 'wcag2aa'])
|
||||
.include(['.text-primary', '.bg-primary', 'button', 'a'])
|
||||
.analyze();
|
||||
|
||||
const contrastViolations = accessibilityScanResults.violations.filter(
|
||||
violation => violation.id === 'color-contrast'
|
||||
);
|
||||
|
||||
expect(contrastViolations).toEqual([]);
|
||||
});
|
||||
|
||||
test('should have proper focus indicators', async ({ page }) => {
|
||||
await page.keyboard.press('Tab');
|
||||
const focusedElement = await page.locator('*:focus');
|
||||
|
||||
// Check that focused element has visible focus indicator
|
||||
const outlineWidth = await focusedElement.evaluate(el => {
|
||||
return window.getComputedStyle(el).outlineWidth;
|
||||
});
|
||||
|
||||
expect(outlineWidth).not.toBe('0px');
|
||||
});
|
||||
|
||||
test('should have accessible labels for form elements', async ({ page }) => {
|
||||
const accessibilityScanResults = await new AxeBuilder({ page })
|
||||
.withRules(['label'])
|
||||
.analyze();
|
||||
|
||||
const labelViolations = accessibilityScanResults.violations.filter(
|
||||
violation => violation.id === 'label'
|
||||
);
|
||||
|
||||
expect(labelViolations).toEqual([]);
|
||||
});
|
||||
|
||||
test('should have proper heading structure', async ({ page }) => {
|
||||
const accessibilityScanResults = await new AxeBuilder({ page })
|
||||
.withRules(['heading-order'])
|
||||
.analyze();
|
||||
|
||||
const headingViolations = accessibilityScanResults.violations.filter(
|
||||
violation => violation.id === 'heading-order'
|
||||
);
|
||||
|
||||
expect(headingViolations).toEqual([]);
|
||||
});
|
||||
});
|
||||
44
tests/e2e/visual-qc.spec.ts
Normal file
44
tests/e2e/visual-qc.spec.ts
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
import { test, expect } from '@playwright/test';
|
||||
|
||||
test.describe('Visual Quality Control Tests', () => {
|
||||
[
|
||||
{ name: 'Board View', path: '/' },
|
||||
{ name: 'Task Detail', path: '/task/1' },
|
||||
{ name: 'Create Task', path: '/create-task' },
|
||||
].forEach(({ name, path }) => {
|
||||
['light', 'dark'].forEach((theme) => {
|
||||
['desktop', 'tablet', 'mobile'].forEach((viewport) => {
|
||||
test(`${name} - ${theme} mode - ${viewport}`, async ({ page }) => {
|
||||
// Set viewport
|
||||
switch (viewport) {
|
||||
case 'mobile':
|
||||
await page.setViewportSize({ width: 375, height: 667 });
|
||||
break;
|
||||
case 'tablet':
|
||||
await page.setViewportSize({ width: 768, height: 1024 });
|
||||
break;
|
||||
default: // desktop
|
||||
await page.setViewportSize({ width: 1280, height: 800 });
|
||||
}
|
||||
|
||||
// Set theme
|
||||
await page.addInitScript((theme) => {
|
||||
window.localStorage.setItem('theme', theme);
|
||||
}, theme);
|
||||
|
||||
// Navigate to page
|
||||
await page.goto(path);
|
||||
|
||||
// Wait for page to load
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
// Take screenshot
|
||||
await expect(page).toHaveScreenshot({
|
||||
fullPage: true,
|
||||
maxDiffPixelRatio: 0.01
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Reference in a new issue