From a53d3b8229b6a927107fc262d05f47f0119ae0bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=82n=20=C4=90o=C3=A0n?= <33853760+andoan16@users.noreply.github.com> Date: Sun, 31 May 2026 10:25:10 +0700 Subject: [PATCH 1/4] =?UTF-8?q?fix:=20resolve=20#418=20=E2=80=94=20v5.0=20?= =?UTF-8?q?QA:=20Mantine=20migration=20visual,=20accessibility,=20and=20cl?= =?UTF-8?q?eanup=20gate?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #418 Signed-off-by: Ân Đoàn <33853760+andoan16@users.noreply.github.com> --- qa/mantine-migration-checklist.md | 82 +++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 qa/mantine-migration-checklist.md diff --git a/qa/mantine-migration-checklist.md b/qa/mantine-migration-checklist.md new file mode 100644 index 00000000..db023307 --- /dev/null +++ b/qa/mantine-migration-checklist.md @@ -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 \ No newline at end of file From b79a937c03e94f50d7c42769f2e9bc9641289f07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=82n=20=C4=90o=C3=A0n?= <33853760+andoan16@users.noreply.github.com> Date: Sun, 31 May 2026 10:25:11 +0700 Subject: [PATCH 2/4] =?UTF-8?q?fix:=20resolve=20#418=20=E2=80=94=20v5.0=20?= =?UTF-8?q?QA:=20Mantine=20migration=20visual,=20accessibility,=20and=20cl?= =?UTF-8?q?eanup=20gate?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #418 Signed-off-by: Ân Đoàn <33853760+andoan16@users.noreply.github.com> --- tests/e2e/visual-qc.spec.ts | 44 +++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 tests/e2e/visual-qc.spec.ts diff --git a/tests/e2e/visual-qc.spec.ts b/tests/e2e/visual-qc.spec.ts new file mode 100644 index 00000000..569179b3 --- /dev/null +++ b/tests/e2e/visual-qc.spec.ts @@ -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 + }); + }); + }); + }); + }); +}); \ No newline at end of file From fd4b65a568d968740cae007c064c66f723b7269e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=82n=20=C4=90o=C3=A0n?= <33853760+andoan16@users.noreply.github.com> Date: Sun, 31 May 2026 10:25:12 +0700 Subject: [PATCH 3/4] =?UTF-8?q?fix:=20resolve=20#418=20=E2=80=94=20v5.0=20?= =?UTF-8?q?QA:=20Mantine=20migration=20visual,=20accessibility,=20and=20cl?= =?UTF-8?q?eanup=20gate?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #418 Signed-off-by: Ân Đoàn <33853760+andoan16@users.noreply.github.com> --- tests/e2e/accessibility-qc.spec.ts | 77 ++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 tests/e2e/accessibility-qc.spec.ts diff --git a/tests/e2e/accessibility-qc.spec.ts b/tests/e2e/accessibility-qc.spec.ts new file mode 100644 index 00000000..5996d9b7 --- /dev/null +++ b/tests/e2e/accessibility-qc.spec.ts @@ -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([]); + }); +}); \ No newline at end of file From 722cdeebe4226fc7a07baa0bf8300524e5656e6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=82n=20=C4=90o=C3=A0n?= <33853760+andoan16@users.noreply.github.com> Date: Sun, 31 May 2026 10:25:13 +0700 Subject: [PATCH 4/4] =?UTF-8?q?fix:=20resolve=20#418=20=E2=80=94=20v5.0=20?= =?UTF-8?q?QA:=20Mantine=20migration=20visual,=20accessibility,=20and=20cl?= =?UTF-8?q?eanup=20gate?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #418 Signed-off-by: Ân Đoàn <33853760+andoan16@users.noreply.github.com> --- scripts/cleanup-analysis.ts | 87 +++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 scripts/cleanup-analysis.ts diff --git a/scripts/cleanup-analysis.ts b/scripts/cleanup-analysis.ts new file mode 100644 index 00000000..fc0e0b33 --- /dev/null +++ b/scripts/cleanup-analysis.ts @@ -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 { + 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 }; \ No newline at end of file