-
Notifications
You must be signed in to change notification settings - Fork 489
Description
Bug: TypeError when toggling "Enable automated testing" checkbox on existing features
Description
When editing an existing feature and unchecking the "Enable automated testing" checkbox (to enable manual verification), the app crashes with:
TypeError: Cannot read properties of undefined (reading 'map')
at TestingTabContent (testing-tab-content.tsx:63)
Screen.Recording.2025-12-20.at.2.22.36.PM.mov
Steps to Reproduce
- Open an existing feature that was created before the verification steps field was added
- Open the edit feature dialog
- Navigate to the "Options" tab
- Uncheck the "Enable automated testing" checkbox
- App crashes immediately
Expected Behavior
The verification steps section should appear with the add button or the existing steps, allowing the user to add manual verification steps.
Actual Behavior
The app crashes with a TypeError because steps is undefined when steps.map() is called.
Root Cause Analysis
The Feature interface declares steps as a required field:
export interface Feature {
// ...
steps: string[]; // Required, not optional
// ...
}However, there's a type/runtime data mismatch:
- Old persisted data: Features created before the verification steps feature was added don't have a
stepsfield in theirfeature.jsonfiles - Missing data migration: When features are loaded in
use-board-features.ts(lines 62-72), there's backward compatibility logic formodelandthinkingLevel, but not forsteps:const featuresWithIds = result.features.map( (f: any, index: number) => ({ ...f, // ... other fields ... model: f.model || "opus", thinkingLevel: f.thinkingLevel || "none", // ❌ Missing: steps: f.steps || [], }) );
- Component assumes valid data:
TestingTabContentcallssteps.map()without checking ifstepsexists, causing the crash when the verification section renders
Proposed Solutions
Solution 1: Add data migration at load time ⭐ Primary Fix
Initialize steps when loading features, like other backward-compatible fields. This ensures all features entering the application state conform to the Feature interface contract:
// apps/ui/src/components/views/board-view/hooks/use-board-features.ts (line ~62)
const featuresWithIds = result.features.map(
(f: any, index: number) => ({
...f,
id: f.id || `feature-${index}-${Date.now()}`,
status: f.status || "backlog",
startedAt: f.startedAt,
model: f.model || "opus",
thinkingLevel: f.thinkingLevel || "none",
steps: f.steps || [], // ✅ Add this line
})
);Solution 2: Add defensive coding in component (Defense in depth)
While the data should always be valid after Solution 1, add defensive checks in TestingTabContent as a safety measure:
// apps/ui/src/components/views/board-view/shared/testing-tab-content.tsx (line ~63)
{(steps || []).map((step, index) => (
<Input
key={index}
value={step}
placeholder={`Verification step ${index + 1}`}
onChange={(e) => handleStepChange(index, e.target.value)}
data-testid={`${testIdPrefix ? testIdPrefix + "-" : ""}feature-step-${index}${testIdPrefix ? "" : "-input"}`}
/>
))}Also update helper functions:
const handleStepChange = (index: number, value: string) => {
const newSteps = [...(steps || [])]; // ✅ Add defensive check
newSteps[index] = value;
onStepsChange(newSteps);
};
const handleAddStep = () => {
onStepsChange([...(steps || []), ""]); // ✅ Add defensive check
};Environment
- App: Automaker
- Affected files:
apps/ui/src/store/app-store.ts(interface definition)apps/ui/src/components/views/board-view/hooks/use-board-features.ts(data loading)apps/ui/src/components/views/board-view/shared/testing-tab-content.tsx(component)