fix(automation): resilient wizard selectors + nav-click fallback for Weather/Cars/RaceInfo
This commit is contained in:
@@ -960,6 +960,20 @@ export class PlaywrightAutomationAdapter implements IBrowserAutomation, IAuthent
|
|||||||
// In real mode, a modal appears asking "Last Settings" or "New Race" - click "New Race"
|
// In real mode, a modal appears asking "Last Settings" or "New Race" - click "New Race"
|
||||||
if (this.isRealMode()) {
|
if (this.isRealMode()) {
|
||||||
await this.clickNewRaceInModal();
|
await this.clickNewRaceInModal();
|
||||||
|
// Ensure Race Information panel is visible by clicking sidebar nav then waiting for fallback selectors
|
||||||
|
const raceInfoFallback = '#set-session-information, .wizard-step[id*="session"], .wizard-step[id*="race-information"]';
|
||||||
|
try {
|
||||||
|
try { await this.page!.click('[data-testid="wizard-nav-set-session-information"]'); this.log('debug','Clicked wizard nav for Race Information', { selector: '[data-testid="wizard-nav-set-session-information"]' }); } catch (e) { this.log('debug','Wizard nav for Race Information not present (continuing)', { error: String(e) }); }
|
||||||
|
await this.page!.waitForSelector(raceInfoFallback, { state: 'attached', timeout: 5000 });
|
||||||
|
this.log('info','Race Information panel found', { selector: raceInfoFallback });
|
||||||
|
} catch (err) {
|
||||||
|
this.log('warn','Race Information panel not found with fallback selector, dumping #create-race-wizard innerHTML', { selector: raceInfoFallback });
|
||||||
|
const inner = await this.page!.evaluate(() => document.querySelector('#create-race-wizard')?.innerHTML || '');
|
||||||
|
this.log('debug','create-race-wizard innerHTML (truncated)', { html: inner ? inner.substring(0,2000) : '' });
|
||||||
|
// Retry nav click once then wait longer before failing
|
||||||
|
try { await this.page!.click('[data-testid="wizard-nav-set-session-information"]'); } catch {}
|
||||||
|
await this.page!.waitForSelector(raceInfoFallback, { state: 'attached', timeout: 10000 });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fill form fields if provided
|
// Fill form fields if provided
|
||||||
@@ -1047,7 +1061,30 @@ export class PlaywrightAutomationAdapter implements IBrowserAutomation, IAuthent
|
|||||||
return { success: true };
|
return { success: true };
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.waitForWizardStep('cars');
|
// Robust: try opening Cars via sidebar nav then wait for a set of fallback selectors.
|
||||||
|
const carsFallbackSelector = '#set-cars, .wizard-step[id*="cars"], .cars-panel';
|
||||||
|
try {
|
||||||
|
try {
|
||||||
|
await this.page!.click('[data-testid="wizard-nav-set-cars"]');
|
||||||
|
this.log('debug', 'Clicked wizard nav for Cars', { selector: '[data-testid="wizard-nav-set-cars"]' });
|
||||||
|
} catch (e) {
|
||||||
|
this.log('debug', 'Wizard nav for Cars not present (continuing)', { error: String(e) });
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await this.page!.waitForSelector(carsFallbackSelector, { state: 'attached', timeout: 5000 });
|
||||||
|
this.log('info', 'Cars panel found', { selector: carsFallbackSelector });
|
||||||
|
} catch (err) {
|
||||||
|
this.log('warn', 'Cars panel not found with fallback selector, dumping #create-race-wizard innerHTML', { selector: carsFallbackSelector });
|
||||||
|
const inner = await this.page!.evaluate(() => document.querySelector('#create-race-wizard')?.innerHTML || '');
|
||||||
|
this.log('debug', 'create-race-wizard innerHTML (truncated)', { html: inner ? inner.substring(0, 2000) : '' });
|
||||||
|
// Retry nav click once then wait longer before failing
|
||||||
|
try { await this.page!.click('[data-testid="wizard-nav-set-cars"]'); } catch {}
|
||||||
|
await this.page!.waitForSelector(carsFallbackSelector, { state: 'attached', timeout: 10000 });
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
this.log('error', 'Failed waiting for Cars panel', { error: String(e), selector: carsFallbackSelector });
|
||||||
|
}
|
||||||
await this.checkWizardDismissed(step);
|
await this.checkWizardDismissed(step);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1057,7 +1094,7 @@ export class PlaywrightAutomationAdapter implements IBrowserAutomation, IAuthent
|
|||||||
expectedStep: 'cars',
|
expectedStep: 'cars',
|
||||||
requiredSelectors: this.isRealMode()
|
requiredSelectors: this.isRealMode()
|
||||||
? [IRACING_SELECTORS.steps.addCarButton]
|
? [IRACING_SELECTORS.steps.addCarButton]
|
||||||
: ['#set-cars'], // Mock mode: check for Cars container
|
: ['#set-cars, .wizard-step[id*="cars"], .cars-panel'], // Mock mode: check for Cars container (fallbacks)
|
||||||
forbiddenSelectors: ['#set-track']
|
forbiddenSelectors: ['#set-track']
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1126,7 +1163,7 @@ export class PlaywrightAutomationAdapter implements IBrowserAutomation, IAuthent
|
|||||||
expectedStep: 'cars',
|
expectedStep: 'cars',
|
||||||
requiredSelectors: this.isRealMode()
|
requiredSelectors: this.isRealMode()
|
||||||
? [IRACING_SELECTORS.steps.addCarButton]
|
? [IRACING_SELECTORS.steps.addCarButton]
|
||||||
: ['#set-cars'], // Mock mode: check for Cars container
|
: ['#set-cars, .wizard-step[id*="cars"], .cars-panel'], // Mock mode: check for Cars container (fallbacks)
|
||||||
forbiddenSelectors: ['#set-track']
|
forbiddenSelectors: ['#set-track']
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1357,7 +1394,30 @@ export class PlaywrightAutomationAdapter implements IBrowserAutomation, IAuthent
|
|||||||
return { success: true };
|
return { success: true };
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.waitForWizardStep('weather');
|
// Robust: try opening Weather via sidebar nav then wait for a set of fallback selectors.
|
||||||
|
const weatherFallbackSelector = '#set-weather, .wizard-step[id*="weather"], .wizard-step[data-step="weather"], .weather-panel';
|
||||||
|
try {
|
||||||
|
try {
|
||||||
|
await this.page!.click('[data-testid="wizard-nav-set-weather"]');
|
||||||
|
this.log('debug', 'Clicked wizard nav for Weather', { selector: '[data-testid="wizard-nav-set-weather"]' });
|
||||||
|
} catch (e) {
|
||||||
|
this.log('debug', 'Wizard nav for Weather not present (continuing)', { error: String(e) });
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await this.page!.waitForSelector(weatherFallbackSelector, { state: 'attached', timeout: 5000 });
|
||||||
|
this.log('info', 'Weather panel found', { selector: weatherFallbackSelector });
|
||||||
|
} catch (err) {
|
||||||
|
this.log('warn', 'Weather panel not found with fallback selector, dumping #create-race-wizard innerHTML', { selector: weatherFallbackSelector });
|
||||||
|
const inner = await this.page!.evaluate(() => document.querySelector('#create-race-wizard')?.innerHTML || '');
|
||||||
|
this.log('debug', 'create-race-wizard innerHTML (truncated)', { html: inner ? inner.substring(0, 2000) : '' });
|
||||||
|
// Retry nav click once then wait longer before failing
|
||||||
|
try { await this.page!.click('[data-testid="wizard-nav-set-weather"]'); } catch {}
|
||||||
|
await this.page!.waitForSelector(weatherFallbackSelector, { state: 'attached', timeout: 10000 });
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
this.log('error', 'Failed waiting for Weather panel', { error: String(e), selector: weatherFallbackSelector });
|
||||||
|
}
|
||||||
await this.checkWizardDismissed(step);
|
await this.checkWizardDismissed(step);
|
||||||
}
|
}
|
||||||
if (config.timeOfDay !== undefined) {
|
if (config.timeOfDay !== undefined) {
|
||||||
|
|||||||
Reference in New Issue
Block a user