Build a systematic design QA process that fits within sprint cycles — automated visual regression with Chromatic, structured designer review sessions, developer self-QA checklists, and a finding tracking workflow.
Design QA without a process becomes a bottleneck — designers spend hours catching issues that could be caught automatically, and developers get lists of vague feedback without actionable fixes. A structured QA process changes this: automated regression catches regressions instantly, developer self-QA eliminates obvious issues, and structured designer sessions focus on decisions only humans can make.
This lesson builds a complete QA process that fits within a 2-week sprint cycle without consuming more than 4 hours of combined design and development time per sprint.
Chromatic integrates with Storybook to screenshot every component story and flag visual differences when code changes. It catches regressions automatically — no manual scanning needed.
Setup:
1# Install Storybook if not already present
2npx storybook init
3
4# Install Chromatic
5npm install -D chromatic
6
7# Run Chromatic (first run creates baseline)
8npx chromatic --project-token=YOUR_TOKENGitHub Actions integration:
1# .github/workflows/chromatic.yml
2name: Chromatic Visual QA
3on: [push]
4jobs:
5 chromatic:
6 runs-on: ubuntu-latest
7 steps:
8 - uses: actions/checkout@v4
9 with: { fetch-depth: 0 }
10 - uses: actions/setup-node@v4
11 - run: npm ci
12 - uses: chromaui/action@latest
13 with:
14 projectToken: ${{ secrets.CHROMATIC_TOKEN }}
15 exitZeroOnChanges: true # don't fail CI on visual changesChromatic workflow:
What Chromatic catches automatically:
What Chromatic does NOT catch:
Storybook story structure for good Chromatic coverage:
1// Button.stories.tsx — cover all states for Chromatic
2export const AllStates: Story = {
3 render: () => (
4 <div style={{ display: 'flex', flexDirection: 'column', gap: '1rem' }}>
5 <Button variant="primary">Default</Button>
6 <Button variant="primary" data-hover>Hover simulation</Button>
7 <Button variant="primary" disabled>Disabled</Button>
8 <Button variant="primary" loading>Loading</Button>
9 </div>
10 )
11};A developer who catches their own issues before designer review saves the most expensive handoff time — designers re-reviewing fixed issues.
Developer self-QA checklist (complete before PR submission):
1# Developer Self-QA Checklist
2
3## Layout
4[ ] Tested at 375px, 768px, 1024px, 1440px viewport widths
5[ ] No horizontal scroll at any width
6[ ] Grid columns match design at each breakpoint
7[ ] Component dimensions match Figma (±2px tolerance)
8
9## Typography
10[ ] Font family loads correctly (Network tab: Inter downloaded?)
11[ ] Font-weight values are numeric (not 'bold' or 'normal' keywords)
12[ ] Line-height is unitless ratio (not fixed px)
13[ ] Font sizes match rem conversion of Figma px values
14
15## Colors
16[ ] Background colors match Figma Inspect hex values
17[ ] Text colors match (check computed, not declared)
18[ ] Border colors match
19[ ] All colors from design tokens (no hardcoded one-offs)
20
21## Interactive States
22[ ] Hover state: background or color change visible
23[ ] Hover transition: smooth, not instant
24[ ] Focus ring visible when tabbing to every interactive element
25[ ] Active/pressed state visible on click+hold
26[ ] Disabled state: visual indication + cursor: not-allowed
27[ ] Loading state: spinner visible, label hidden or transparent
28[ ] Error state: red border + error message visible
29
30## Accessibility
31[ ] Tabbed through all interactive elements: accessible in order
32[ ] All form inputs have visible labels
33[ ] Images have alt text
34[ ] No keyboard traps (can always Tab away from any element)
35[ ] Screen reader: VoiceOver/NVDA announces component correctly
36
37## Browser Testing
38[ ] Chrome: pass
39[ ] Firefox: pass
40[ ] Safari: pass (if macOS available)Time estimate: 20-30 minutes for a typical page, 10-15 minutes for a component.
Tools to speed up self-QA:
A structured designer QA session maximizes coverage per hour by following a sequence: page-level scan first, then component-level detail, then interactive states.
QA session agenda:
10:00 — 0:10: Page-level scan (10 min)
2 - Screenshot the page at 1440px
3 - Compare side-by-side with Figma artboard
4 - Identify obvious layout differences
5 - Note: sections that look 'right at a glance' → skip component QA
6 - Note: sections with visible differences → focus next steps here
7
80:10 — 0:35: Component-level check (25 min)
9 - For each section with differences:
10 - Select component element → DevTools Computed values
11 - Compare with Figma Inspect values
12 - Document: spec vs actual for each finding
13 - For components that look correct: spot-check one value per component
14 - Focus: typography (font-weight most commonly wrong)
15
160:35 — 0:50: Interactive state testing (15 min)
17 - Hover every interactive element (button, link, card, input)
18 - Tab through the entire page (focus rings)
19 - Activate error state on form inputs (wrong input data)
20 - Test loading state if triggered by button click
21
220:50 — 1:00: Document and prioritize (10 min)
23 - Write findings in GitHub Issues (or Linear)
24 - Assign severity: Critical / High / Low
25 - Tag with sprint number and page name
26 - Add Figma link to the specific element for contextQA session tools:
QA findings that are not systematically tracked get lost, forgotten, or duplicated. A GitHub Issues-based workflow keeps findings visible, assigned, and resolved.
GitHub Issue template for QA findings:
1---
2name: Design QA Finding
3about: Visual implementation discrepancy
4labels: design-qa
5---
6
7## Component
8[Component name and location on page]
9
10## Issue
11[What is wrong — be specific about which property]
12
13## Specification
14[Value from Figma Inspect with link to component]
15
16## Actual
17[Value from browser DevTools Computed]
18
19## Screenshots
20[Attach: Figma artboard screenshot and browser screenshot side-by-side]
21
22## Fix/* Exact CSS fix to apply */
1
2## Severity
3- [ ] Critical (accessibility, wrong brand color)
4- [ ] High (wrong component state, spacing > 8px)
5- [ ] Low (minor, < 4px difference)Tracking QA findings in a sprint:
1Label: design-qa → filter all design QA issues
2Label: sprint-3 → filter by sprint
3Label: severity-critical → filter urgent issues
4Label: severity-high → filter significant issues
5Assigned to: developer → developer responsibility
6Milestone: Sprint 3 QA → sprint trackingQA finding lifecycle:
1Open → Designer creates issue with finding + fix
2In Progress → Developer assigned, working on fix
3Review → Fix PR submitted
4Closed → Designer confirms fix in staging, closes issueQA sign-off criteria:
QA tracking dashboard (GitHub Project):
1Columns: Open | In Progress | In Review | Closed
2Filter: label:design-qa milestone:'Sprint 3 QA'
3View: Table with Severity column sortableA complete QA workflow for a sprint implementing the course detail page — automated, self-QA, and structured designer session.
1/* QA INTEGRATION: Sprint 3 — Course Detail Page
2
3=== AUTOMATED: Chromatic (continuous) ===
4
5Storybook stories covering:
6 CourseCard/Default
7 CourseCard/Hover (using args: { 'data-hover': true })
8 CourseCard/Enrolled
9 LessonItem/Default
10 LessonItem/Completed
11 LessonItem/Active
12 EnrollButton/Default
13 EnrollButton/Loading
14 EnrollButton/Enrolled
15 EnrollButton/Disabled
16
17Chromatic result (PR #342):
18 15 unchanged stories → auto-approved
19 3 changed stories → flagged for review:
20 EnrollButton/Default → background color changed
21 ACCEPT: intentional (brand color update)
22 LessonItem/Active → border-left color changed
23 ACCEPT: intentional (theme update)
24 CourseCard/Default → title font-weight changed
25 DENY: unintended regression (was changed in global CSS reset)
26
27Developer action: Fix font-weight regression before merge ✓
28
29=== DEVELOPER SELF-QA (30 minutes, 2 days before demo) ===
30
31Checklist results:
32 Layout: ✓ (tested at 375, 768, 1024, 1440 — all correct)
33 Typography:
34 ✗ FOUND: .lesson-item__title font-weight: 400 (spec: 500)
35 ✗ FOUND: .instructor-name font-size: 1rem (spec: 0.875rem = 14px)
36 Colors: ✓ (all match Figma)
37 States:
38 ✓ Hover states working
39 ✗ FOUND: No focus ring on .lesson-item (missing :focus-visible style)
40 ✓ Disabled enrollment button correct
41 Accessibility:
42 ✗ FOUND: Course thumbnail alt text is 'Image' (not descriptive)
43 Browser:
44 ✓ Chrome, Firefox
45 ✗ Safari: lesson scroll container horizontal scroll broken
46 (needs -webkit-overflow-scrolling: touch)
47
48Issues filed by developer:
49 #347: lesson-item font-weight incorrect (found self-QA)
50 #348: instructor name font-size incorrect (found self-QA)
51 #349: lesson-item missing focus-visible (found self-QA)
52 #350: thumbnail alt text not descriptive (found self-QA)
53 #351: Safari horizontal scroll fix needed (found self-QA)
54
55Fixes applied (2 hours):
56 .lesson-item__title { font-weight: 500; }
57 .instructor-name { font-size: 0.875rem; }
58 .lesson-item:focus-visible { outline: 2px solid #2563eb; outline-offset: 2px; }
59 /* thumbnail alt: updated in React prop to course.title + description */
60 .recommendation-scroll { -webkit-overflow-scrolling: touch; }
61
62=== DESIGNER QA SESSION (60 min, day before demo) ===
63
64Page scan result:
65 - Hero: ✓ match Figma
66 - Course info: small deviation in instructor section → investigate
67 - Lesson list: ✓ (already fixed by self-QA)
68 - Enrollment section: ✓
69
70Component-level findings:
71 FINDING #352: Instructor section layout
72 Issue: avatar margin 12px right (spec: 16px)
73 Spec: gap: 16px (Figma: gap: 16px)
74 Actual: gap: 0.75rem = 12px (computed)
75 Severity: Low
76 Fix: .instructor-card { gap: 1rem; } /* was 0.75rem */
77
78 FINDING #353: Course progress bar height
79 Issue: progress track 3px (spec: 4px)
80 Severity: Low
81 Fix: .progress-track { height: 0.25rem; } /* was 3px → 0.25rem */
82
83Interactive states:
84 ✓ All hover states working
85 ✓ Focus rings visible on all interactive elements
86 ✓ Enrollment loading state correct
87
88QA SESSION RESULT:
89 2 Low findings (#352, #353)
90 Both fixed in 15 minutes
91 QA SIGN-OFF: ✓ Sprint 3 Course Detail — approved for release
92
93Total QA time this sprint:
94 Chromatic automated: 0 min (runs in CI)
95 Developer self-QA: 30 min
96 Issue filing and fixing (self-QA): 120 min
97 Designer QA session: 60 min
98 Designer finding fixes: 15 min
99 TOTAL: ~3.5 hours combined for 5 developer + 1 designer
100*/The workflow shows progressive QA gates: Chromatic catches the font-weight regression automatically before it even reaches manual QA. Developer self-QA finds 5 issues that would have been designer QA findings, saving designer time. Designer QA then focuses on decisions only they can make (layout precision, spacing judgement). Total QA time was 3.5 hours for a full page — without this process, a similar page might require 2-3 hours of designer QA alone, plus async finding resolution over days.
The next lesson covers Design Critiques — how to structure design critique sessions that produce actionable feedback rather than subjective opinions, and how developers can participate productively in design review.
Your progress is saved in this browser, on this device only.