fix(automation): resilient wizard selectors + nav-click fallback for Weather/Cars/RaceInfo

This commit is contained in:
2025-11-26 17:47:15 +01:00
parent b6b8303f38
commit cd810b024c

View File

@@ -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"
if (this.isRealMode()) {
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
@@ -1047,7 +1061,30 @@ export class PlaywrightAutomationAdapter implements IBrowserAutomation, IAuthent
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);
}
@@ -1057,7 +1094,7 @@ export class PlaywrightAutomationAdapter implements IBrowserAutomation, IAuthent
expectedStep: 'cars',
requiredSelectors: this.isRealMode()
? [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']
});
@@ -1126,7 +1163,7 @@ export class PlaywrightAutomationAdapter implements IBrowserAutomation, IAuthent
expectedStep: 'cars',
requiredSelectors: this.isRealMode()
? [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']
});
@@ -1357,7 +1394,30 @@ export class PlaywrightAutomationAdapter implements IBrowserAutomation, IAuthent
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);
}
if (config.timeOfDay !== undefined) {