| name | noir-test-flow |
| description | Visual + behavioral testing protocol for NOIR โ triple-mode checks (light/dark/VI/responsive), interactive element testing, data consistency verification, and bug fix workflow. Used by /noir-qa orchestrator. |
NOIR Test Flow โ Visual + Behavioral Testing Protocol
Purpose: Defines HOW to test each page/feature. Called by /noir-qa and /noir-qa-run or used standalone.
Standalone usage: /noir-test-flow โ applies the full protocol to a specific page or set of pages.
As sub-protocol: Referenced by /noir-qa Phase 4 (Execution) and /noir-qa-run Execute phase.
CORE PRINCIPLE
"If a human QA engineer would catch it, you must catch it."
Dark mode, Vietnamese, and responsive are NOT separate phases โ they are tested on EVERY visual state (page, tab, dialog, popup). This catches the bugs that single-mode testing misses.
TRIPLE-MODE VISUAL AUDIT (Page Level)
For each page's initial view, execute 4 modes:
Light Mode (Baseline)
1. browser_navigate โ page URL (or SPA sidebar click โ see Technical Notes)
2. browser_wait_for โ network idle / specific element visible
3. browser_take_screenshot โ temp/qa-{page}-light.png
4. READ screenshot and analyze:
- Layout: alignment, spacing, overflow, content clipping
- Components: broken images, missing icons, wrong empty states
- Typography: font consistency, text truncation, ellipsis working
- Colors: theme consistency, contrast, hover states visible
- Loading: skeleton โ data (no flash of empty)
- Card shadows: shadow-sm + hover:shadow-lg per design standard
Dark Mode
5. browser_evaluate โ document.documentElement.classList.add('dark')
6. browser_take_screenshot โ temp/qa-{page}-dark.png
7. READ screenshot and verify:
- Text readable (no white-on-white, no black-on-black)
- Borders visible (not disappearing into background)
- Status badges maintain contrast
- Charts/graphs readable
- No hardcoded colors overriding theme variables
- Input fields: background distinguishable from page background
- Dropdown menus / popovers: correct dark background (not white)
Vietnamese
8. browser_evaluate โ localStorage.setItem('i18nextLng','vi'); location.reload()
9. browser_wait_for โ content loaded
10. browser_take_screenshot โ temp/qa-{page}-vi.png
11. READ screenshot and verify:
- No raw i18n keys (e.g., "products.searchPlaceholder" as literal text)
- No English text remaining (except allowed: CRM, API, SMTP, Blog)
- No text overflow from longer Vietnamese strings (buttons, headers, labels)
- Date format matches Vietnamese locale (DD/MM/YYYY)
- Sidebar labels are pure Vietnamese (no "Blog Posts", must be "Bร i viแบฟt")
- Vietnamese + dark mode: switch to dark briefly โ screenshot โ verify no issues
- Switch back to light mode after
Responsive
12. Restore to light mode + English before responsive checks
13. For each viewport [1440, 1024, 768]:
- browser_resize โ {width}px
- browser_take_screenshot โ temp/qa-{page}-{width}px.png
- READ and verify:
- 1440: full layout, sidebar visible, all columns shown
- 1024: sidebar may collapse, table columns may hide, no overflow
- 768: mobile/tablet layout, content stacks vertically, no horizontal scroll on body
- Specific: tables horizontal scroll within container, buttons not cut off,
cards stack vertically, PageHeader wraps correctly, search remains usable
14. browser_resize โ restore 1440px
MINI TRIPLE CHECK (Element Level)
For EACH interactive element type on the page. Every distinct visual state gets this protocol:
- Screenshot in light mode (baseline)
- Switch to dark mode โ screenshot โ verify: text readable, borders visible, inputs distinguishable
- Switch to Vietnamese โ screenshot โ verify: all text translated, no overflow, no raw i18n keys
- Resize to 768px โ screenshot โ verify: layout adapts, content accessible, no overflow
- Restore light mode + English + 1440px before proceeding
Required Visual States (100% Matrix)
| Visual State | Light | Dark | VI | 768px | Notes |
|---|
| Each TAB content | โ
| โ
| โ
| โ
| Different content layout per tab |
| Create dialog | โ
| โ
| โ
| โ
| Form fields, buttons, footer |
| Edit dialog | โ
| โ
| โ
| โ
| May differ from create (pre-populated) |
| Detail/View dialog | โ
| โ
| โ
| โ
| Read-only content, labels |
| Confirmation dialog | โ
| โ
| โ
| โ
| Destructive button styling, text |
| Filter popover | โ
| โ
| โ
| โ
| Dropdown options, filter labels |
| Empty state | โ
| โ
| โ
| โ
| Icon, title, description text |
| Error banner (FormErrorBanner) | โ
| โ
| โ
| โ
| Banner background, error text |
| Validation errors on form | โ
| โ
| โ
| โ
| Error text color vs input bg |
| Toast/notification | โ
| โ
| โ
| โ
| Background contrast, text, position |
| Date picker popup | โ
| โ
| โ
| โ
| Month/day names, calendar grid bg |
Dropdown menu (actions โฎ) | โ
| โ
| โ
| โ
| Menu item text, background, hover |
| Select/Combobox dropdown | โ
| โ
| โ
| โ
| Option labels, search, selected state |
| Color picker popup | โ
| โ
| โ
| โ
| Color swatch visibility in dark |
| Loading/skeleton state | โ
| โ
| โ | โ
| Skeleton colors in dark (no text) |
| Bulk action toolbar | โ
| โ
| โ
| โ
| Selection count, action buttons |
| Tooltip (on icon buttons) | โ
| โ
| โ
| โ | Content, background (cursor-attached) |
Efficiency: Shared components (DataTablePagination, etc.) need full Mini Triple Check only on FIRST occurrence. Subsequent pages: quick dark mode spot-check. Page-specific dialogs/tabs: always full check.
INTERACTIVE ELEMENT TESTING
Tables (DataTable)
- Column headers render correctly, all have labels
- Sort: click each sortable column header, verify order + indicator
- Pagination: page 2, change page size, verify "Showing X of Y" updates
- Search: type query โ verify filtering โ clear โ verify reset
- Column visibility: open dropdown, hide column, verify gone, show back
- Column reorder: if supported, drag column, verify new order
- Density toggle: switch compact/normal/comfortable if available
- Empty state: search nonsense โ verify
<EmptyState> component (not plain text)
โ Mini Triple Check on empty state
- Row selection: check/uncheck rows, verify bulk action toolbar appears
- Actions dropdown: click
โฎ โ verify menu items โ verify each action works
- Group by: if supported, group โ verify group headers with correct count
Forms (Create/Edit Dialogs)
- Open Create dialog โ screenshot โ Mini Triple Check
- Field-by-field testing for EVERY field:
- Focus โ verify focus ring/border
- Tab to next โ verify tab order (top-to-bottom, left-to-right)
- Required fields โ verify red asterisk
* on label
- Type invalid โ blur โ verify error (NOT while typing)
- Type valid โ verify error clears
- Dropdowns: open โ select โ verify selection
- Date pickers: open โ select โ verify format. Dark mode: calendar popup screenshot
- Rich text editors: type โ verify toolbar works
- File uploads: upload โ verify preview
- Color pickers: select โ verify preview
- Submit empty โ verify ALL required field errors at once
- Submit invalid โ verify specific field errors (not generic toast)
- Submit valid โ verify: toast + dialog closes + list updates + data matches
- Cancel โ closes, no data changed
- Click outside โ closes (Credenza behavior)
- ESC โ closes
- Edit mode: open existing โ verify fields pre-populated โ Mini Triple Check
Filters
- Apply each filter individually โ verify results update
- Apply combination โ verify AND logic
- Verify active filter indicator/badge shows count
- Clear individual โ verify results update
- Clear all โ verify full reset
- Filter persists across pagination
Destructive Actions
- Click delete/archive โ verify confirmation dialog appears (NEVER instant delete)
- Mini Triple Check on confirmation dialog
- Cancel โ nothing changed
- Confirm โ item removed/updated + toast + related data updated + activity timeline
Tabs
- For EACH tab:
- Click tab โ verify content loads
- Verify URL updates with
?tab=xxx
- Mini Triple Check on tab content
- Direct-navigate to
?tab=xxx โ verify correct tab active + content loaded
- Verify no flash/flicker on tab switch
Messages & Notifications
- Toasts: trigger success action โ verify position, auto-dismiss, text โ Mini Triple Check
- Error banners: trigger server error โ verify shows, dismiss works, clears on retry โ Mini Triple Check
- Validation messages: submit invalid โ verify under field โ Mini Triple Check
- Date picker popup: open โ verify calendar โ Mini Triple Check
- Select/Combobox: open โ verify options โ Mini Triple Check
- Tooltip: hover icon button โ verify shows โ Dark + VI check (no resize needed)
Navigation
- Breadcrumbs: correct path, each segment clickable
- Sidebar: current page highlighted
- Back navigation: browser back works correctly
- Deep link: navigate to URL directly โ verify same state loads
DATA CONSISTENCY CHECKS
After EACH CRUD operation, verify:
Create
- Item appears in list with correct data
- List total count incremented
- Dashboard widgets updated (if applicable)
- Activity timeline shows "Created ..." entry
- Related entities reflect change (e.g., department employee count)
- Search returns the new item
Edit
- ALL changed fields persisted (re-open edit dialog to verify)
- List row updated with new values
- Detail page (if exists) shows updated data
- Activity timeline shows "Updated ..." entry
- Related views reflect change
Delete (Soft)
- Item removed from active list
- List total count decremented
- Related entities updated (counts, references)
- Activity timeline shows "Deleted ..." entry
- Dashboard widgets updated
CROSS-FEATURE FLOW TEMPLATES
Use these as templates when creating flow definitions in .qa/flows/.
Flow: Product โ Order โ Payment Lifecycle
Create Product โ Add Variants โ Set Inventory (StockIn, confirm)
โ Dashboard product count increased
โ Create Customer โ Create Order with product variant
โ Confirm โ inventory decreased โ Process โ Ship โ Deliver โ Complete
โ Payment in Payments list with correct amount
โ Revenue in Dashboard
โ Customer writes Review โ Approve โ review count on product detail
Flow: Customer Journey
Create Customer โ Add to Group โ group count updated
โ Create Order โ Customer Detail โ order in history tab
โ Cancel order โ status updates in: Order detail, Customer history, Dashboard
โ Activity Timeline shows all actions with correct descriptions
โ Vietnamese โ activity descriptions translated
Flow: Content Publishing
Create Blog Category โ Create Blog Tags (2+)
โ Create Post with image โ Assign category + tags โ Draft
โ Media Library shows image
โ Edit โ Publish โ status badge changes
โ Delete tag โ post's tag list updates (no crash)
โ Edit category name โ post shows updated category
Flow: HR Workflow
Create Department (child) โ tree shows it
โ Create Employee in department โ Add Tags
โ Department detail: employee count = 1
โ Edit employee โ changes persist
โ Export CSV โ CSV contains employee
โ Import modified CSV โ change applied
โ Move to different department โ both counts update
Flow: CRM Pipeline
Create Company โ Create Contact linked โ company shows contact count
โ Create Lead โ Kanban shows in first stage
โ Drag through stages โ Win โ dashboard metrics update
โ Activity on contact โ timeline shows
โ Delete company โ contacts still accessible (soft delete)
Flow: PM Workflow
Create Project โ auto-code PRJ-xxx
โ Add columns โ Create tasks in different columns
โ Drag task โ status changes in detail
โ Subtask โ complete โ parent progress
โ Comment โ timestamp correct
โ Attachment โ download works
โ Archive โ gone from Kanban, in Archived view
Flow: Data Integrity & Edge Cases
Delete Brand with products โ products still display
Disable Module (CRM) โ sidebar gone, URL โ 404, dashboard widgets hidden, re-enable โ returns
Test user with custom role โ remove permission โ verify sidebar/URL/actions restricted
Language switch ENโVIโEN โ all labels correct, no raw keys, date formats change
Theme switch lightโdarkโlight โ no artifacts
Flow: Error Handling
Navigate to /portal/entity/00000000-...0 โ 404 or graceful redirect
Stop backend โ Submit form โ error banner (not crash) โ Restart backend
Delete entity via API while edit dialog open โ Save โ conflict handling
Rapid pagination clicks โ final page correct (no stale data)
Rapid double-click Submit โ only ONE entity created
TEST CASE PRIORITY LEVELS
| Priority | Meaning | When to run | Typical bugs found |
|---|
| P0 | Critical path โ app unusable if broken | Every commit (smoke) | CRITICAL, HIGH |
| P1 | Core functionality โ feature broken | Every PR (regression) | HIGH, MEDIUM |
| P2 | Edge cases โ non-obvious scenarios | Weekly / pre-release | MEDIUM, LOW |
| P3 | Cosmetic โ nice-to-have | Monthly / manual | LOW |
BUG SEVERITY CLASSIFICATION
| Severity | Definition | Examples |
|---|
| CRITICAL | Feature broken, data loss, security | Form submits but data not saved, crash, security bypass |
| HIGH | Feature partially broken, bad UX | Wrong data displayed, dialog won't close, pagination broken |
| MEDIUM | Visual bug, minor UX | Misalignment, wrong icon, dark mode contrast issue |
| LOW | Cosmetic, nice-to-have | Hover inconsistent, spacing off by a few px |
Priority vs Severity: Priority is the test's urgency (when to run). Severity is the bug's impact (how bad). A P2 edge-case test can find a CRITICAL bug โ that's the point of edge-case testing.
BUG FIX WORKFLOW
When you find a bug:
- Log it โ add to results with severity + description + screenshot
- Analyze root cause โ read relevant source code
- Fix it โ minimal code change
- Restart if needed:
- Frontend CSS/TSX/JSON โ HMR, wait 2s
- Backend handler/service โ
dotnet watch auto-reloads, wait 3-5s
- DI/Program.cs โ restart backend
- vite.config โ restart frontend
- Build check (only if logic change):
- Frontend:
cd src/NOIR.Web/frontend && pnpm run build
- Backend:
dotnet build src/NOIR.sln
- Health check:
curl -sf http://localhost:4000/robots.txt -o /dev/null && echo "Backend: OK"
curl -sf http://localhost:3000 -o /dev/null && echo "Frontend: OK"
- Re-verify โ exact same test that found the bug
- Screenshot fixed state โ
temp/qa-{page}-fixed-{BUG-ID}.png
- Update result status to
FIXED+VERIFIED
- Regression check โ if shared component changed, note affected pages
Bug Decision Tree
CSS/layout bug? โ Fix Tailwind classes โ No restart (HMR)
Missing translation? โ Add to BOTH en/*.json AND vi/*.json โ No restart (HMR)
Dark mode bug? โ Fix hardcoded color or missing dark: variant โ No restart
Data display bug? โ Trace component โ hook โ handler โ spec โ Fix at correct layer โ Watch reload
Form validation? โ Check Zod + FluentValidation โ Fix both if needed โ Watch reload
State management? โ Check TanStack Query invalidation โ No restart
Navigation/routing? โ Check router, useUrlTab/useUrlDialog โ No restart
DI/startup? โ Fix Program.cs/DI โ Restart backend
Field-level UX? โ Fix FormField/FormItem props โ No restart
FIX-THEN-COMMIT Strategy
After fixing ALL bugs on a single page (not per-bug), create ONE commit:
git add [specific files only]
git commit -m "$(cat <<'EOF'
fix(qa): [page-name] โ [N] bugs fixed
- BUG-001: [brief description]
- BUG-002: [brief description]
QA: NOIR QA Agent
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
EOF
)"
TECHNICAL NOTES
Playwright MCP Tools
Use mcp__playwright__* for ALL browser interactions:
browser_navigate โ go to URLs (initial load only โ see SPA bug below)
browser_click โ click elements (use accessible name or CSS selector)
browser_fill_form โ fill multiple form fields at once
browser_take_screenshot โ capture to temp/
browser_snapshot โ accessibility tree (for finding elements)
browser_select_option โ <select> dropdowns
browser_press_key โ keyboard (Escape, Enter, Tab)
browser_wait_for โ network idle or element visible
browser_hover โ hover states
browser_drag โ drag-and-drop (Kanban, tree reorder)
browser_type โ type character by character
browser_resize โ responsive breakpoints
Strategy: browser_snapshot first to understand page structure, then use accessible names for clicking/filling. More robust than CSS selectors.
CRITICAL: MCP Direct โ No Scripts
NEVER write Playwright test scripts (.js/.ts files). Always use mcp__playwright__* tools directly with AI reasoning (max effort, Opus model). The AI reads screenshots, analyzes accessibility trees, and makes intelligent decisions about what to click/verify โ this catches visual bugs that scripted tests miss.
โ WRONG: Write a .js file โ run it with npx playwright test
โ
RIGHT: mcp__playwright__browser_navigate โ mcp__playwright__browser_snapshot โ AI analyzes โ mcp__playwright__browser_click
The entire value of this QA system is AI visual reasoning + interactive exploration, not scripted automation.
Windows SPA Navigation Bug (CRITICAL)
On Windows, browser_navigate / page.goto() often produces blank white pages for React SPA routes. HTML shell loads but React doesn't mount.
Workaround: Navigate via SPA sidebar clicks instead of direct URL. Use browser_navigate ONLY for initial page load (/portal), then sidebar clicks for all subsequent pages. For detail pages without sidebar links, click table rows from parent list.
Context Efficiency
- Save
browser_snapshot output to files (filename param) instead of inline
- NEVER dump full sidebar accessibility tree โ 100+ lines of identical content
- Only read
<main> content area
- For DataTable pattern pages, screenshot is sufficient โ skip tree dump
Login Flow
1. browser_navigate โ http://localhost:3000/login
2. browser_snapshot โ find email/password fields
3. browser_fill_form โ email: admin@noir.local, password: 123qwe
4. browser_click โ Sign In button
5. browser_wait_for โ dashboard loaded
6. For Platform Admin tests: logout, login as platform@noir.local / 123qwe
Screenshot Naming
temp/qa-{page}-{variant}.png
Page-level: -light, -dark, -vi, -1024px, -768px
Element-level: -tab-{name}-{mode}, -create-dialog-{mode}, -edit-dialog-{mode}
-confirm-dialog-{mode}, -empty-state-{mode}
Action: -create-error, -create-valid, -fixed-{BUG-ID}
SERVICE LIFECYCLE
Restart Protocol
| Change Type | Restart? | Action |
|---|
| Frontend CSS/TSX/i18n JSON | NO | Vite HMR (wait 2s) |
| Backend handler/spec/service | NO if dotnet watch | Watch reloads (wait 3-5s) |
| Backend DI / Program.cs | YES โ backend | Kill :4000, rebuild, restart |
| vite.config / tailwind.config | YES โ frontend | Kill :3000, restart pnpm dev |
Restart Commands
netstat -ano | grep ":4000 " | grep "LISTEN" | awk '{print $5}' | sort -u | while read pid; do taskkill //F //PID "$pid" 2>/dev/null; done
sleep 2
cd src/NOIR.Web && dotnet build --nologo -v q -c Debug > /dev/null 2>&1
ASPNETCORE_ENVIRONMENT=Development ASPNETCORE_URLS="http://localhost:4000" dotnet watch run --no-launch-profile > ../../.backend.log 2>&1 &
netstat -ano | grep ":3000 " | grep "LISTEN" | awk '{print $5}' | sort -u | while read pid; do taskkill //F //PID "$pid" 2>/dev/null; done
sleep 1
powershell -Command "Start-Process cmd -ArgumentList '/c cd /d src\NOIR.Web\frontend && pnpm run dev > ..\..\..\.frontend.log 2>&1'"
curl -sf http://localhost:4000/robots.txt -o /dev/null && echo "Backend: OK" || echo "Backend: FAILED"
curl -sf http://localhost:3000 -o /dev/null && echo "Frontend: OK" || echo "Frontend: FAILED"
Crash Recovery
- Check which service is down:
tail -20 .backend.log or .frontend.log
- If crash caused by your fix โ revert fix first
- Restart crashed service
- Wait for health check
- Resume testing