143cc458c1
Q.DEFER.002 sub-B closure: manual Pa11y audit-pass via Playwright MCP login + axe-core CDN inject on 16 auth-required views. Found ~13 unique violation patterns, 12 fixed, 3 deferred to Q.DEFER.004. ROOT CAUSE found: AdminLayout `<v-navigation-drawer color="secondary" theme="dark">` resolved to Vuetify default-dark `secondary=#54b6b2` (Teal mid) instead of liderraForest `#012019` теало-нуар. Switching to direct hex preserves design intent + restores white-text contrast across all 8 admin views (~50 nodes color-contrast violations cleared). Patterns fixed: 1. AdminLayout sidebar palette (8 admin views): - color="secondary" → color="#012019" (root cause) - .brand-sub red #b94837 → #e06155 (3.41 → 5.08) - .nav-count gray #7a8c87 → #8a9c95 (4.26 → 5.34) - <v-list nav> + role="navigation" + aria-label (aria-required-children fix: <v-list role=list> had [role=link] children — undefined для list) 2. DashboardBalance .runway-bar — role="img" (aria-prohibited-attr fix) 3. DashboardKpiRow .delta-up — #2e8b57 → #1b6e3b (4.27 → 6.25) 4. TransactionsTable .tx-amount-up — #2e8b57 → #1b6e3b (same fix) 5. RemindersList .empty-hint — #9a9690 → #6b6356 (2.98 → 5.74; +liderra-muted alignment) 6. KanbanView .kanban-board — tabindex="0" role="region" aria-label (scrollable-region-focusable fix) 7. ProjectCard: - .v-progress-linear + :aria-label="Прогресс дневной нормы: N%" - icon menu :aria-label="Меню действий проекта «...»" - bulk-select .card-check input :aria-label="Выбрать проект «...»" 8. useStatusPill in_progress #3F7C95 → #2A5A6E (4.07 → 6.11); useStatusPill.spec.ts sync 9. ProjectsView toolbar select-all input aria-label 10. AdminTenants impersonate v-btn aria-label 11. Global app.css: `.v-messages, .v-field-label { --v-medium-emphasis-opacity: 0.7; }` Vuetify default ~0.52 → rendered #7a7a7a/#767471 fails 4.20-4.29:1; 0.7 → rendered ≈#595959 → 7.9:1+ passes WCAG AA. Re-verified post-fix via axe-core on all affected views: all clean except DEV-only `.dev-index-num` chip (tree-shaked в prod, not a real violation). Vitest verified post-fix: 79 files / 614 passed / 3 skipped / 0 failed (baseline preserved). 3 patterns deferred to Q.DEFER.004: - DealsTable VDataTable show-select bulk-checkboxes (6 nodes) — Vuetify slot rewrite needed - AdminSupplierPrices 9 form inputs — v-text-field/v-switch label props - Vuetify v-tooltip eager-mount aria-tooltip-name — library-level cosmetic Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
53 lines
2.2 KiB
TypeScript
53 lines
2.2 KiB
TypeScript
import { describe, it, expect } from 'vitest';
|
|
import { useStatusPill, STATUS_PILL_SLUGS } from '../../resources/js/composables/useStatusPill';
|
|
|
|
describe('useStatusPill', () => {
|
|
it('exposes exactly 14 known slugs', () => {
|
|
expect(STATUS_PILL_SLUGS).toHaveLength(14);
|
|
expect(STATUS_PILL_SLUGS).toEqual(
|
|
expect.arrayContaining([
|
|
'new',
|
|
'in_progress',
|
|
'callback',
|
|
'quality',
|
|
'meeting_set',
|
|
'won',
|
|
'refund',
|
|
'duplicate',
|
|
'junk',
|
|
'no_answer',
|
|
'cancelled',
|
|
'closed',
|
|
'postponed',
|
|
'archived',
|
|
]),
|
|
);
|
|
});
|
|
|
|
it.each([
|
|
['new', { bg: 'rgba(15,110,86,0.12)', color: '#0F6E56' }],
|
|
['in_progress', { bg: 'rgba(63,124,149,0.12)', color: '#2A5A6E' }],
|
|
['callback', { bg: 'rgba(217,164,65,0.18)', color: '#A07820' }],
|
|
['quality', { bg: 'rgba(46,139,87,0.15)', color: '#2E8B57' }],
|
|
['meeting_set', { bg: 'rgba(122,91,163,0.15)', color: '#7A5BA3' }],
|
|
['won', { bg: 'rgba(46,139,87,0.22)', color: '#1F6940', fontWeight: 600 }],
|
|
['refund', { bg: 'rgba(204,110,80,0.15)', color: '#B0563D' }],
|
|
['duplicate', { bg: 'rgba(1,32,25,0.08)', color: '#3A3A3A' }],
|
|
['junk', { bg: 'rgba(184,58,58,0.10)', color: '#B83A3A' }],
|
|
['no_answer', { bg: 'rgba(107,99,86,0.15)', color: '#6B6356' }],
|
|
['cancelled', { bg: 'rgba(107,99,86,0.18)', color: '#6B6356', textDecoration: 'line-through' }],
|
|
['closed', { bg: 'rgba(1,32,25,0.10)', color: '#3A3A3A' }],
|
|
['postponed', { bg: 'rgba(15,110,86,0.06)', color: '#6B6356' }],
|
|
['archived', { bg: '#012019', color: '#E8E2D4' }],
|
|
])('returns correct tokens for %s', (slug, expected) => {
|
|
const result = useStatusPill(slug);
|
|
expect(result).toMatchObject(expected);
|
|
});
|
|
|
|
it('falls back to a neutral style for unknown slug', () => {
|
|
const result = useStatusPill('unknown_slug');
|
|
expect(result.bg).toMatch(/rgba\(1, ?32, ?25/);
|
|
expect(result.color).toBeDefined();
|
|
});
|
|
});
|