Files
gridpilot.gg/packages/infrastructure/adapters/automation/IRacingSelectors-update-plan.md
2025-11-27 18:14:25 +01:00

106 lines
7.3 KiB
Markdown

# iRacing Selectors Update Plan
**Date:** 2025-11-27
**Based on:** HTML dumps from `html-dumps-optimized/iracing-hosted-sessions/` (01-18) vs [`IRacingSelectors.ts`](packages/infrastructure/adapters/automation/IRacingSelectors.ts).
**Goal:** Verify selectors against recent dumps, propose updates for stability (React/Chakra UI resilience), prioritize fixes.
## Clean Architecture Impact
Selectors adhere to Clean Arch by relying on stable attributes (text, aria-label, data-testid, IDs like #set-*) rather than volatile classes. Updates reinforce this: prefer `:has-text()`, `data-testid`, label proximity over class names. No cross-layer leaks; selectors are pure infrastructure adapters.
## Priority Summary
| Priority | Count | Examples |
|----------|-------|----------|
| **Critical** (broken) | 2 | `adminList` (no [data-list="admins"]), generic sliders (risky ID match) |
| **Recommended** (stability) | 8 | Time sliders (add label context), fields (add chakra-), unconfirmed fields (label-for/placeholder) |
| **Optional** (enhancements) | 5 | Add Car/Track buttons (dynamic count handling), BLOCKED_SELECTORS (chakra-button) |
| **Verified/Matches** | 70+ | Wizard nav/step IDs, most buttons/text |
**Total selectors needing updates: 15**
## Selector Verification Tables
### login
| Selector | Current Selector | Status | Evidence (Dump) | Proposed | Priority |
|----------|------------------|--------|-----------------|----------|----------|
| emailInput | `#username, input[name="username"], input[type="email"]` | Unconfirmed | No login dump | N/A | - |
| passwordInput | `#password, input[type="password"]` | Unconfirmed | No login dump | N/A | - |
| submitButton | `button[type="submit"], button:has-text("Sign In")` | Unconfirmed | No login dump | N/A | - |
### hostedRacing
| Selector | Current Selector | Status | Evidence (Dump) | Proposed | Priority |
|----------|------------------|--------|-----------------|----------|----------|
| createRaceButton | `button:has-text("Create a Race"), button[aria-label="Create a Race"]` | Matches | 01-hosted-racing.json: `bu.chakra-button:0 t:"Create a Race"` | N/A | Verified |
| hostedTab | `a:has-text("Hosted")` | Matches | 01: sidebar `a.c0:2 t:"Hosted"` | N/A | Verified |
| createRaceModal | `#modal-children-container, .modal-content` | Matches | 02: `#confirm-create-race-modal-modal-content` | N/A | Verified |
| newRaceButton | `a.btn:has-text("New Race")` | Matches | 02: `a.btn.btn-lg:1 t:"New Race"` | N/A | Verified |
| lastSettingsButton | `a.btn:has-text("Last Settings")` | Matches | 02: `a.btn.btn-lg:0 t:"Last Settings"` | N/A | Verified |
### wizard
#### Core
| Selector | Current Selector | Status | Evidence | Proposed | Priority |
|----------|------------------|--------|-----------|----------|----------|
| modal | `#create-race-modal-modal-content, .modal-content` | Matches | All dumps: `#create-race-modal-modal-content` | N/A | Verified |
| modalDialog | `.modal-dialog` | Matches | Dumps: `#create-race-modal-modal-dialog` | N/A | Verified |
| modalContent | `#create-race-modal-modal-content, .modal-content` | Matches | Dumps | N/A | Verified |
| modalTitle | `[data-testid="modal-title"], .modal-title` | Unconfirmed | No exact match | `[data-testid="modal-title"]` | Optional |
| nextButton | `.wizard-footer a.btn:last-child` | Matches | 03,05,07: `d.wizard-footer@4>d.pull-xs-left>a.btn.btn-sm:1` (dynamic text) | N/A | Verified |
| backButton | `.wizard-footer a.btn:first-child` | Matches | Dumps: first-child | N/A | Verified |
| confirmButton | `.modal-footer a.btn-success, button:has-text("Confirm")` | Unconfirmed | No final confirm dump | N/A | - |
| cancelButton | `.modal-footer a.btn-secondary:has-text("Back")` | Matches | Dumps: "Back" | N/A | Verified |
| closeButton | `[data-testid="button-close-modal"]` | Matches | Dumps: `data-testid=button-close-modal` | N/A | Verified |
#### sidebarLinks (all Matches - data-testid exact)
| Selector | Status | Evidence |
|----------|--------|----------|
| raceInformation | Matches | 03+: `data-testid=wizard-nav-set-session-information` |
| ... (all 11) | Matches | Exact data-testid in 03,05,07,08 |
#### stepContainers (all Matches - #set-* IDs)
| Selector | Status | Evidence |
|----------|--------|----------|
| raceInformation (#set-session-information) | Matches | 03 |
| admins (#set-admins) | Matches | 05 |
| timeLimit (#set-time-limit) | Matches | 07 |
| cars (#set-cars) | Matches | 08 |
| ... (all 11) | Matches | Dumps |
### fields (Recommended: Add chakra- for stability)
| Selector | Current | Status | Evidence | Proposed | Priority |
|----------|---------|--------|----------|----------|----------|
| textInput | `input.form-control, .chakra-input, ...` | Matches | Chakra inputs in dumps | `.chakra-input, input[placeholder], input[type="text"]` | Recommended |
| ... (similar for others) | Partial | Chakra dominant | Add chakra- prefixes | Recommended |
### steps (Key issues highlighted)
| Selector | Current | Status | Evidence (Dump) | Proposed | Priority |
|----------|---------|--------|-----------------|----------|----------|
| sessionName | `#set-session-information .card-block .form-group:first-of-type input.form-control, ...` | Unconfirmed | 03: form-groups, chakra-input | `label:has-text("Session Name") ~ input.chakra-input` | Recommended |
| password | Complex | Unconfirmed | 03 | `label:has-text("Password") ~ input[type="password"], input[placeholder*="Password"]` | Recommended |
| adminList | `[data-list="admins"]` | No Match | 05: no data-list; #set-admins card | `#set-admins table.table.table-striped, #set-admins .card-block table` | Critical |
| practice | `input[id*="time-limit-slider"]` | Matches but risky | 07: `time-limit-slider1764248520320` | `label:has-text("Practice") ~ div input[id*="time-limit-slider"]` | Recommended |
| qualify/race | Similar | Matches risky | 07 | Label proximity | Recommended |
| addCarButton | `a.btn:has-text("Add a Car")` | Matches | 08: `a.btn.btn-sm t:"Add a Car 16 Available"` | `a.btn:has-text("Add a Car")` (handles dynamic) | Verified |
| carList | `table.table.table-striped` | Matches | 08: many `table.table.table-striped` | `#set-cars table.table.table-striped` | Verified |
| ... (track similar) | Matches | 08+ | N/A | Verified |
### BLOCKED_SELECTORS (Optional: Chakra enhancements)
| Selector | Status | Proposed | Priority |
|----------|--------|----------|----------|
| checkout | Matches | Add `.chakra-button:has-text("Check Out")` | Optional |
| ... | Matches | Minor | Optional |
## BDD Scenarios for Verification
- GIVEN hosted page (01), THEN `hostedRacing.createRaceButton` finds 1 button.
- GIVEN #set-admins (05), THEN `steps.adminList` finds 1 table; `addAdminButton` finds 1.
- GIVEN time-limits (07), THEN `steps.practice` finds 1 slider near "Practice" label.
- GIVEN cars (08), THEN `carList` finds table; `addCarButton:has-text("Add a Car")` finds 1.
- GIVEN any step, THEN `wizard.nextButton:last-child` enabled, finds 1.
**Run via Playwright: `expect(page.locator(selector)).toHaveCount(1)` per scenario.**
## Docker E2E Impacts
No major changes; selectors stable. Minor fixture updates if sliders refined (update E2ETestBrowserLauncher.ts expectations). Test post-update.
## Implementation Roadmap (for Code mode)
1. Apply Critical/Recommended updates via apply_diff.
2. Verify with browser_action on local iRacing mock/fixture.
3. Add BDD tests in tests/.