# UI Automation Troubleshooting Guide
## Overview
This guide helps troubleshoot common issues with the UI Automation and Reflection system. It covers problems with component registration, UI state visibility, automation server connectivity, and debugging techniques.
## Quick Diagnostic Tools
### 1. Browser Console UI State Inspection
Inspect current component registration directly in the browser console via `window.__UI_STATE__`:
```javascript
// In the browser console:
window.__UI_STATE__ // Full UI state object
JSON.stringify(window.__UI_STATE__, null, 2) // Pretty-printed JSON output
Object.keys(window.__UI_STATE__).length // Component count
```
### 2. Claude Code Slash Command
Use the `/ui-state` command in Claude Code to get automated analysis:
```
/ui-state
```
This will run the dump tool and provide AI-powered analysis of your UI state.
### 3. Browser Console Logging
Enable detailed logging by checking browser console for UI reflection messages:
- `🔄 [UI-STATE]` - Component registration updates
- `🔌 [WEBSOCKET]` - WebSocket connection status
- `📡 [UI_STATE_UPDATE]` - State change broadcasts
## Common Issues and Solutions
### Issue 1: Components Not Showing in UI State
**Symptoms:**
- UI state dump shows only sidebar/navigation components
- Screen-specific components are missing
- Empty or minimal component count
**Root Causes & Solutions:**
#### A. Missing UI Reflection Integration
**Problem:** Component doesn't use `useAutomationIdAndRegister` hook.
**Solution:** Add UI reflection to the component:
```tsx
// Before: No UI reflection
function MyComponent() {
return (
);
}
```
#### B. Incorrect Import Paths
**Problem:** Import paths are wrong, causing hook to be undefined.
**Error Message:**
```
TypeError: useAutomationIdAndRegister is not a function
```
**Solution:** Use correct import paths:
```tsx
// Correct imports
import { useAutomationIdAndRegister } from 'packages/ui/src/ui-reflection/useAutomationIdAndRegister';
import { ReflectionContainer } from 'packages/ui/src/ui-reflection/ReflectionContainer';
```
#### C. Missing ReflectionContainer Wrapper
**Problem:** Components are registered but not properly nested.
**Solution:** Wrap main content with ReflectionContainer:
```tsx
function PageComponent() {
const { automationIdProps: pageProps } = useAutomationIdAndRegister({
id: 'my-page',
type: 'container',
label: 'My Page'
});
return (
{/* All page content goes here */}
{/* ... */}
);
}
```
### Issue 2: Automation Server Connection Problems
**Symptoms:**
- `window.__UI_STATE__` returns undefined or empty
- WebSocket connection failures in browser console
- UI state not updating in real-time
**Diagnostic Steps:**
1. **Check Automation Server Status:**
```bash
# Check if automation server is running
curl http://localhost:4000/api/ui-state
```
2. **Verify Server Logs:**
```bash
# In the main project directory
docker-compose logs | grep automation
```
3. **Check WebSocket Connection:**
Open browser console and look for:
```
[WEBSOCKET] 🔌 Client connected
[WEBSOCKET] 📡 UI_STATE_UPDATE received
```
**Solutions:**
#### A. Start Automation Server
```bash
# Start the automation server
cd tools/ai-automation
npm start
```
#### B. Check Port Conflicts
If port 4000 is in use, update configuration:
```bash
# Check what's using port 4000
lsof -i :4000
# Kill conflicting process if needed
kill -9
```
#### C. Restart Docker Services
```bash
# Restart all services
docker-compose down
docker-compose up -d
```
### Issue 3: UI State Not Updating
**Symptoms:**
- Components show in initial dump but don't update
- State changes not reflected in UI state
- Stale component metadata
**Root Causes & Solutions:**
#### A. Missing Metadata Updates
**Problem:** Component state changes but metadata isn't updated.
**Solution:** Use `updateMetadata` function:
```tsx
function DynamicButton({ label, disabled }) {
const { automationIdProps, updateMetadata } = useAutomationIdAndRegister({
id: 'dynamic-button',
type: 'button',
label,
disabled
});
// Update metadata when props change
useEffect(() => {
updateMetadata({ label, disabled });
}, [label, disabled, updateMetadata]);
return ;
}
```
#### B. Module Instance Mismatch
**Problem:** Different UIStateManager instances in different processes.
**Solution:** Ensure automation server is used as source of truth:
- Use HTTP API endpoints instead of direct module access
- Verify WebSocket connections are active
- Check for multiple server instances
### Issue 4: Component Hierarchy Issues
**Symptoms:**
- Components appear as root-level instead of nested
- Parent-child relationships are incorrect
- Auto-generated IDs are wrong
**Solutions:**
#### A. Proper Context Usage
```tsx
// Correct: Parent sets context for children
function ParentContainer() {
const { automationIdProps } = useAutomationIdAndRegister({
id: 'parent-container',
type: 'container',
label: 'Parent'
});
return (
{/* Children inherit parent context automatically */}
{/* Will be parent-container-child */}
);
}
function ChildComponent() {
// No explicit parentId needed - inherited from context
const { automationIdProps } = useAutomationIdAndRegister({
type: 'button',
label: 'Child Button'
});
return ;
}
```
#### B. ID Naming Conventions
Follow consistent naming patterns:
- Screen/Page: `my-screen`
- Subcontainer: `${parentId}-section` (e.g., `my-screen-filters`)
- Component: `${parentId}-type` (e.g., `my-screen-filters-select`)
### Issue 5: Form Field Naming and Override ID Support
**Symptoms:**
- Form fields show generic auto-generated names like `formField-1`, `formField-2`
- Meaningful field names like `email`, `phone_no` are not appearing
- Components ignore `data-automation-id` attributes
**Root Causes & Solutions:**
#### A. Missing Override ID Support
**Problem:** Components auto-generate IDs instead of using provided `data-automation-id`.
**Solution:** Implement the override ID pattern in form components:
```tsx
// Enhanced useAutomationIdAndRegister with actions support
export function useAutomationIdAndRegister(
component: Omit & { id?: string },
actionsOrShouldRegister: ActionConfig | boolean = [],
overrideId?: string
): {
automationIdProps: { id: string; 'data-automation-id': string };
updateMetadata: (partial: Partial) => void;
updateActions: (newActions: ActionConfig) => void;
}
// Where ActionConfig = ComponentAction[] | (() => ComponentAction[])
// In form components (Input, CustomSelect, TextArea):
const { automationIdProps } = useAutomationIdAndRegister({
type: 'formField',
fieldType: 'textField',
id,
label
}, true, dataAutomationId); // Pass override ID as third parameter
```
#### B. Implementing Override ID Pattern in Components
**Solution:** Update form components to support `data-automation-id`:
```tsx
// Before: No override support
export const Input = forwardRef(
({ label, id, ...props }, ref) => {
const { automationIdProps } = useAutomationIdAndRegister({
id,
type: 'formField',
fieldType: 'textField'
});
return ;
}
);
// After: With override support
export const Input = forwardRef(
({ label, id, "data-automation-id": dataAutomationId, ...props }, ref) => {
const { automationIdProps } = useAutomationIdAndRegister({
id,
type: 'formField',
fieldType: 'textField'
}, true, dataAutomationId); // Pass override ID
return ;
}
);
```
#### C. Usage Pattern for Meaningful Field Names
**Solution:** Use `data-automation-id` for meaningful form field names:
```tsx
// Form with meaningful field names
function MyForm() {
return (
);
}
```
### Issue 6: Dialog Type Registration Problems
**Symptoms:**
- Dialogs appear as `Type: container` instead of `Type: dialog`
- Dialog `open` property is missing from UI state
- Dialog actions (submit/cancel) are not available
**Root Causes & Solutions:**
#### A. Incorrect Dialog Wrapper Usage
**Problem:** Using `ReflectionContainer` wrapper makes dialogs appear as containers.
**Solution:** Use `withDataAutomationId` directly on dialog content:
```tsx
// Before: Shows as Type: container
function MyDialog({ open, onOpenChange }) {
const { automationIdProps } = useAutomationIdAndRegister({
id: 'my-dialog',
type: 'dialog',
title: 'My Dialog'
});
return (
);
}
// After: Shows as Type: dialog
function MyDialog({ open, onOpenChange }) {
const { automationIdProps: updateDialog } = useAutomationIdAndRegister({
id: 'my-dialog',
type: 'dialog',
title: 'My Dialog',
open
});
return (
);
}
```
#### B. Missing Dialog State Updates
**Solution:** Update dialog metadata when state changes:
```tsx
// Update dialog metadata when open state changes
useEffect(() => {
if (updateMetadata) {
updateMetadata({ open });
}
}, [open, updateMetadata]);
```
### Issue 7: Double Registration Prevention
**Symptoms:**
- Duplicate components appearing in UI state
- Form fields registered both by parent and themselves
- Generic IDs mixed with meaningful names
**Root Causes & Solutions:**
#### A. Parent and Child Both Registering
**Problem:** Parent component and form components both call `useAutomationIdAndRegister`.
**Solution:** Remove duplicate registrations from parent component:
```tsx
// Before: Double registration
function QuickAddForm() {
// DON'T: Register fields at parent level
const { automationIdProps: emailProps } = useAutomationIdAndRegister({
id: 'email',
type: 'formField',
fieldType: 'textField',
parentId: 'my-form'
});
return (
);
}
// After: Single registration with override ID
function QuickAddForm() {
return (
);
}
```
#### B. Conditional Registration Pattern
**Solution:** Use conditional registration to prevent duplicates:
```tsx
// In form components, check for data-automation-id
const shouldRegister = !dataAutomationId;
const { automationIdProps } = useAutomationIdAndRegister({
type: 'formField',
fieldType: 'textField',
id: shouldRegister ? id : undefined
}, shouldRegister, dataAutomationId);
```
### Issue 8: Hook Parameter Debugging
**Symptoms:**
- `useAutomationIdAndRegister` behaves unexpectedly
- Parameters not being passed correctly
- Function receiving default values instead of provided ones
**Debugging Steps:**
#### A. Verify Function Signature
**Check:** Ensure you're passing parameters in the correct order:
```tsx
// Correct parameter order
useAutomationIdAndRegister(
component: Omit & { id?: string },
actionsOrShouldRegister: ActionConfig | boolean = [],
overrideId?: string
)
// Where ActionConfig = ComponentAction[] | (() => ComponentAction[])
// Common mistake: Missing actionsOrShouldRegister parameter
// WRONG:
const { automationIdProps } = useAutomationIdAndRegister({
type: 'formField',
fieldType: 'textField'
}, dataAutomationId); // Missing actionsOrShouldRegister parameter
// CORRECT:
const { automationIdProps } = useAutomationIdAndRegister({
type: 'formField',
fieldType: 'textField'
}, true, dataAutomationId); // All parameters provided
```
#### B. Add Debug Logging
**Solution:** Add logging to verify parameter values:
```tsx
const { automationIdProps } = useAutomationIdAndRegister({
type: 'formField',
fieldType: 'textField',
id
}, shouldRegister, dataAutomationId);
console.log('🔍 Hook params:', { shouldRegister, dataAutomationId, id });
console.log('🔍 Generated props:', automationIdProps);
```
### Issue 9: Raw HTML Elements vs UI Components
**Symptoms:**
- Some form fields not appearing in UI state
- Mixed registration patterns in the same component
- Inconsistent automation ID application
**Root Causes & Solutions:**
#### A. Raw HTML Elements Don't Auto-Register
**Problem:** Using raw ``, `