Some checks are pending
Bidi Control Character Guard / bidi-control-guard (push) Waiting to run
Circular Dependency Check / Check for new circular dependencies (push) Waiting to run
Citus Migration Smoke / Combined migrations on single-node Citus (push) Waiting to run
E2E Fresh Install Tests / fresh-install-e2e (push) Waiting to run
ext-v2 guardrails / Run ext-v2 guard and ESLint (push) Waiting to run
Integration Tests / Check for relevant changes (push) Waiting to run
Integration Tests / ${{ (github.event_name == 'schedule' || github.event.inputs.suite == 'full') && 'Full integration suite' || 'Tier-1 integration subset' }} (push) Blocked by required conditions
Mobile checks / Mobile lint + typecheck (push) Waiting to run
Mobile checks / Mobile unit tests (push) Waiting to run
Mobile checks / Mobile dependency audit (report) (push) Waiting to run
Mobile checks / Mobile reproducibility checks (push) Waiting to run
Secrets guard (env backups) / Ensure no tracked env backup files (push) Waiting to run
Temporal Readiness / fast-readiness (push) Waiting to run
Temporal Readiness / docker-parity (push) Waiting to run
TypeScript Type Check / Nx affected typecheck (push) Waiting to run
Unit Tests / Skipped-test budget (push) Waiting to run
Unit Tests / Nx affected unit tests (push) Waiting to run
Unit Tests / Server unit coverage (informational) (push) Waiting to run
Validate Tenant Management Schema / Check for relevant changes (push) Waiting to run
Validate Tenant Management Schema / Validate Tenant Management Schema (push) Blocked by required conditions
EE Workflows Build Guard / ee-workflows-build-guard (push) Waiting to run
Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz Source: /opt/alga-psa on psa.joliet.tech
169 lines
5.8 KiB
Markdown
169 lines
5.8 KiB
Markdown
# UI Automation IDs
|
|
|
|
## Overview
|
|
|
|
The UI reflection system provides a live, high-level JSON description of the application's UI state. To ensure proper integration with automated testing and LLM-driven interactions, all UI components must maintain consistency between their UI state IDs and DOM data-automation-id attributes.
|
|
|
|
## Parent-Child Relationships
|
|
|
|
Components automatically inherit their parent's ID through React context, eliminating the need to manually wire parentId everywhere:
|
|
|
|
```typescript
|
|
// Parent container sets the context
|
|
<ReflectionContainer id="ticketing-dashboard">
|
|
{/* Children automatically know their parent */}
|
|
<TicketFilters /> {/* gets ticketing-dashboard as parent */}
|
|
<TicketTable /> {/* gets ticketing-dashboard as parent */}
|
|
</ReflectionContainer>
|
|
```
|
|
|
|
## Naming Conventions
|
|
|
|
Follow these patterns for component IDs:
|
|
|
|
1. **Screen/Page Components**:
|
|
```typescript
|
|
// Base page ID
|
|
id="ticketing-dashboard"
|
|
```
|
|
|
|
2. **Subcontainers**:
|
|
```typescript
|
|
// Major sections use parent ID + purpose
|
|
id={`${parentId}-filters`} // ticketing-dashboard-filters
|
|
id={`${parentId}-table`} // ticketing-dashboard-table
|
|
```
|
|
|
|
3. **UI Components**:
|
|
```typescript
|
|
// Individual elements use parent ID + type
|
|
id={`${parentId}-status-select`} // ticketing-dashboard-filters-status-select
|
|
id={`${parentId}-search-input`} // ticketing-dashboard-filters-search-input
|
|
```
|
|
|
|
## Sidebar Menu ID Convention
|
|
|
|
The sidebar menu items use a double-prefix pattern in their DOM automation IDs. The `Sidebar` component generates an `id` of `menu-{name}` for each item, which is then passed to `SidebarMenuItem`. The `SidebarMenuItem` renders the element with a `data-automation-id` of `sidebar-menu-menu-{name}`, resulting in the `menu-` prefix appearing twice.
|
|
|
|
For example, the Home menu item renders as:
|
|
```
|
|
data-automation-id="sidebar-menu-menu-home"
|
|
```
|
|
|
|
Other examples:
|
|
- Tickets: `sidebar-menu-menu-tickets`
|
|
- Companies: `sidebar-menu-menu-companies`
|
|
- Settings: `sidebar-menu-menu-settings`
|
|
|
|
When writing tests or automation scripts targeting sidebar items, use the full double-prefix form (`sidebar-menu-menu-{name}`).
|
|
|
|
## The useAutomationIdAndRegister Hook
|
|
|
|
Use this hook to combine UI reflection registration and data-automation-id props:
|
|
|
|
```typescript
|
|
function MyComponent({ id, ...props }) {
|
|
// Register with reflection system and get DOM props
|
|
const { automationIdProps, updateMetadata } = useAutomationIdAndRegister<ContainerComponent>({
|
|
id, // Optional - will auto-generate if not provided
|
|
type: 'container',
|
|
label: 'My Component'
|
|
});
|
|
|
|
return <div {...automationIdProps} {...props} />;
|
|
}
|
|
```
|
|
|
|
### Features
|
|
|
|
1. **Automatic ID Generation**:
|
|
```typescript
|
|
// With explicit ID
|
|
const { automationIdProps } = useAutomationIdAndRegister({
|
|
id: `${parentId}-filters`,
|
|
type: 'container'
|
|
});
|
|
|
|
// With auto-generated ID
|
|
const { automationIdProps } = useAutomationIdAndRegister({
|
|
type: 'container' // generates like: container-1, container-2, etc.
|
|
});
|
|
```
|
|
|
|
2. **Parent Context Integration**:
|
|
```typescript
|
|
// Auto-generated IDs include parent context
|
|
parentId: 'my-screen'
|
|
auto-generated: 'my-screen-button-1'
|
|
```
|
|
|
|
3. **Single Source of Truth**:
|
|
- One hook call provides both reflection registration and DOM attributes
|
|
- No chance of mismatch between UI state and DOM
|
|
- Type-safe through TypeScript generics
|
|
|
|
## Core Components
|
|
|
|
Over 52 UI components now implement the `useAutomationIdAndRegister` pattern, including but not limited to:
|
|
- Button (`packages/ui/src/components/Button.tsx`)
|
|
- Input (`packages/ui/src/components/Input.tsx`)
|
|
- Dialog (`packages/ui/src/components/Dialog.tsx`)
|
|
- SearchableSelect, CustomSelect, AsyncSearchableSelect
|
|
- TextArea, SearchInput, TagInput
|
|
- ClientPicker, UserPicker, ContactPicker, CountryPicker
|
|
- DateTimePicker, DatePicker, TimePicker
|
|
- GenericDialog, CategoryPicker, BoardPicker
|
|
|
|
When creating new components that use the UI reflection system, follow these examples to maintain consistency.
|
|
|
|
## Testing
|
|
|
|
When writing tests, always use the component's ID to locate elements:
|
|
|
|
```typescript
|
|
// Good - uses data-automation-id that matches UI state
|
|
cy.get('[data-automation-id="ticketing-dashboard-filters-status-select"]').click();
|
|
|
|
// Bad - uses other selectors that might change
|
|
cy.get('.status-select').click();
|
|
cy.get('select:contains("Status")').click();
|
|
```
|
|
|
|
## Benefits
|
|
|
|
1. **Automated Testing**:
|
|
- Consistent, predictable IDs make tests reliable
|
|
- Parent-child relationships reflected in ID structure
|
|
- Auto-generated IDs maintain uniqueness
|
|
|
|
2. **LLM Integration**:
|
|
- Hierarchical component structure is clear from IDs
|
|
- Consistent naming makes UI state easy to understand
|
|
- Automatic parent-child tracking improves accuracy
|
|
|
|
3. **Developer Experience**:
|
|
- No manual parentId prop passing
|
|
- Auto-generated IDs reduce boilerplate
|
|
- Single hook call for all UI reflection needs
|
|
- Type-safe through TypeScript
|
|
|
|
4. **Maintenance**:
|
|
- Consistent naming conventions
|
|
- Clear component hierarchy
|
|
- Reduced coupling between tests and implementation
|
|
- Single source of truth for IDs
|
|
|
|
## Implementation Details
|
|
|
|
The UI reflection system uses React's Context API to maintain a live representation of the UI state. Each component that registers with the system contributes to this state, and the data-automation-id attributes provide a direct mapping between the logical UI state and the actual DOM elements.
|
|
|
|
The system now includes:
|
|
- ReflectionParentContext for automatic parent-child relationships
|
|
- useAutomationIdAndRegister hook for unified registration and DOM props
|
|
- Automatic ID generation with consistent naming patterns
|
|
- Type-safe component registration through TypeScript
|
|
|
|
See also:
|
|
- [UI Reflection System](ui_reflection_system.md)
|
|
- [Development Guide](../getting-started/development_guide.md)
|