refactoring
This commit is contained in:
@@ -0,0 +1,123 @@
|
||||
import type { Page } from 'playwright';
|
||||
import type { ILogger } from '../../../../application/ports/ILogger';
|
||||
import type { IPlaywrightAuthFlow } from './PlaywrightAuthFlow';
|
||||
import { IRACING_URLS, IRACING_SELECTORS, IRACING_TIMEOUTS } from '../dom/IRacingSelectors';
|
||||
import { AuthenticationGuard } from './AuthenticationGuard';
|
||||
|
||||
export class IRacingPlaywrightAuthFlow implements IPlaywrightAuthFlow {
|
||||
constructor(private readonly logger?: ILogger) {}
|
||||
|
||||
getLoginUrl(): string {
|
||||
return IRACING_URLS.login;
|
||||
}
|
||||
|
||||
getPostLoginLandingUrl(): string {
|
||||
return IRACING_URLS.hostedSessions;
|
||||
}
|
||||
|
||||
isLoginUrl(url: string): boolean {
|
||||
const lower = url.toLowerCase();
|
||||
return (
|
||||
lower.includes('oauth.iracing.com') ||
|
||||
lower.includes('/membersite/login') ||
|
||||
lower.includes('/login.jsp') ||
|
||||
lower.includes('/login')
|
||||
);
|
||||
}
|
||||
|
||||
isAuthenticatedUrl(url: string): boolean {
|
||||
const lower = url.toLowerCase();
|
||||
return (
|
||||
lower.includes('/web/racing/hosted') ||
|
||||
lower.includes('/membersite/member') ||
|
||||
lower.includes('members-ng.iracing.com') ||
|
||||
lower.startsWith(IRACING_URLS.hostedSessions.toLowerCase()) ||
|
||||
lower.startsWith(IRACING_URLS.home.toLowerCase())
|
||||
);
|
||||
}
|
||||
|
||||
isLoginSuccessUrl(url: string): boolean {
|
||||
return this.isAuthenticatedUrl(url) && !this.isLoginUrl(url);
|
||||
}
|
||||
|
||||
async detectAuthenticatedUi(page: Page): Promise<boolean> {
|
||||
const authSelectors = [
|
||||
IRACING_SELECTORS.hostedRacing.createRaceButton,
|
||||
'[aria-label*="user menu" i]',
|
||||
'[aria-label*="account menu" i]',
|
||||
'.user-menu',
|
||||
'.account-menu',
|
||||
'nav a[href*="/membersite"]',
|
||||
'nav a[href*="/members"]',
|
||||
];
|
||||
|
||||
for (const selector of authSelectors) {
|
||||
try {
|
||||
const element = page.locator(selector).first();
|
||||
const isVisible = await element.isVisible().catch(() => false);
|
||||
if (isVisible) {
|
||||
this.logger?.info?.('Authenticated UI detected', { selector });
|
||||
return true;
|
||||
}
|
||||
} catch {
|
||||
// Ignore selector errors, try next selector
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
async detectLoginUi(page: Page): Promise<boolean> {
|
||||
const guard = new AuthenticationGuard(page, this.logger);
|
||||
return guard.checkForLoginUI();
|
||||
}
|
||||
|
||||
async navigateToAuthenticatedArea(page: Page): Promise<void> {
|
||||
await page.goto(this.getPostLoginLandingUrl(), {
|
||||
waitUntil: 'domcontentloaded',
|
||||
timeout: IRACING_TIMEOUTS.navigation,
|
||||
});
|
||||
}
|
||||
|
||||
async waitForPostLoginRedirect(page: Page, timeoutMs: number): Promise<boolean> {
|
||||
const start = Date.now();
|
||||
this.logger?.info?.('Waiting for post-login redirect', { timeoutMs });
|
||||
|
||||
while (Date.now() - start < timeoutMs) {
|
||||
try {
|
||||
if (page.isClosed()) {
|
||||
this.logger?.warn?.('Page closed while waiting for post-login redirect');
|
||||
return false;
|
||||
}
|
||||
|
||||
const url = page.url();
|
||||
|
||||
if (this.isLoginSuccessUrl(url)) {
|
||||
this.logger?.info?.('Login success detected by URL', { url });
|
||||
return true;
|
||||
}
|
||||
|
||||
// Fallback: detect authenticated UI even if URL is not the canonical one
|
||||
const hasAuthUi = await this.detectAuthenticatedUi(page);
|
||||
if (hasAuthUi) {
|
||||
this.logger?.info?.('Login success detected by authenticated UI', { url });
|
||||
return true;
|
||||
}
|
||||
|
||||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : String(error);
|
||||
this.logger?.debug?.('Error while waiting for post-login redirect', { error: message });
|
||||
|
||||
if (page.isClosed()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
await new Promise((resolve) => setTimeout(resolve, 500));
|
||||
}
|
||||
}
|
||||
|
||||
this.logger?.warn?.('Post-login redirect wait timed out', { timeoutMs });
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user