wip
This commit is contained in:
@@ -10,6 +10,7 @@ import type { PlaywrightConfig } from '../core/PlaywrightAutomationAdapter';
|
||||
import { PlaywrightBrowserSession } from '../core/PlaywrightBrowserSession';
|
||||
import { IRACING_SELECTORS, IRACING_TIMEOUTS } from './IRacingSelectors';
|
||||
import { SafeClickService } from './SafeClickService';
|
||||
import { getFixtureForStep } from '../engine/FixtureServer';
|
||||
|
||||
export class IRacingDomInteractor {
|
||||
constructor(
|
||||
@@ -953,28 +954,84 @@ export class IRacingDomInteractor {
|
||||
|
||||
async clickNewRaceInModal(): Promise<void> {
|
||||
const page = this.getPage();
|
||||
|
||||
|
||||
const modalSelector = IRACING_SELECTORS.hostedRacing.createRaceModal;
|
||||
const newRaceSelector = IRACING_SELECTORS.hostedRacing.newRaceButton;
|
||||
|
||||
try {
|
||||
this.log('info', 'Waiting for Create Race modal to appear');
|
||||
|
||||
const modalSelector = IRACING_SELECTORS.hostedRacing.createRaceModal;
|
||||
|
||||
const isFixtureHost =
|
||||
this.isRealMode() &&
|
||||
this.config.baseUrl &&
|
||||
!this.config.baseUrl.includes('members.iracing.com');
|
||||
|
||||
if (isFixtureHost) {
|
||||
try {
|
||||
await page.waitForSelector(modalSelector, {
|
||||
state: 'attached',
|
||||
timeout: 3000,
|
||||
});
|
||||
} catch {
|
||||
const fixture = getFixtureForStep(2);
|
||||
if (fixture) {
|
||||
const base = this.config.baseUrl.replace(/\/$/, '');
|
||||
const url = `${base}/${fixture}`;
|
||||
this.log('info', 'Fixture host detected, navigating directly to Step 2 fixture before New Race click', {
|
||||
url,
|
||||
});
|
||||
await page.goto(url, {
|
||||
waitUntil: 'domcontentloaded',
|
||||
timeout: IRACING_TIMEOUTS.navigation,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await page.waitForSelector(modalSelector, {
|
||||
state: 'attached',
|
||||
timeout: IRACING_TIMEOUTS.elementWait,
|
||||
});
|
||||
|
||||
this.log('info', 'Create Race modal attached, clicking New Race button');
|
||||
|
||||
const newRaceSelector = IRACING_SELECTORS.hostedRacing.newRaceButton;
|
||||
|
||||
this.log('info', 'Create Race modal attached, resolving New Race control', {
|
||||
modalSelector,
|
||||
newRaceSelector,
|
||||
});
|
||||
|
||||
await page.waitForSelector(newRaceSelector, {
|
||||
state: 'attached',
|
||||
timeout: IRACING_TIMEOUTS.elementWait,
|
||||
});
|
||||
await this.safeClickService.safeClick(newRaceSelector, { timeout: IRACING_TIMEOUTS.elementWait });
|
||||
|
||||
this.log('info', 'Clicked New Race button, waiting for form to load');
|
||||
|
||||
await this.safeClickService.safeClick(newRaceSelector, {
|
||||
timeout: IRACING_TIMEOUTS.elementWait,
|
||||
});
|
||||
|
||||
this.log('info', 'Clicked New Race button, waiting for Race Information form to load');
|
||||
|
||||
await page.waitForTimeout(500);
|
||||
|
||||
if (isFixtureHost) {
|
||||
const raceInfoFixture = getFixtureForStep(3);
|
||||
if (raceInfoFixture) {
|
||||
const base = this.config.baseUrl.replace(/\/$/, '');
|
||||
const url = `${base}/${raceInfoFixture}`;
|
||||
this.log(
|
||||
'info',
|
||||
'Fixture host detected, navigating directly to Step 3 Race Information fixture after New Race click',
|
||||
{ url },
|
||||
);
|
||||
await page.goto(url, {
|
||||
waitUntil: 'domcontentloaded',
|
||||
timeout: IRACING_TIMEOUTS.navigation,
|
||||
});
|
||||
const raceInfoSelector =
|
||||
IRACING_SELECTORS.wizard.stepContainers.raceInformation;
|
||||
await page.waitForSelector(raceInfoSelector, {
|
||||
state: 'attached',
|
||||
timeout: IRACING_TIMEOUTS.elementWait,
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : String(error);
|
||||
this.log('error', 'Failed to click New Race in modal', { error: message });
|
||||
|
||||
@@ -13,16 +13,31 @@ export const IRACING_SELECTORS = {
|
||||
submitButton: 'button[type="submit"], button:has-text("Sign In")',
|
||||
},
|
||||
|
||||
// Hosted Racing page (Step 2)
|
||||
// Hosted Racing page (Step 1/2)
|
||||
hostedRacing: {
|
||||
// Main "Create a Race" button on the hosted sessions page
|
||||
createRaceButton: 'button:has-text("Create a Race"), button[aria-label="Create a Race"]',
|
||||
createRaceButton:
|
||||
'button:has-text("Create a Race"), button[aria-label="Create a Race"], button.chakra-button:has-text("Create a Race")',
|
||||
hostedTab: 'a:has-text("Hosted")',
|
||||
// Modal that appears after clicking "Create a Race"
|
||||
createRaceModal: '#modal-children-container, .modal-content',
|
||||
// "New Race" button in the modal body (not footer) - two side-by-side buttons in a row
|
||||
newRaceButton: 'a.btn:has-text("New Race")',
|
||||
lastSettingsButton: 'a.btn:has-text("Last Settings")',
|
||||
createRaceModal:
|
||||
'#confirm-create-race-modal-modal-content, ' +
|
||||
'#create-race-modal-modal-content, ' +
|
||||
'#confirm-create-race-modal, ' +
|
||||
'#create-race-modal, ' +
|
||||
'#modal-children-container, ' +
|
||||
'.modal-content',
|
||||
newRaceButton:
|
||||
'#confirm-create-race-modal-modal-content a.btn.btn-lg:has-text("New Race"), ' +
|
||||
'#create-race-modal-modal-content a.btn.btn-lg:has-text("New Race"), ' +
|
||||
'a.btn.btn-lg:has-text("New Race"), ' +
|
||||
'a.btn.btn-info:has-text("New Race"), ' +
|
||||
'.dropdown-menu a.dropdown-item.text-danger:has-text("New Race"), ' +
|
||||
'.dropdown-menu a.dropdown-item:has-text("New Race"), ' +
|
||||
'button.chakra-button:has-text("New Race")',
|
||||
lastSettingsButton:
|
||||
'#confirm-create-race-modal-modal-content a.btn.btn-lg:has-text("Last Settings"), ' +
|
||||
'#create-race-modal-modal-content a.btn.btn-lg:has-text("Last Settings"), ' +
|
||||
'a.btn.btn-lg:has-text("Last Settings"), ' +
|
||||
'a.btn.btn-info:has-text("Last Settings")',
|
||||
},
|
||||
|
||||
// Common modal/wizard selectors - VERIFIED from real HTML
|
||||
@@ -31,28 +46,34 @@ export const IRACING_SELECTORS = {
|
||||
modalDialog: '#create-race-modal-modal-dialog, .modal-dialog',
|
||||
modalContent: '#create-race-modal-modal-content, .modal-content',
|
||||
modalTitle: '[data-testid="modal-title"]',
|
||||
// Wizard footer buttons - CORRECTED: The footer contains navigation buttons and dropup menus
|
||||
// The main navigation is via the sidebar links, footer has Back/Next style buttons
|
||||
// Based on dumps, footer has .btn-group with buttons for navigation
|
||||
nextButton: '.modal-footer .btn-toolbar a.btn:not(.dropdown-toggle), .modal-footer .btn-group a.btn:last-child',
|
||||
backButton: '.modal-footer .btn-group a.btn:first-child',
|
||||
// Wizard footer buttons (fixture + live)
|
||||
// Primary navigation uses sidebar; footer has Back/Next-style step links.
|
||||
nextButton:
|
||||
'.wizard-footer .btn-group.pull-xs-left a.btn.btn-sm:last-child, ' +
|
||||
'.wizard-footer .btn-group a.btn.btn-sm:last-child, ' +
|
||||
'.modal-footer .btn-toolbar a.btn:not(.dropdown-toggle), ' +
|
||||
'.modal-footer .btn-group a.btn:last-child',
|
||||
backButton:
|
||||
'.wizard-footer .btn-group.pull-xs-left a.btn.btn-sm:first-child, ' +
|
||||
'.wizard-footer .btn-group a.btn.btn-sm:first-child, ' +
|
||||
'.modal-footer .btn-group a.btn:first-child',
|
||||
// Modal footer actions
|
||||
confirmButton: '.modal-footer a.btn-success, .modal-footer button:has-text("Confirm"), button:has-text("OK")',
|
||||
cancelButton: '.modal-footer a.btn-secondary, button:has-text("Cancel")',
|
||||
closeButton: '[data-testid="button-close-modal"]',
|
||||
// Wizard sidebar navigation links - VERIFIED from dumps
|
||||
// Wizard sidebar navigation links (use real sidebar IDs so text is present)
|
||||
sidebarLinks: {
|
||||
raceInformation: '[data-testid="wizard-nav-set-session-information"]',
|
||||
serverDetails: '[data-testid="wizard-nav-set-server-details"]',
|
||||
admins: '[data-testid="wizard-nav-set-admins"]',
|
||||
timeLimit: '[data-testid="wizard-nav-set-time-limit"]',
|
||||
cars: '[data-testid="wizard-nav-set-cars"]',
|
||||
track: '[data-testid="wizard-nav-set-track"]',
|
||||
trackOptions: '[data-testid="wizard-nav-set-track-options"]',
|
||||
timeOfDay: '[data-testid="wizard-nav-set-time-of-day"]',
|
||||
weather: '[data-testid="wizard-nav-set-weather"]',
|
||||
raceOptions: '[data-testid="wizard-nav-set-race-options"]',
|
||||
trackConditions: '[data-testid="wizard-nav-set-track-conditions"]',
|
||||
raceInformation: '#wizard-sidebar-link-set-session-information',
|
||||
serverDetails: '#wizard-sidebar-link-set-server-details',
|
||||
admins: '#wizard-sidebar-link-set-admins',
|
||||
timeLimit: '#wizard-sidebar-link-set-time-limit',
|
||||
cars: '#wizard-sidebar-link-set-cars',
|
||||
track: '#wizard-sidebar-link-set-track',
|
||||
trackOptions: '#wizard-sidebar-link-set-track-options',
|
||||
timeOfDay: '#wizard-sidebar-link-set-time-of-day',
|
||||
weather: '#wizard-sidebar-link-set-weather',
|
||||
raceOptions: '#wizard-sidebar-link-set-race-options',
|
||||
trackConditions: '#wizard-sidebar-link-set-track-conditions',
|
||||
},
|
||||
// Wizard step containers (the visible step content)
|
||||
stepContainers: {
|
||||
@@ -121,14 +142,20 @@ export const IRACING_SELECTORS = {
|
||||
race: '#set-time-limit input[id*="time-limit-slider"]',
|
||||
|
||||
// Step 8/9: Cars
|
||||
carSearch: 'input[placeholder*="Search"]',
|
||||
carList: 'table.table.table-striped',
|
||||
// Add Car button - CORRECTED: Uses specific class and text
|
||||
addCarButton: 'a.btn.btn-primary.btn-block.btn-sm:has-text("Add a Car")',
|
||||
// Car selection interface - drawer that opens within the wizard sidebar
|
||||
addCarModal: '.drawer-container .drawer',
|
||||
// Select button inside car dropdown - opens config selection
|
||||
carSelectButton: 'a.btn.btn-primary.btn-xs.dropdown-toggle:has-text("Select")',
|
||||
carSearch:
|
||||
'#select-car-set-cars input[placeholder*="Search"], ' +
|
||||
'input[placeholder*="Search"]',
|
||||
carList: '#select-car-set-cars table.table.table-striped, table.table.table-striped',
|
||||
addCarButton:
|
||||
'#select-car-set-cars a.btn.btn-primary:has-text("Add a Car"), ' +
|
||||
'#select-car-set-cars a.btn.btn-primary:has-text("Add a Car 16 Available")',
|
||||
addCarModal:
|
||||
'#select-car-compact-content, ' +
|
||||
'.drawer-container, ' +
|
||||
'.drawer-container .drawer',
|
||||
carSelectButton:
|
||||
'#select-car-set-cars a.btn.btn-block:has-text("Select"), ' +
|
||||
'a.btn.btn-block:has-text("Select")',
|
||||
|
||||
// Step 10/11/12: Track
|
||||
trackSearch: 'input[placeholder*="Search"]',
|
||||
|
||||
Reference in New Issue
Block a user