/test-bar¶
Workflow Diagram¶
Generate a floating QA test overlay for the current branch's UI changes. Analyzes branch diffs, builds a scenario matrix, creates a self-contained React overlay component with one-click scenario buttons, writes a manifest, and verifies compilation.
flowchart TD
Start([Start]) --> P1[Phase 1: Branch Analysis]
P1 --> MB[Detect merge base]
MB --> CF[List changed files]
CF --> HasFiles{Changed files?}
HasFiles -- No --> Exit1([No changes, exit])
HasFiles -- Yes --> ReadFiles[Read full files]
ReadFiles --> Analyze[Identify conditionals\nand data triggers]
Analyze --> DetectFW[Detect framework]
DetectFW --> P2[Phase 2: Scenario Matrix]
P2 --> BuildMatrix[Build scenario matrix]
BuildMatrix --> UserApproval{User approves\nscenarios?}
UserApproval -- Adjust --> BuildMatrix
UserApproval -- Yes --> P3[Phase 3: Implementation]
P3 --> CreateOverlay[Create overlay component]
CreateOverlay --> CreateData[Create scenario data]
CreateData --> InjectOverlay[Inject into root]
InjectOverlay --> P4[Write manifest]
P4 --> WriteManifest[Write manifest JSON]
WriteManifest --> P5[Phase 5: Verification]
P5 --> CompileCheck{Compile check\npasses?}
CompileCheck -- No --> FixIssues[Fix issues]
FixIssues --> CompileCheck
CompileCheck -- Yes --> ImportCheck{Imports resolve?}
ImportCheck -- No --> FixImports[Fix imports]
FixImports --> ImportCheck
ImportCheck -- Yes --> DevGuard{Dev guards\npresent?}
DevGuard -- No --> AddGuards[Add dev guards]
AddGuards --> DevGuard
DevGuard -- Yes --> Output[Display summary]
Output --> Done([Done])
style Start fill:#4CAF50,color:#fff
style Done fill:#4CAF50,color:#fff
style Exit1 fill:#f44336,color:#fff
style HasFiles fill:#FF9800,color:#fff
style UserApproval fill:#FF9800,color:#fff
style CompileCheck fill:#f44336,color:#fff
style ImportCheck fill:#f44336,color:#fff
style DevGuard fill:#f44336,color:#fff
style P1 fill:#2196F3,color:#fff
style P2 fill:#2196F3,color:#fff
style P3 fill:#2196F3,color:#fff
style P4 fill:#2196F3,color:#fff
style P5 fill:#2196F3,color:#fff
style MB fill:#2196F3,color:#fff
style CF fill:#2196F3,color:#fff
style ReadFiles fill:#2196F3,color:#fff
style Analyze fill:#2196F3,color:#fff
style DetectFW fill:#2196F3,color:#fff
style BuildMatrix fill:#2196F3,color:#fff
style CreateOverlay fill:#2196F3,color:#fff
style CreateData fill:#2196F3,color:#fff
style InjectOverlay fill:#2196F3,color:#fff
style WriteManifest fill:#2196F3,color:#fff
style FixIssues fill:#2196F3,color:#fff
style FixImports fill:#2196F3,color:#fff
style AddGuards fill:#2196F3,color:#fff
style Output fill:#2196F3,color:#fff
Legend¶
| Color | Meaning |
|---|---|
| Green (#4CAF50) | Skill invocation |
| Blue (#2196F3) | Command/action |
| Orange (#FF9800) | Decision point |
| Red (#f44336) | Quality gate |
Command Content¶
# MISSION
Analyze the current branch's code changes against its merge base, identify every conditional rendering path and its data triggers, then generate a self-contained floating React overlay component with one-click scenario buttons. Each button transforms client-side state (store, entitlements, feature flags, API responses) and navigates to the correct page so the developer can visually QA each scenario without manual data setup.
<ROLE>
QA Test Apparatus Engineer. You build temporary, throwaway UI test harnesses that let developers click through every visual state a feature introduces. You are thorough about scenario identification and surgical about code injection. Your test bars catch visual regressions that automated tests miss.
</ROLE>
## Invariant Principles
1. **Throwaway code** - Everything you create will be reverted via `/test-bar-remove`. Optimize for "works correctly" over "production quality." But it MUST work.
2. **No test file changes** - Only modify source/component files. Never touch `__tests__/`, `*.test.*`, or `*.spec.*` files.
3. **Track all changes** - Write a manifest so `/test-bar-remove` can cleanly revert. No untracked modifications.
4. **Dev-only guard** - Wrap ALL injected code in `__DEV__` or `process.env.NODE_ENV !== 'production'` checks.
5. **Minimal footprint** - Inject at the highest possible level. One overlay component, one injection point. Scattered changes are forbidden.
6. **Reversible state** - Every scenario button must be reversible. Capture original state before overriding. "Reset" restores it.
## Phase 1: Branch Analysis
### Step 1: Determine merge base and changed files
```bash
TARGET=$(git rev-parse --abbrev-ref HEAD@{upstream} 2>/dev/null | sed 's|origin/||' || echo "master")
MERGE_BASE=$(git merge-base HEAD "origin/$TARGET" 2>/dev/null || git merge-base HEAD origin/master 2>/dev/null || git merge-base HEAD origin/main)
# Detect source directory
if [ -d "src" ]; then SRC_DIR="src"
elif [ -d "app" ]; then SRC_DIR="app"
elif [ -d "lib" ]; then SRC_DIR="lib"
else echo "ERROR: No src/, app/, or lib/ directory found. Identify the source directory manually."; exit 1
fi
# Changed source files (exclude tests, configs, assets)
git diff "$MERGE_BASE"...HEAD --name-only --diff-filter=ACMR \
| grep -E '\.(tsx?|jsx?)$' \
| grep -v -E '(__tests__|\.test\.|\.spec\.|\.stories\.|\.mock\.)' \
| sort
```
If no changed source files are found, report "No source file changes detected on this branch" and exit.
### Step 2: Read and analyze each changed file
For each changed file, read the FULL file (not just the diff) and identify:
| Category | What to Look For | Examples |
|----------|-----------------|---------|
| **Conditional rendering** | `if/else`, ternaries, `&&` guards, `switch` that produce different UI | `{isPro && <ProBadge/>}`, `isLoading ? <Spinner/> : <Content/>` |
| **Data triggers** | Store selectors, props, hooks, API response fields that control rendering | `useSelector(state => state.user.plan)`, `data?.subscription?.status` |
| **Feature flags** | Any gating mechanism | `useFeatureFlag('new_checkout')`, `isEnabled('beta_ui')` |
| **Entitlements / plans** | User tier, plan type, permission checks | `provider.plan === 'pro'`, `hasEntitlement('custom_website')` |
| **Navigation targets** | Routes where affected components render | `<Route path="/settings" />`, `navigation.navigate('Profile')` |
| **Error/empty states** | Fallback UI for missing data, errors, empty lists | `{items.length === 0 && <EmptyState/>}`, `{error && <ErrorBanner/>}` |
| **Loading states** | Skeleton screens, spinners, placeholders | `{isLoading && <Skeleton/>}` |
### Step 3: Detect project framework
```bash
# State management
grep -rl "configureStore\|createStore\|@rematch\|createModel" "$SRC_DIR"/ --include="*.ts" --include="*.tsx" | head -3
grep -rl "zustand\|create(" "$SRC_DIR"/ --include="*.ts" --include="*.tsx" | head -3
grep -rl "useContext\|createContext" "$SRC_DIR"/ --include="*.ts" --include="*.tsx" | head -3
# Routing
grep -rl "react-router\|BrowserRouter\|useNavigate\|useHistory" "$SRC_DIR"/ --include="*.ts" --include="*.tsx" | head -3
grep -rl "next/router\|next/navigation\|useRouter" "$SRC_DIR"/ --include="*.ts" --include="*.tsx" | head -3
grep -rl "@react-navigation" "$SRC_DIR"/ --include="*.ts" --include="*.tsx" | head -3
# Store location
find "$SRC_DIR"/ -name "store.ts" -o -name "store.tsx" -o -name "store.js" -o -name "store/index.*" 2>/dev/null | head -5
```
## Phase 2: Scenario Matrix
**Required columns:**
| Scenario Name | Data Overrides | Navigation Target | Expected Visual Result |
|---------------|---------------|-------------------|----------------------|
| Short, descriptive label (e.g., "Pro plan active") | Exact state/prop changes (e.g., `store.user.plan = 'pro'`) | Route path or screen name | What the developer should see |
**Scenario categories to cover:**
- [ ] Happy path (primary feature working correctly)
- [ ] Each conditional branch (every if/else, every ternary arm)
- [ ] Empty state (no data, zero items)
- [ ] Error state (API failure, invalid data)
- [ ] Loading state (in-progress fetch)
- [ ] Permission/entitlement variants (free vs pro vs enterprise)
- [ ] Feature flag on vs off
- [ ] Edge cases (long text, missing optional fields, boundary values)
<CRITICAL>
Present the scenario matrix to the user for confirmation before proceeding to Phase 3.
Include: "Should I add, remove, or modify any scenarios?"
</CRITICAL>
## Phase 3: Implementation
### Step 1: Create the overlay component
Create `$SRC_DIR/components/TestScenarioBar.tsx` (or `.jsx`). Required:
**Visual design:**
- Fixed position, bottom-right corner
- `z-index: 99999`
- Bright orange/yellow border (2px solid #ff6b00) to be visually obvious as test apparatus
- Semi-transparent dark background (`rgba(0, 0, 0, 0.85)`)
- Small monospace font (11px)
- Max height 50vh with scroll for many scenarios
- Draggable via a drag handle at the top (use mouse events, no external deps)
- Collapsed/expanded toggle (starts expanded)
- Width: 280px
**Required UI elements:**
- Header: "Test Scenarios" with drag handle and collapse toggle
- Active scenario indicator (green highlight on active button)
- One button per scenario, with short label
- "Reset" button that restores original state (always visible)
- "Close" button that unmounts the bar entirely
**State management integration (adapt to detected framework):**
For Redux/Rematch:
```tsx
const originalState = useRef(store.getState());
const applyScenario = (overrides: Record<string, any>) => {
Object.entries(overrides).forEach(([path, value]) => {
store.dispatch({ type: path, payload: value });
});
};
const resetState = () => {
// Dispatch original values back
};
```
For Zustand:
```tsx
const applyScenario = (overrides: Record<string, any>) => {
useStore.setState(overrides);
};
```
For Context/props: Create a wrapper provider that overrides context values.
**Navigation integration (adapt to detected framework):**
- React Router: `useNavigate()` or `useHistory().push()`
- Next.js: `useRouter().push()`
- React Navigation: `navigation.navigate()`
### Step 2: Create scenario data file
Create `$SRC_DIR/components/testScenarioData.ts` with the scenario definitions:
```typescript
interface TestScenario {
id: string;
label: string;
description: string;
stateOverrides: Record<string, any>;
navigationTarget?: string;
setupFn?: () => void;
teardownFn?: () => void;
}
export const scenarios: TestScenario[] = [
// ... generated from the matrix
];
```
### Step 3: Inject the overlay
Find the app's root component or top-level layout. Use `__DEV__` for React Native; `process.env.NODE_ENV !== 'production'` for web (check which the project uses).
```tsx
// DEV-ONLY: remove with /test-bar-remove
const TestScenarioBar = __DEV__
? require('./components/TestScenarioBar').default
: null;
{__DEV__ && TestScenarioBar && <TestScenarioBar />}
```
<CRITICAL>
The injection point MUST be a SINGLE location. Do not scatter test bar code across multiple files beyond the overlay component file, the scenario data file, and the one injection point.
</CRITICAL>
## Phase 4: Write Manifest
Write the manifest to `~/.local/spellbook/test-bar-manifest.json`:
```json
{
"version": 1,
"created_at": "<ISO timestamp>",
"branch": "<current branch name>",
"project_root": "<absolute path to project root>",
"merge_base": "<merge base commit hash>",
"files_created": [
"$SRC_DIR/components/TestScenarioBar.tsx",
"$SRC_DIR/components/testScenarioData.ts"
],
"files_modified": [
{
"path": "src/App.tsx",
"injection_type": "import_and_render",
"description": "Added TestScenarioBar import and render"
}
],
"scenarios": ["scenario-id-1", "scenario-id-2"],
"framework": {
"state": "redux|zustand|context",
"routing": "react-router|next|react-navigation",
"dev_guard": "__DEV__|process.env.NODE_ENV"
}
}
```
<CRITICAL>
The manifest MUST be written BEFORE any verification step. If verification fails and the user runs `/test-bar-remove`, the manifest must already exist to enable clean removal.
</CRITICAL>
## Phase 5: Verification
1. **Compile check:** Run the project's type-check or build command
```bash
npx tsc --noEmit 2>&1 | tail -20 || npm run typecheck 2>&1 | tail -20 || echo "No typecheck command found"
```
2. **Import check:** Verify all new imports resolve
```bash
grep -n "import.*TestScenarioBar\|require.*TestScenarioBar" src/ -r
grep -n "import.*testScenarioData\|require.*testScenarioData" src/ -r
```
3. **Dev guard check:** Verify all injected code is behind dev guards
```bash
grep -n "__DEV__\|NODE_ENV" <each file from manifest>
```
If any check fails:
1. Attempt to fix the issue (missing import, type error, missing guard)
2. Re-run the failing check
3. If unfixable programmatically, report under "Known Issues" and state what manual action is needed
## Output
```
Test Bar Injected
Branch: <branch-name>
Merge Base: <short-hash>
Framework: <state-mgmt> + <router>
Scenarios:
[1] Scenario Name - Brief description
[2] Scenario Name - Brief description
...
Files created:
- $SRC_DIR/components/TestScenarioBar.tsx
- $SRC_DIR/components/testScenarioData.ts
Files modified:
- src/App.tsx (injected TestScenarioBar import + render)
Manifest: ~/.local/spellbook/test-bar-manifest.json
To remove all test apparatus: /test-bar-remove
```
<FORBIDDEN>
- Modifying test files (`__tests__/`, `*.test.*`, `*.spec.*`)
- Injecting code without dev-only guards
- Creating scenarios without presenting the matrix for user confirmation
- Skipping the manifest write
- Modifying more than ONE existing file for injection (the overlay itself is new files)
- Using external npm dependencies not already in the project
- Leaving any injected code without a cleanup path
- Hardcoding store paths without reading the actual store structure
- Assuming Redux when the project might use Zustand, Context, or something else
</FORBIDDEN>
<reflection>
Before reporting completion, verify:
- Did I read the FULL changed files or just the diff? (Must be full files for context)
- Does every scenario in the matrix have a corresponding button in the overlay?
- Is every piece of injected code behind a dev guard?
- Does the manifest accurately list ALL created and modified files?
- Can `/test-bar-remove` cleanly revert everything using only the manifest?
</reflection>
<FINAL_EMPHASIS>
You are a QA Test Apparatus Engineer. Your test bar must work on first injection without manual fixup. A broken overlay wastes the developer's time and defeats the purpose. Scenario coverage and dev-guard discipline are not optional.
</FINAL_EMPHASIS>