linting
This commit is contained in:
@@ -7,9 +7,9 @@
|
||||
|
||||
import type { AsyncUseCase } from '@core/shared/application';
|
||||
import type { Logger } from '@core/shared/application';
|
||||
import type { IPageViewRepository } from '../../domain/repositories/IPageViewRepository';
|
||||
import type { IEngagementRepository } from '../../domain/repositories/IEngagementRepository';
|
||||
import type { IAnalyticsSnapshotRepository } from '../../domain/repositories/IAnalyticsSnapshotRepository';
|
||||
import type { IPageViewRepository } from '../repositories/IPageViewRepository';
|
||||
import type { IEngagementRepository } from '@core/analytics/domain/repositories/IEngagementRepository';
|
||||
import type { IAnalyticsSnapshotRepository } from '@core/analytics/domain/repositories/IAnalyticsSnapshotRepository';
|
||||
import type { EntityType } from '../../domain/types/PageView';
|
||||
import type { SnapshotPeriod } from '../../domain/types/AnalyticsSnapshot';
|
||||
|
||||
@@ -69,7 +69,8 @@ export class GetEntityAnalyticsQuery
|
||||
);
|
||||
this.logger.debug(`Total page views for entity ${input.entityId}: ${totalPageViews}`);
|
||||
} catch (error) {
|
||||
this.logger.error(`Error counting total page views for entity ${input.entityId}: ${error.message}`);
|
||||
const err = error instanceof Error ? error : new Error(String(error));
|
||||
this.logger.error(`Error counting total page views for entity ${input.entityId}: ${err.message}`);
|
||||
throw error;
|
||||
}
|
||||
|
||||
@@ -82,7 +83,8 @@ export class GetEntityAnalyticsQuery
|
||||
);
|
||||
this.logger.debug(`Unique visitors for entity ${input.entityId}: ${uniqueVisitors}`);
|
||||
} catch (error) {
|
||||
this.logger.error(`Error counting unique visitors for entity ${input.entityId}: ${error.message}`);
|
||||
const err = error instanceof Error ? error : new Error(String(error));
|
||||
this.logger.error(`Error counting unique visitors for entity ${input.entityId}: ${err.message}`);
|
||||
throw error;
|
||||
}
|
||||
|
||||
@@ -94,7 +96,8 @@ export class GetEntityAnalyticsQuery
|
||||
);
|
||||
this.logger.debug(`Sponsor clicks for entity ${input.entityId}: ${sponsorClicks}`);
|
||||
} catch (error) {
|
||||
this.logger.error(`Error getting sponsor clicks for entity ${input.entityId}: ${error.message}`);
|
||||
const err = error instanceof Error ? error : new Error(String(error));
|
||||
this.logger.error(`Error getting sponsor clicks for entity ${input.entityId}: ${err.message}`);
|
||||
throw error;
|
||||
}
|
||||
|
||||
@@ -104,7 +107,8 @@ export class GetEntityAnalyticsQuery
|
||||
engagementScore = await this.calculateEngagementScore(input.entityId, since);
|
||||
this.logger.debug(`Engagement score for entity ${input.entityId}: ${engagementScore}`);
|
||||
} catch (error) {
|
||||
this.logger.error(`Error calculating engagement score for entity ${input.entityId}: ${error.message}`);
|
||||
const err = error instanceof Error ? error : new Error(String(error));
|
||||
this.logger.error(`Error calculating engagement score for entity ${input.entityId}: ${err.message}`);
|
||||
throw error;
|
||||
}
|
||||
|
||||
@@ -130,7 +134,8 @@ export class GetEntityAnalyticsQuery
|
||||
previousPageViews = fullPreviousPageViews - totalPageViews; // This calculates change, not just previous period's total
|
||||
this.logger.debug(`Previous period full page views: ${fullPreviousPageViews}, change: ${previousPageViews}`);
|
||||
} catch (error) {
|
||||
this.logger.error(`Error counting previous period page views for entity ${input.entityId}: ${error.message}`);
|
||||
const err = error instanceof Error ? error : new Error(String(error));
|
||||
this.logger.error(`Error counting previous period page views for entity ${input.entityId}: ${err.message}`);
|
||||
throw error;
|
||||
}
|
||||
|
||||
@@ -145,7 +150,8 @@ export class GetEntityAnalyticsQuery
|
||||
this.logger.debug(`Previous period full unique visitors: ${fullPreviousUniqueVisitors}, change: ${previousUniqueVisitors}`);
|
||||
|
||||
} catch (error) {
|
||||
this.logger.error(`Error counting previous period unique visitors for entity ${input.entityId}: ${error.message}`);
|
||||
const err = error instanceof Error ? error : new Error(String(error));
|
||||
this.logger.error(`Error counting previous period unique visitors for entity ${input.entityId}: ${err.message}`);
|
||||
throw error;
|
||||
}
|
||||
|
||||
@@ -218,7 +224,8 @@ export class GetEntityAnalyticsQuery
|
||||
sponsorClicks = await this.engagementRepository.getSponsorClicksForEntity(entityId, since);
|
||||
this.logger.debug(`Sponsor clicks for engagement score for entity ${entityId}: ${sponsorClicks}`);
|
||||
} catch (error) {
|
||||
this.logger.error(`Error getting sponsor clicks for engagement score for entity ${entityId}: ${error.message}`);
|
||||
const err = error instanceof Error ? error : new Error(String(error));
|
||||
this.logger.error(`Error getting sponsor clicks for engagement score for entity ${entityId}: ${err.message}`);
|
||||
throw error;
|
||||
}
|
||||
const score = sponsorClicks * 10; // Weighted score
|
||||
|
||||
@@ -8,7 +8,7 @@ import type { AsyncUseCase } from '@core/shared/application';
|
||||
import type { Logger } from '@core/shared/application';
|
||||
import { PageView } from '../../domain/entities/PageView';
|
||||
import type { EntityType, VisitorType } from '../../domain/types/PageView';
|
||||
import type { IPageViewRepository } from '../../domain/repositories/IPageViewRepository';
|
||||
import type { IPageViewRepository } from '../repositories/IPageViewRepository';
|
||||
|
||||
export interface RecordPageViewInput {
|
||||
entityType: EntityType;
|
||||
@@ -57,7 +57,8 @@ export class RecordPageViewUseCase
|
||||
this.logger.info('Page view recorded successfully', { pageViewId, input });
|
||||
return { pageViewId };
|
||||
} catch (error) {
|
||||
this.logger.error('Error recording page view', error, { input });
|
||||
const err = error instanceof Error ? error : new Error(String(error));
|
||||
this.logger.error('Error recording page view', err, { input });
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
export interface Logger {
|
||||
debug(message: string, ...args: any[]): void;
|
||||
info(message: string, ...args: any[]): void;
|
||||
warn(message: string, ...args: any[]): void;
|
||||
error(message: string, ...args: any[]): void;
|
||||
debug(message: string, ...args: unknown[]): void;
|
||||
info(message: string, ...args: unknown[]): void;
|
||||
warn(message: string, ...args: unknown[]): void;
|
||||
error(message: string, ...args: unknown[]): void;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { AnalyticsEntityId } from '../../../core/analytics/domain/value-objects/AnalyticsEntityId';
|
||||
import { AnalyticsEntityId } from '@core/analytics/domain/value-objects/AnalyticsEntityId';
|
||||
|
||||
describe('AnalyticsEntityId', () => {
|
||||
it('creates a valid AnalyticsEntityId from a non-empty string', () => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { AnalyticsSessionId } from '../../../core/analytics/domain/value-objects/AnalyticsSessionId';
|
||||
import { AnalyticsSessionId } from '@core/analytics/domain/value-objects/AnalyticsSessionId';
|
||||
|
||||
describe('AnalyticsSessionId', () => {
|
||||
it('creates a valid AnalyticsSessionId from a non-empty string', () => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { PageViewId } from '../../../core/analytics/domain/value-objects/PageViewId';
|
||||
import { PageViewId } from '@core/analytics/domain/value-objects/PageViewId';
|
||||
|
||||
describe('PageViewId', () => {
|
||||
it('creates a valid PageViewId from a non-empty string', () => {
|
||||
|
||||
@@ -10,8 +10,8 @@ export * from './domain/entities/PageView';
|
||||
export * from './domain/entities/EngagementEvent';
|
||||
export * from './domain/entities/AnalyticsSnapshot';
|
||||
|
||||
// Domain repositories
|
||||
export * from './domain/repositories/IPageViewRepository';
|
||||
// Application repositories
|
||||
export * from './application/repositories/IPageViewRepository';
|
||||
export * from './domain/repositories/IEngagementRepository';
|
||||
export * from './domain/repositories/IAnalyticsSnapshotRepository';
|
||||
|
||||
@@ -20,7 +20,7 @@ export * from './application/use-cases/RecordPageViewUseCase';
|
||||
export * from './application/use-cases/RecordEngagementUseCase';
|
||||
export * from './application/use-cases/GetEntityAnalyticsQuery';
|
||||
|
||||
// Infrastructure
|
||||
export * from './infrastructure/repositories/InMemoryPageViewRepository';
|
||||
export * from './infrastructure/repositories/InMemoryEngagementRepository';
|
||||
export * from './infrastructure/repositories/InMemoryAnalyticsSnapshotRepository';
|
||||
// Infrastructure (moved to adapters)
|
||||
export type { IPageViewRepository } from './application/repositories/IPageViewRepository';
|
||||
export type { IEngagementRepository } from './domain/repositories/IEngagementRepository';
|
||||
export type { IAnalyticsSnapshotRepository } from './domain/repositories/IAnalyticsSnapshotRepository';
|
||||
@@ -5,7 +5,7 @@ import { CompleteOnboardingPresenter } from '@apps/api/src/modules/driver/presen
|
||||
|
||||
describe('CompleteDriverOnboardingUseCase', () => {
|
||||
let useCase: CompleteDriverOnboardingUseCase;
|
||||
let driverRepository: { findById: any; save: any };
|
||||
let driverRepository: { findById: () => Promise<any>; save: () => Promise<void> };
|
||||
|
||||
beforeEach(() => {
|
||||
driverRepository = {
|
||||
|
||||
@@ -5,7 +5,7 @@ import type { CheckoutServicePort } from '@core/automation/application/ports/Che
|
||||
import type { CheckoutConfirmationPort } from '@core/automation/application/ports/CheckoutConfirmationPort';
|
||||
import type { CheckoutInfoDTO } from '@core/automation/application/dto/CheckoutInfoDTO';
|
||||
import { CheckoutPrice } from '@core/automation/domain/value-objects/CheckoutPrice';
|
||||
import { CheckoutState, CheckoutStateEnum } from '@core/automation/domain/value-objects/CheckoutState';
|
||||
|
||||
import { CheckoutConfirmation } from '@core/automation/domain/value-objects/CheckoutConfirmation';
|
||||
|
||||
/**
|
||||
|
||||
@@ -35,7 +35,7 @@ describe('ICheckoutConfirmationPort contract', () => {
|
||||
it('should define the required interface structure', () => {
|
||||
// This test verifies the port interface contract exists
|
||||
const mockPort: ICheckoutConfirmationPort = {
|
||||
requestCheckoutConfirmation: async (_request: CheckoutConfirmationRequest) => {
|
||||
requestCheckoutConfirmation: async (__request: CheckoutConfirmationRequest) => {
|
||||
return Result.ok(CheckoutConfirmation.create('confirmed'));
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { describe, expect, test } from 'vitest'
|
||||
import { OverlayAction, ActionAck } from '@core/automation/application/ports/IOverlaySyncPort'
|
||||
import { IAutomationEventPublisher, AutomationEvent } from '@core/automation/application/ports/IAutomationEventPublisher'
|
||||
import { OverlayAction } from '@core/automation/application/ports/IOverlaySyncPort'
|
||||
import { IAutomationLifecycleEmitter, LifecycleCallback } from '@core/automation/infrastructure//IAutomationLifecycleEmitter'
|
||||
import { OverlaySyncService } from '@core/automation/application/services/OverlaySyncService'
|
||||
|
||||
@@ -26,7 +25,7 @@ describe('OverlaySyncService (unit)', () => {
|
||||
// create service wiring: pass emitter as dependency (constructor shape expected)
|
||||
const svc = new OverlaySyncService({
|
||||
lifecycleEmitter: emitter,
|
||||
logger: console as any,
|
||||
logger: console as unknown,
|
||||
publisher: { publish: async () => {} },
|
||||
})
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ describe('OverlaySyncService timeout (unit)', () => {
|
||||
const emitter = new MockLifecycleEmitter()
|
||||
const svc = new OverlaySyncService({
|
||||
lifecycleEmitter: emitter,
|
||||
logger: console as any,
|
||||
logger: console as unknown,
|
||||
publisher: { publish: async () => {} },
|
||||
})
|
||||
|
||||
|
||||
@@ -469,7 +469,7 @@ describe('RecalculateChampionshipStandingsUseCase', () => {
|
||||
|
||||
races.forEach((race) => raceRepository.seedRace(race));
|
||||
|
||||
const drivers = ['driver-1', 'driver-2', 'driver-3'];
|
||||
const _drivers = ['driver-1', 'driver-2', 'driver-3'];
|
||||
|
||||
const resultsData: Array<{
|
||||
raceId: string;
|
||||
|
||||
@@ -73,7 +73,7 @@ describe('StartAutomationSessionUseCase', () => {
|
||||
expect(mockSessionRepository.save).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
config,
|
||||
currentStep: expect.objectContaining({ value: 1 }),
|
||||
_currentStep: expect.objectContaining({ value: 1 }),
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import type { LogLevel } from './LoggerLogLevel';
|
||||
import type { LogContext } from './LoggerContext';
|
||||
import type { Logger } from '@core/shared/application';
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { AutomationSession } from '../../domain/entities/AutomationSession';
|
||||
import { SessionStateValue } from '../../domain/value-objects/SessionState';
|
||||
|
||||
|
||||
export interface SessionRepositoryPort {
|
||||
save(session: AutomationSession): Promise<void>;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { OverlaySyncPort, OverlayAction, ActionAck } from '../ports/OverlaySyncPort';
|
||||
|
||||
import { AutomationEventPublisherPort, AutomationEvent } from '../ports/AutomationEventPublisherPort';
|
||||
import { AutomationLifecycleEmitterPort, LifecycleCallback } from '../ports/AutomationLifecycleEmitterPort';
|
||||
import { LoggerPort } from '../ports/LoggerPort';
|
||||
|
||||
@@ -37,7 +37,7 @@ export class ClearSessionUseCase {
|
||||
});
|
||||
}
|
||||
return result;
|
||||
} catch (error: any) {
|
||||
} catch (error) {
|
||||
this.logger.error('Error clearing user session.', error, {
|
||||
useCase: 'ClearSessionUseCase'
|
||||
});
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Result } from '../../../shared/result/Result';
|
||||
import type { Logger } from '@core/shared/application';
|
||||
import type { CheckoutServicePort } from '../ports/CheckoutServicePort';
|
||||
import type { CheckoutConfirmationPort } from '../ports/CheckoutConfirmationPort';
|
||||
import { CheckoutStateEnum } from '../../domain/value-objects/CheckoutState';
|
||||
|
||||
|
||||
interface SessionMetadata {
|
||||
sessionName: string;
|
||||
|
||||
@@ -31,7 +31,7 @@ export class InitiateLoginUseCase {
|
||||
this.logger.warn('Login flow initiation failed.', { error: result.error });
|
||||
}
|
||||
return result;
|
||||
} catch (error: any) {
|
||||
} catch (error) {
|
||||
this.logger.error('Error initiating login flow.', error);
|
||||
return Result.fail(error.message || 'Unknown error during login initiation.');
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { AutomationSession } from '@core/automation/domain/entities/AutomationSession';
|
||||
import { StepId } from '@core/automation/domain/value-objects/StepId';
|
||||
import { SessionState } from '@core/automation/domain/value-objects/SessionState';
|
||||
|
||||
describe('AutomationSession Entity', () => {
|
||||
describe('create', () => {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { randomUUID } from 'crypto';
|
||||
import type { IEntity } from '@core/shared/domain';
|
||||
import { StepId } from '../value-objects/StepId';
|
||||
import { SessionState } from '../value-objects/SessionState';
|
||||
|
||||
import type { HostedSessionConfig } from '../types/HostedSessionConfig';
|
||||
import { AutomationDomainError } from '../errors/AutomationDomainError';
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ describe('PageStateValidator', () => {
|
||||
describe('validateState', () => {
|
||||
it('should return valid when all required selectors are present', () => {
|
||||
// Arrange
|
||||
const actualState = (selector: string) => {
|
||||
const actualState = (_selector: string) => {
|
||||
return ['#add-car-button', '#cars-list'].includes(selector);
|
||||
};
|
||||
|
||||
@@ -27,7 +27,7 @@ describe('PageStateValidator', () => {
|
||||
|
||||
it('should return invalid when required selectors are missing', () => {
|
||||
// Arrange
|
||||
const actualState = (selector: string) => {
|
||||
const actualState = (_selector: string) => {
|
||||
return selector === '#add-car-button'; // Only one of two selectors present
|
||||
};
|
||||
|
||||
@@ -48,7 +48,7 @@ describe('PageStateValidator', () => {
|
||||
|
||||
it('should return invalid when forbidden selectors are present', () => {
|
||||
// Arrange
|
||||
const actualState = (selector: string) => {
|
||||
const actualState = (_selector: string) => {
|
||||
return ['#add-car-button', '#set-track'].includes(selector);
|
||||
};
|
||||
|
||||
@@ -70,7 +70,7 @@ describe('PageStateValidator', () => {
|
||||
|
||||
it('should handle empty forbidden selectors array', () => {
|
||||
// Arrange
|
||||
const actualState = (selector: string) => {
|
||||
const actualState = (_selector: string) => {
|
||||
return selector === '#add-car-button';
|
||||
};
|
||||
|
||||
@@ -89,7 +89,7 @@ describe('PageStateValidator', () => {
|
||||
|
||||
it('should handle undefined forbidden selectors', () => {
|
||||
// Arrange
|
||||
const actualState = (selector: string) => {
|
||||
const actualState = (_selector: string) => {
|
||||
return selector === '#add-car-button';
|
||||
};
|
||||
|
||||
@@ -108,7 +108,7 @@ describe('PageStateValidator', () => {
|
||||
|
||||
it('should return error result when actualState function throws', () => {
|
||||
// Arrange
|
||||
const actualState = (selector: string) => {
|
||||
const actualState = (_selector: string) => {
|
||||
throw new Error('Selector evaluation failed');
|
||||
};
|
||||
|
||||
@@ -144,7 +144,7 @@ describe('PageStateValidator', () => {
|
||||
|
||||
it('should validate complex state with both required and forbidden selectors', () => {
|
||||
// Arrange - Simulate being on Cars page but Track page elements leaked through
|
||||
const actualState = (selector: string) => {
|
||||
const actualState = (_selector: string) => {
|
||||
const presentSelectors = ['#add-car-button', '#cars-list', '#set-track'];
|
||||
return presentSelectors.includes(selector);
|
||||
};
|
||||
|
||||
@@ -26,7 +26,7 @@ export interface PageStateValidationResult {
|
||||
}
|
||||
|
||||
export interface PageStateValidationInput {
|
||||
actualState: (selector: string) => boolean;
|
||||
actualState: (_selector: string) => boolean;
|
||||
validation: PageStateValidation;
|
||||
realMode?: boolean;
|
||||
}
|
||||
@@ -59,14 +59,14 @@ export class PageStateValidator
|
||||
* @returns Result with validation outcome
|
||||
*/
|
||||
validateState(
|
||||
actualState: (selector: string) => boolean,
|
||||
actualState: (_selector: string) => boolean,
|
||||
validation: PageStateValidation
|
||||
): Result<PageStateValidationResult, Error> {
|
||||
try {
|
||||
const { expectedStep, requiredSelectors, forbiddenSelectors = [] } = validation;
|
||||
|
||||
// Check required selectors are present
|
||||
const missingSelectors = requiredSelectors.filter(selector => !actualState(selector));
|
||||
const missingSelectors = requiredSelectors.filter(_selector => !actualState(_selector));
|
||||
|
||||
if (missingSelectors.length > 0) {
|
||||
const result: PageStateValidationResult = {
|
||||
@@ -79,7 +79,7 @@ export class PageStateValidator
|
||||
}
|
||||
|
||||
// Check forbidden selectors are absent
|
||||
const unexpectedSelectors = forbiddenSelectors.filter(selector => actualState(selector));
|
||||
const unexpectedSelectors = forbiddenSelectors.filter(_selector => actualState(_selector));
|
||||
|
||||
if (unexpectedSelectors.length > 0) {
|
||||
const result: PageStateValidationResult = {
|
||||
@@ -118,7 +118,7 @@ export class PageStateValidator
|
||||
* @returns Result with validation outcome
|
||||
*/
|
||||
validateStateEnhanced(
|
||||
actualState: (selector: string) => boolean,
|
||||
actualState: (_selector: string) => boolean,
|
||||
validation: PageStateValidation,
|
||||
realMode: boolean = false
|
||||
): Result<PageStateValidationResult, Error> {
|
||||
@@ -183,7 +183,7 @@ export class PageStateValidator
|
||||
}
|
||||
|
||||
// Check required selectors are present (with fallbacks for real mode)
|
||||
const missingSelectors = requiredSelectors.filter(selector => {
|
||||
const missingSelectors = requiredSelectors.filter(_selector => {
|
||||
if (realMode) {
|
||||
const relatedSelectors = selectorsToCheck.filter(s =>
|
||||
s.includes(expectedStep) ||
|
||||
@@ -212,7 +212,7 @@ export class PageStateValidator
|
||||
}
|
||||
|
||||
// Check forbidden selectors are absent
|
||||
const unexpectedSelectors = forbiddenSelectors.filter(selector => actualState(selector));
|
||||
const unexpectedSelectors = forbiddenSelectors.filter(_selector => actualState(_selector));
|
||||
|
||||
if (unexpectedSelectors.length > 0) {
|
||||
const result: PageStateValidationResult = {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { StepTransitionValidator } from '@core/automation/domain/services/StepTransitionValidator';
|
||||
import { StepId } from '@core/automation/domain/value-objects/StepId';
|
||||
import { SessionState } from '@core/automation/domain/value-objects/SessionState';
|
||||
|
||||
|
||||
describe('StepTransitionValidator Service', () => {
|
||||
describe('canTransition', () => {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { StepId } from '../value-objects/StepId';
|
||||
import { SessionState } from '../value-objects/SessionState';
|
||||
|
||||
import type { IDomainValidationService } from '@core/shared/domain';
|
||||
import { Result } from '../../../shared/result/Result';
|
||||
|
||||
@@ -96,7 +96,7 @@ export class StepTransitionValidator
|
||||
return { isValid: true };
|
||||
}
|
||||
|
||||
static shouldStopAtStep18(nextStep: StepId): boolean {
|
||||
static shouldStopAtStep18(_nextStep: StepId): boolean {
|
||||
return nextStep.isFinalStep();
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ describe('CheckoutConfirmation Value Object', () => {
|
||||
});
|
||||
|
||||
it('should throw error for invalid decision', () => {
|
||||
expect(() => CheckoutConfirmation.create('invalid' as any)).toThrow(
|
||||
expect(() => CheckoutConfirmation.create('invalid' as unknown)).toThrow(
|
||||
'Invalid checkout confirmation decision',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -24,7 +24,7 @@ export class CheckoutConfirmation {
|
||||
return CheckoutConfirmation.create('confirmed');
|
||||
}
|
||||
|
||||
static cancelled(_reason?: string): CheckoutConfirmation {
|
||||
static cancelled(__reason?: string): CheckoutConfirmation {
|
||||
return CheckoutConfirmation.create('cancelled');
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { CheckoutState, CheckoutStateEnum } from '@core/automation/domain/value-objects/CheckoutState';
|
||||
|
||||
|
||||
/**
|
||||
* CheckoutState Value Object - GREEN PHASE
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { SessionState } from '@core/automation/domain/value-objects/SessionState';
|
||||
|
||||
|
||||
describe('SessionState Value Object', () => {
|
||||
describe('create', () => {
|
||||
@@ -44,11 +44,11 @@ describe('SessionState Value Object', () => {
|
||||
});
|
||||
|
||||
it('should throw error for invalid state', () => {
|
||||
expect(() => SessionState.create('INVALID' as any)).toThrow('Invalid session state');
|
||||
expect(() => SessionState.create('INVALID' as unknown)).toThrow('Invalid session state');
|
||||
});
|
||||
|
||||
it('should throw error for empty string', () => {
|
||||
expect(() => SessionState.create('' as any)).toThrow('Invalid session state');
|
||||
expect(() => SessionState.create('' as unknown)).toThrow('Invalid session state');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
||||
import { loadAutomationConfig, getAutomationMode, AutomationMode } from '../../../core/automation/infrastructure/config/AutomationConfig';
|
||||
|
||||
|
||||
describe('AutomationConfig', () => {
|
||||
const originalEnv = process.env;
|
||||
@@ -17,7 +17,7 @@ describe('AutomationConfig', () => {
|
||||
describe('getAutomationMode', () => {
|
||||
describe('NODE_ENV-based mode detection', () => {
|
||||
it('should return production mode when NODE_ENV=production', () => {
|
||||
(process.env as any).NODE_ENV = 'production';
|
||||
(process.env as unknown).NODE_ENV = 'production';
|
||||
delete process.env.AUTOMATION_MODE;
|
||||
|
||||
const mode = getAutomationMode();
|
||||
@@ -26,7 +26,7 @@ describe('AutomationConfig', () => {
|
||||
});
|
||||
|
||||
it('should return test mode when NODE_ENV=test', () => {
|
||||
(process.env as any).NODE_ENV = 'test';
|
||||
(process.env as unknown).NODE_ENV = 'test';
|
||||
delete process.env.AUTOMATION_MODE;
|
||||
|
||||
const mode = getAutomationMode();
|
||||
@@ -35,7 +35,7 @@ describe('AutomationConfig', () => {
|
||||
});
|
||||
|
||||
it('should return test mode when NODE_ENV is not set', () => {
|
||||
delete (process.env as any).NODE_ENV;
|
||||
delete (process.env as unknown).NODE_ENV;
|
||||
delete process.env.AUTOMATION_MODE;
|
||||
|
||||
const mode = getAutomationMode();
|
||||
@@ -44,7 +44,7 @@ describe('AutomationConfig', () => {
|
||||
});
|
||||
|
||||
it('should return test mode for unknown NODE_ENV values', () => {
|
||||
(process.env as any).NODE_ENV = 'staging';
|
||||
(process.env as unknown).NODE_ENV = 'staging';
|
||||
delete process.env.AUTOMATION_MODE;
|
||||
|
||||
const mode = getAutomationMode();
|
||||
@@ -53,7 +53,7 @@ describe('AutomationConfig', () => {
|
||||
});
|
||||
|
||||
it('should return development mode when NODE_ENV=development', () => {
|
||||
(process.env as any).NODE_ENV = 'development';
|
||||
(process.env as unknown).NODE_ENV = 'development';
|
||||
delete process.env.AUTOMATION_MODE;
|
||||
|
||||
const mode = getAutomationMode();
|
||||
@@ -104,7 +104,7 @@ describe('AutomationConfig', () => {
|
||||
|
||||
it('should ignore invalid AUTOMATION_MODE and use NODE_ENV', () => {
|
||||
process.env.AUTOMATION_MODE = 'invalid-mode';
|
||||
(process.env as any).NODE_ENV = 'production';
|
||||
(process.env as unknown).NODE_ENV = 'production';
|
||||
|
||||
const mode = getAutomationMode();
|
||||
|
||||
@@ -116,7 +116,7 @@ describe('AutomationConfig', () => {
|
||||
describe('loadAutomationConfig', () => {
|
||||
describe('default configuration', () => {
|
||||
it('should return test mode when NODE_ENV is not set', () => {
|
||||
delete (process.env as any).NODE_ENV;
|
||||
delete (process.env as unknown).NODE_ENV;
|
||||
delete process.env.AUTOMATION_MODE;
|
||||
|
||||
const config = loadAutomationConfig();
|
||||
@@ -143,7 +143,7 @@ describe('AutomationConfig', () => {
|
||||
|
||||
describe('production mode configuration', () => {
|
||||
it('should return production mode when NODE_ENV=production', () => {
|
||||
(process.env as any).NODE_ENV = 'production';
|
||||
(process.env as unknown).NODE_ENV = 'production';
|
||||
delete process.env.AUTOMATION_MODE;
|
||||
|
||||
const config = loadAutomationConfig();
|
||||
@@ -228,7 +228,7 @@ describe('AutomationConfig', () => {
|
||||
});
|
||||
|
||||
it('should fallback to test mode for invalid NODE_ENV', () => {
|
||||
(process.env as any).NODE_ENV = 'invalid-env';
|
||||
(process.env as unknown).NODE_ENV = 'invalid-env';
|
||||
delete process.env.AUTOMATION_MODE;
|
||||
|
||||
const config = loadAutomationConfig();
|
||||
@@ -239,7 +239,7 @@ describe('AutomationConfig', () => {
|
||||
|
||||
describe('full configuration scenario', () => {
|
||||
it('should load complete test environment configuration', () => {
|
||||
(process.env as any).NODE_ENV = 'test';
|
||||
(process.env as unknown).NODE_ENV = 'test';
|
||||
delete process.env.AUTOMATION_MODE;
|
||||
|
||||
const config = loadAutomationConfig();
|
||||
@@ -249,7 +249,7 @@ describe('AutomationConfig', () => {
|
||||
});
|
||||
|
||||
it('should load complete production environment configuration', () => {
|
||||
(process.env as any).NODE_ENV = 'production';
|
||||
(process.env as unknown).NODE_ENV = 'production';
|
||||
delete process.env.AUTOMATION_MODE;
|
||||
|
||||
const config = loadAutomationConfig();
|
||||
|
||||
@@ -12,7 +12,7 @@ describe('BrowserModeConfig - GREEN Phase', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
process.env = { ...originalEnv };
|
||||
delete (process.env as any).NODE_ENV;
|
||||
delete (process.env as unknown).NODE_ENV;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@@ -21,7 +21,7 @@ describe('BrowserModeConfig - GREEN Phase', () => {
|
||||
|
||||
describe('Development Mode with Runtime Control', () => {
|
||||
it('should default to headless in development mode', () => {
|
||||
(process.env as any).NODE_ENV = 'development';
|
||||
(process.env as unknown).NODE_ENV = 'development';
|
||||
|
||||
const loader = new BrowserModeConfigLoader();
|
||||
const config = loader.load();
|
||||
@@ -31,7 +31,7 @@ describe('BrowserModeConfig - GREEN Phase', () => {
|
||||
});
|
||||
|
||||
it('should allow runtime switch to headless mode in development', () => {
|
||||
(process.env as any).NODE_ENV = 'development';
|
||||
(process.env as unknown).NODE_ENV = 'development';
|
||||
|
||||
const loader = new BrowserModeConfigLoader();
|
||||
loader.setDevelopmentMode('headless');
|
||||
@@ -42,7 +42,7 @@ describe('BrowserModeConfig - GREEN Phase', () => {
|
||||
});
|
||||
|
||||
it('should allow runtime switch to headed mode in development', () => {
|
||||
(process.env as any).NODE_ENV = 'development';
|
||||
(process.env as unknown).NODE_ENV = 'development';
|
||||
|
||||
const loader = new BrowserModeConfigLoader();
|
||||
loader.setDevelopmentMode('headed');
|
||||
@@ -53,7 +53,7 @@ describe('BrowserModeConfig - GREEN Phase', () => {
|
||||
});
|
||||
|
||||
it('should persist runtime setting across multiple load() calls', () => {
|
||||
(process.env as any).NODE_ENV = 'development';
|
||||
(process.env as unknown).NODE_ENV = 'development';
|
||||
|
||||
const loader = new BrowserModeConfigLoader();
|
||||
loader.setDevelopmentMode('headless');
|
||||
@@ -66,7 +66,7 @@ describe('BrowserModeConfig - GREEN Phase', () => {
|
||||
});
|
||||
|
||||
it('should return current development mode via getter', () => {
|
||||
(process.env as any).NODE_ENV = 'development';
|
||||
(process.env as unknown).NODE_ENV = 'development';
|
||||
|
||||
const loader = new BrowserModeConfigLoader();
|
||||
expect(loader.getDevelopmentMode()).toBe('headless');
|
||||
@@ -78,7 +78,7 @@ describe('BrowserModeConfig - GREEN Phase', () => {
|
||||
|
||||
describe('Production Mode', () => {
|
||||
it('should use headless mode when NODE_ENV=production', () => {
|
||||
(process.env as any).NODE_ENV = 'production';
|
||||
(process.env as unknown).NODE_ENV = 'production';
|
||||
|
||||
const loader = new BrowserModeConfigLoader();
|
||||
const config = loader.load();
|
||||
@@ -88,7 +88,7 @@ describe('BrowserModeConfig - GREEN Phase', () => {
|
||||
});
|
||||
|
||||
it('should ignore setDevelopmentMode in production', () => {
|
||||
(process.env as any).NODE_ENV = 'production';
|
||||
(process.env as unknown).NODE_ENV = 'production';
|
||||
|
||||
const loader = new BrowserModeConfigLoader();
|
||||
loader.setDevelopmentMode('headed');
|
||||
@@ -101,7 +101,7 @@ describe('BrowserModeConfig - GREEN Phase', () => {
|
||||
|
||||
describe('Test Mode', () => {
|
||||
it('should use headless mode when NODE_ENV=test', () => {
|
||||
(process.env as any).NODE_ENV = 'test';
|
||||
(process.env as unknown).NODE_ENV = 'test';
|
||||
|
||||
const loader = new BrowserModeConfigLoader();
|
||||
const config = loader.load();
|
||||
@@ -111,7 +111,7 @@ describe('BrowserModeConfig - GREEN Phase', () => {
|
||||
});
|
||||
|
||||
it('should ignore setDevelopmentMode in test mode', () => {
|
||||
(process.env as any).NODE_ENV = 'test';
|
||||
(process.env as unknown).NODE_ENV = 'test';
|
||||
|
||||
const loader = new BrowserModeConfigLoader();
|
||||
loader.setDevelopmentMode('headed');
|
||||
@@ -124,7 +124,7 @@ describe('BrowserModeConfig - GREEN Phase', () => {
|
||||
|
||||
describe('Default Mode', () => {
|
||||
it('should default to headless mode when NODE_ENV is not set', () => {
|
||||
delete (process.env as any).NODE_ENV;
|
||||
delete (process.env as unknown).NODE_ENV;
|
||||
|
||||
const loader = new BrowserModeConfigLoader();
|
||||
const config = loader.load();
|
||||
@@ -134,7 +134,7 @@ describe('BrowserModeConfig - GREEN Phase', () => {
|
||||
});
|
||||
|
||||
it('should use headless mode for any non-development NODE_ENV value', () => {
|
||||
(process.env as any).NODE_ENV = 'staging';
|
||||
(process.env as unknown).NODE_ENV = 'staging';
|
||||
|
||||
const loader = new BrowserModeConfigLoader();
|
||||
const config = loader.load();
|
||||
@@ -146,7 +146,7 @@ describe('BrowserModeConfig - GREEN Phase', () => {
|
||||
|
||||
describe('Source Tracking', () => {
|
||||
it('should report GUI as source in development mode', () => {
|
||||
(process.env as any).NODE_ENV = 'development';
|
||||
(process.env as unknown).NODE_ENV = 'development';
|
||||
|
||||
const loader = new BrowserModeConfigLoader();
|
||||
const config = loader.load();
|
||||
@@ -155,7 +155,7 @@ describe('BrowserModeConfig - GREEN Phase', () => {
|
||||
});
|
||||
|
||||
it('should report NODE_ENV as source in production mode', () => {
|
||||
(process.env as any).NODE_ENV = 'production';
|
||||
(process.env as unknown).NODE_ENV = 'production';
|
||||
|
||||
const loader = new BrowserModeConfigLoader();
|
||||
const config = loader.load();
|
||||
@@ -164,7 +164,7 @@ describe('BrowserModeConfig - GREEN Phase', () => {
|
||||
});
|
||||
|
||||
it('should report NODE_ENV as source in test mode', () => {
|
||||
(process.env as any).NODE_ENV = 'test';
|
||||
(process.env as unknown).NODE_ENV = 'test';
|
||||
|
||||
const loader = new BrowserModeConfigLoader();
|
||||
const config = loader.load();
|
||||
@@ -173,7 +173,7 @@ describe('BrowserModeConfig - GREEN Phase', () => {
|
||||
});
|
||||
|
||||
it('should report NODE_ENV as source when NODE_ENV is not set', () => {
|
||||
delete (process.env as any).NODE_ENV;
|
||||
delete (process.env as unknown).NODE_ENV;
|
||||
|
||||
const loader = new BrowserModeConfigLoader();
|
||||
const config = loader.load();
|
||||
|
||||
@@ -5,12 +5,12 @@ import type { CheckoutInfoDTO } from '../../../application/dto/CheckoutInfoDTO';
|
||||
import { IRACING_SELECTORS } from './dom/IRacingSelectors';
|
||||
|
||||
interface Page {
|
||||
locator(selector: string): Locator;
|
||||
locator(_selector: string): Locator;
|
||||
}
|
||||
|
||||
interface Locator {
|
||||
first(): Locator;
|
||||
locator(selector: string): Locator;
|
||||
locator(_selector: string): Locator;
|
||||
getAttribute(name: string): Promise<string | null>;
|
||||
innerHTML(): Promise<string>;
|
||||
textContent(): Promise<string | null>;
|
||||
|
||||
@@ -190,7 +190,7 @@ describe('AuthenticationGuard', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Login button selector specificity', () => {
|
||||
describe('Login button _selector specificity', () => {
|
||||
test('should detect login button on actual login pages', async () => {
|
||||
// Simulate a real login page with a login form
|
||||
const mockLocator = {
|
||||
|
||||
@@ -2,7 +2,7 @@ import { describe, test, expect, beforeEach } from 'vitest';
|
||||
import { SessionCookieStore } from '@core/automation/infrastructure//automation/auth/SessionCookieStore';
|
||||
import type { Cookie } from 'playwright';
|
||||
|
||||
const logger = console as any;
|
||||
const logger = console as unknown;
|
||||
|
||||
describe('SessionCookieStore - Cookie Validation', () => {
|
||||
let cookieStore: SessionCookieStore;
|
||||
|
||||
@@ -20,9 +20,9 @@ import { Result } from '../../../../../shared/result/Result';
|
||||
import { IRACING_SELECTORS, IRACING_URLS, IRACING_TIMEOUTS, ALL_BLOCKED_SELECTORS, BLOCKED_KEYWORDS } from '../dom/IRacingSelectors';
|
||||
import { SessionCookieStore } from '../auth/SessionCookieStore';
|
||||
import { PlaywrightBrowserSession } from './PlaywrightBrowserSession';
|
||||
import { getFixtureForStep } from '../engine/FixtureServer';
|
||||
|
||||
import { BrowserModeConfigLoader, BrowserMode } from '../../../config/BrowserModeConfig';
|
||||
import { getAutomationMode } from '../../../config/AutomationConfig';
|
||||
|
||||
import { PageStateValidator, PageStateValidation, PageStateValidationResult } from '@core/automation/domain/services/PageStateValidator';
|
||||
import { IRacingDomNavigator } from '../dom/IRacingDomNavigator';
|
||||
import { SafeClickService } from '../dom/SafeClickService';
|
||||
@@ -543,7 +543,7 @@ export class PlaywrightAutomationAdapter implements IBrowserAutomation, Authenti
|
||||
*/
|
||||
async attachPanel(page?: Page, actionId?: string): Promise<void> {
|
||||
const selector = '#gridpilot-overlay'
|
||||
await this.emitLifecycle({ type: 'panel-attached', actionId, timestamp: Date.now(), payload: { selector } })
|
||||
await this.emitLifecycle({ type: 'panel-attached', actionId, timestamp: Date.now(), payload: { _selector } })
|
||||
await this.emitLifecycle({ type: 'action-started', actionId, timestamp: Date.now() })
|
||||
}
|
||||
private isRealMode(): boolean {
|
||||
@@ -583,7 +583,7 @@ export class PlaywrightAutomationAdapter implements IBrowserAutomation, Authenti
|
||||
}
|
||||
}
|
||||
|
||||
const actualState = (selector: string): boolean => {
|
||||
const actualState = (_selector: string): boolean => {
|
||||
return selectorChecks[selector] === true;
|
||||
};
|
||||
|
||||
@@ -1247,7 +1247,7 @@ export class PlaywrightAutomationAdapter implements IBrowserAutomation, Authenti
|
||||
* @param elementText Optional text content of the element (should be direct text only)
|
||||
* @returns true if the selector/text matches a blocked pattern
|
||||
*/
|
||||
private isBlockedSelector(selector: string, elementText?: string): boolean {
|
||||
private isBlockedSelector(_selector: string, elementText?: string): boolean {
|
||||
const selectorLower = selector.toLowerCase();
|
||||
const textLower = elementText?.toLowerCase().trim() ?? '';
|
||||
|
||||
@@ -1293,7 +1293,7 @@ export class PlaywrightAutomationAdapter implements IBrowserAutomation, Authenti
|
||||
* @param selector The CSS selector of the element to verify
|
||||
* @throws Error if element is a blocked checkout/payment button
|
||||
*/
|
||||
private async verifyNotBlockedElement(selector: string): Promise<void> {
|
||||
private async verifyNotBlockedElement(_selector: string): Promise<void> {
|
||||
if (!this.page) return;
|
||||
|
||||
// In mock mode we bypass safety blocking to allow tests to exercise checkout flows
|
||||
@@ -1394,7 +1394,7 @@ export class PlaywrightAutomationAdapter implements IBrowserAutomation, Authenti
|
||||
throw error;
|
||||
}
|
||||
// Otherwise ignore - element might not exist yet, safeClick will handle that
|
||||
this.log('debug', 'Could not verify element (may not exist yet)', { selector, error: String(error) });
|
||||
this.log('debug', 'Could not verify element (may not exist yet)', { _selector, error: String(error) });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1409,7 +1409,7 @@ export class PlaywrightAutomationAdapter implements IBrowserAutomation, Authenti
|
||||
* @param options Click options including timeout and force
|
||||
* @returns Promise that resolves when click succeeds or throws after max retries
|
||||
*/
|
||||
private async safeClick(selector: string, options?: { timeout?: number; force?: boolean }): Promise<void> {
|
||||
private async safeClick(_selector: string, options?: { timeout?: number; force?: boolean }): Promise<void> {
|
||||
if (!this.page) {
|
||||
throw new Error('Browser not connected');
|
||||
}
|
||||
@@ -1438,7 +1438,7 @@ export class PlaywrightAutomationAdapter implements IBrowserAutomation, Authenti
|
||||
try {
|
||||
// On final attempt, use force: true if datetime picker issues detected
|
||||
const useForce = options?.force || attempt === maxRetries;
|
||||
await this.page.click(selector, { timeout, force: useForce });
|
||||
await this.page.click(_selector, { timeout, force: useForce });
|
||||
return; // Success
|
||||
} catch (error) {
|
||||
// Re-throw blocked errors immediately
|
||||
@@ -1496,7 +1496,7 @@ export class PlaywrightAutomationAdapter implements IBrowserAutomation, Authenti
|
||||
this.log('debug', 'JS fallback click did not find element or failed', { selector });
|
||||
}
|
||||
} catch (e) {
|
||||
this.log('debug', 'JS fallback click error', { selector, error: String(e) });
|
||||
this.log('debug', 'JS fallback click error', { _selector, error: String(e) });
|
||||
}
|
||||
|
||||
this.log('error', 'Max retries reached, click still blocked', { selector });
|
||||
@@ -1559,7 +1559,7 @@ export class PlaywrightAutomationAdapter implements IBrowserAutomation, Authenti
|
||||
|
||||
if (isVisible) {
|
||||
await radioLabel.click({ timeout: IRACING_TIMEOUTS.elementWait });
|
||||
this.log('info', 'Selected weather type', { weatherType, selector: labelSelector });
|
||||
this.log('info', 'Selected weather type', { weatherType, _selector: labelSelector });
|
||||
} else {
|
||||
this.log('debug', 'Weather type radio not visible, may already be selected or step is different');
|
||||
}
|
||||
@@ -1674,10 +1674,10 @@ export class PlaywrightAutomationAdapter implements IBrowserAutomation, Authenti
|
||||
});
|
||||
// Brief pause for modal animation (reduced from 300ms)
|
||||
await this.page.waitForTimeout(150);
|
||||
this.log('info', 'Add Car modal is visible', { selector: modalSelector });
|
||||
this.log('info', 'Add Car modal is visible', { _selector: modalSelector });
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : String(error);
|
||||
this.log('warn', 'Add Car modal not found with primary selector, dumping #create-race-wizard innerHTML and retrying', { error: message });
|
||||
this.log('warn', 'Add Car modal not found with primary _selector, dumping #create-race-wizard innerHTML and retrying', { error: message });
|
||||
const html = await this.page!.innerHTML('#create-race-wizard').catch(() => '');
|
||||
this.log('debug', 'create-race-wizard innerHTML (truncated)', { html: html ? html.slice(0, 2000) : '' });
|
||||
this.log('info', 'Retrying wait for Add Car modal with extended timeout');
|
||||
@@ -1688,7 +1688,7 @@ export class PlaywrightAutomationAdapter implements IBrowserAutomation, Authenti
|
||||
timeout: 10000,
|
||||
});
|
||||
await this.page.waitForTimeout(150);
|
||||
this.log('info', 'Add Car modal found after retry', { selector: modalSelectorRetry });
|
||||
this.log('info', 'Add Car modal found after retry', { _selector: modalSelectorRetry });
|
||||
} catch {
|
||||
this.log('warn', 'Add Car modal still not found after retry');
|
||||
}
|
||||
@@ -1775,7 +1775,7 @@ export class PlaywrightAutomationAdapter implements IBrowserAutomation, Authenti
|
||||
for (const selector of directSelectors) {
|
||||
const button = this.page.locator(selector).first();
|
||||
if (await button.count() > 0 && await button.isVisible()) {
|
||||
await this.safeClick(selector, { timeout: IRACING_TIMEOUTS.elementWait });
|
||||
await this.safeClick(_selector, { timeout: IRACING_TIMEOUTS.elementWait });
|
||||
this.log('info', 'Clicked direct Select button for first search result', { selector });
|
||||
return;
|
||||
}
|
||||
@@ -1788,7 +1788,7 @@ export class PlaywrightAutomationAdapter implements IBrowserAutomation, Authenti
|
||||
if (await dropdownButton.count() > 0 && await dropdownButton.isVisible()) {
|
||||
// Click dropdown to open menu
|
||||
await this.safeClick(dropdownSelector, { timeout: IRACING_TIMEOUTS.elementWait });
|
||||
this.log('debug', 'Clicked dropdown toggle, waiting for menu', { selector: dropdownSelector });
|
||||
this.log('debug', 'Clicked dropdown toggle, waiting for menu', { _selector: dropdownSelector });
|
||||
|
||||
// Wait for dropdown menu to appear
|
||||
await this.page.waitForSelector('.dropdown-menu.show', { timeout: 3000 }).catch(() => { });
|
||||
@@ -1797,7 +1797,7 @@ export class PlaywrightAutomationAdapter implements IBrowserAutomation, Authenti
|
||||
const itemSelector = IRACING_SELECTORS.steps.trackSelectDropdownItem;
|
||||
await this.page.waitForTimeout(200);
|
||||
await this.safeClick(itemSelector, { timeout: IRACING_TIMEOUTS.elementWait });
|
||||
this.log('info', 'Clicked first dropdown item to select track config', { selector: itemSelector });
|
||||
this.log('info', 'Clicked first dropdown item to select track config', { _selector: itemSelector });
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1805,7 +1805,7 @@ export class PlaywrightAutomationAdapter implements IBrowserAutomation, Authenti
|
||||
const carRowSelector = '.car-row, .car-item, [data-testid*="car"], [id*="favorite_cars"], [id*="select-car"]';
|
||||
const carRow = this.page.locator(carRowSelector).first();
|
||||
if (await carRow.count() > 0) {
|
||||
this.log('info', 'Fallback: clicking car row/item to select', { selector: carRowSelector });
|
||||
this.log('info', 'Fallback: clicking car row/item to select', { _selector: carRowSelector });
|
||||
// Click the row itself (or its first clickable descendant)
|
||||
try {
|
||||
await this.safeClick(carRowSelector, { timeout: IRACING_TIMEOUTS.elementWait });
|
||||
@@ -1888,7 +1888,7 @@ export class PlaywrightAutomationAdapter implements IBrowserAutomation, Authenti
|
||||
(await direct.isVisible().catch(() => false));
|
||||
|
||||
if (hasDirect) {
|
||||
this.log('info', 'Clicking direct New Race button', { selector: directSelector });
|
||||
this.log('info', 'Clicking direct New Race button', { _selector: directSelector });
|
||||
await this.safeClick(directSelector, { timeout: IRACING_TIMEOUTS.elementWait });
|
||||
} else {
|
||||
const dropdownToggleSelector =
|
||||
@@ -2100,7 +2100,7 @@ export class PlaywrightAutomationAdapter implements IBrowserAutomation, Authenti
|
||||
}
|
||||
|
||||
try {
|
||||
this.log('debug', `Waiting for wizard step: ${stepName}`, { selector: containerSelector });
|
||||
this.log('debug', `Waiting for wizard step: ${stepName}`, { _selector: containerSelector });
|
||||
// Use 'attached' instead of 'visible' because iRacing wizard steps are marked as
|
||||
// 'active hidden' in the DOM - they exist but are hidden via CSS class
|
||||
await this.page.waitForSelector(containerSelector, {
|
||||
@@ -2129,11 +2129,11 @@ export class PlaywrightAutomationAdapter implements IBrowserAutomation, Authenti
|
||||
const timeout = this.isRealMode() ? IRACING_TIMEOUTS.elementWait : this.config.timeout;
|
||||
|
||||
// Split combined selectors and try each one
|
||||
const selectors = selector.split(', ').map(s => s.trim());
|
||||
const selectors = _selector.split(', ').map(s => s.trim());
|
||||
|
||||
for (const sel of selectors) {
|
||||
try {
|
||||
this.log('debug', `Trying selector for ${fieldName}`, { selector: sel });
|
||||
this.log('debug', `Trying _selector for ${fieldName}`, { _selector: sel });
|
||||
|
||||
// Check if element exists and is visible
|
||||
const element = this.page.locator(sel).first();
|
||||
@@ -2143,11 +2143,11 @@ export class PlaywrightAutomationAdapter implements IBrowserAutomation, Authenti
|
||||
// Use 'attached' instead of 'visible' because iRacing wizard steps have class="hidden"
|
||||
await element.waitFor({ state: 'attached', timeout });
|
||||
await element.fill(value);
|
||||
this.log('info', `Successfully filled ${fieldName}`, { selector: sel, value });
|
||||
this.log('info', `Successfully filled ${fieldName}`, { _selector: sel, value });
|
||||
return { success: true, fieldName, valueSet: value };
|
||||
}
|
||||
} catch (error) {
|
||||
this.log('debug', `Selector failed for ${fieldName}`, { selector: sel, error: String(error) });
|
||||
this.log('debug', `Selector failed for ${fieldName}`, { _selector: sel, error: String(error) });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2155,12 +2155,12 @@ export class PlaywrightAutomationAdapter implements IBrowserAutomation, Authenti
|
||||
try {
|
||||
this.log('debug', `Trying combined selector for ${fieldName}`, { selector });
|
||||
// Use 'attached' instead of 'visible' because iRacing wizard steps have class="hidden"
|
||||
await this.page.waitForSelector(selector, { state: 'attached', timeout });
|
||||
await this.page.waitForSelector(_selector, { state: 'attached', timeout });
|
||||
await this.page.fill(selector, value);
|
||||
return { success: true, fieldName, valueSet: value };
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : String(error);
|
||||
this.log('error', `Failed to fill ${fieldName}`, { selector, error: message });
|
||||
this.log('error', `Failed to fill ${fieldName}`, { _selector, error: message });
|
||||
return { success: false, fieldName, valueSet: value, error: message };
|
||||
}
|
||||
}
|
||||
@@ -2194,7 +2194,7 @@ export class PlaywrightAutomationAdapter implements IBrowserAutomation, Authenti
|
||||
// Some wizard footer buttons are present/attached but not considered "visible" by Playwright
|
||||
// (offscreen, overlapped by overlays, or transitional). Use a forced safe click first,
|
||||
// then fall back to name-based or last-resort selectors if that fails.
|
||||
this.log('debug', 'Attempting next button (primary) with forced click', { selector: nextButtonSelector });
|
||||
this.log('debug', 'Attempting next button (primary) with forced click', { _selector: nextButtonSelector });
|
||||
try {
|
||||
await this.safeClick(nextButtonSelector, { timeout, force: true });
|
||||
this.log('info', `Clicked next button to ${nextStepName} (primary forced)`);
|
||||
@@ -2204,7 +2204,7 @@ export class PlaywrightAutomationAdapter implements IBrowserAutomation, Authenti
|
||||
}
|
||||
|
||||
// Try fallback with step name (also attempt forced click)
|
||||
this.log('debug', 'Trying fallback next button (forced)', { selector: fallbackSelector });
|
||||
this.log('debug', 'Trying fallback next button (forced)', { _selector: fallbackSelector });
|
||||
try {
|
||||
await this.safeClick(fallbackSelector, { timeout, force: true });
|
||||
this.log('info', `Clicked next button (fallback) to ${nextStepName}`);
|
||||
@@ -2248,7 +2248,7 @@ export class PlaywrightAutomationAdapter implements IBrowserAutomation, Authenti
|
||||
}
|
||||
|
||||
// Use 'attached' instead of 'visible' because mock fixtures/wizard steps may be present but hidden
|
||||
await this.page.waitForSelector(selector, { state: 'attached', timeout });
|
||||
await this.page.waitForSelector(_selector, { state: 'attached', timeout });
|
||||
await this.safeClick(selector, { timeout });
|
||||
return { success: true, target: selector };
|
||||
}
|
||||
@@ -2260,7 +2260,7 @@ export class PlaywrightAutomationAdapter implements IBrowserAutomation, Authenti
|
||||
const selector = this.getFieldSelector(fieldName);
|
||||
const timeout = this.isRealMode() ? IRACING_TIMEOUTS.elementWait : this.config.timeout;
|
||||
|
||||
this.log('debug', 'fillField', { fieldName, selector, mode: this.config.mode });
|
||||
this.log('debug', 'fillField', { fieldName, _selector, mode: this.config.mode });
|
||||
|
||||
// In mock mode, reveal typical fixture-hidden containers to allow Playwright to interact.
|
||||
if (!this.isRealMode()) {
|
||||
@@ -2277,7 +2277,7 @@ export class PlaywrightAutomationAdapter implements IBrowserAutomation, Authenti
|
||||
}
|
||||
|
||||
// Wait for the element to be attached to the DOM
|
||||
await this.page.waitForSelector(selector, { state: 'attached', timeout });
|
||||
await this.page.waitForSelector(_selector, { state: 'attached', timeout });
|
||||
|
||||
// Try normal Playwright fill first; fall back to JS injection in mock mode if Playwright refuses due to visibility.
|
||||
try {
|
||||
@@ -2315,7 +2315,7 @@ export class PlaywrightAutomationAdapter implements IBrowserAutomation, Authenti
|
||||
|
||||
// Try to wait for the canonical selector first
|
||||
try {
|
||||
await this.page.waitForSelector(selector, { state: 'attached', timeout });
|
||||
await this.page.waitForSelector(_selector, { state: 'attached', timeout });
|
||||
await this.page.selectOption(selector, value);
|
||||
return;
|
||||
} catch {
|
||||
@@ -2774,7 +2774,7 @@ export class PlaywrightAutomationAdapter implements IBrowserAutomation, Authenti
|
||||
// ignore evaluation errors during tests
|
||||
}
|
||||
}
|
||||
await this.page.waitForSelector(selector, { state: 'attached', timeout });
|
||||
await this.page.waitForSelector(_selector, { state: 'attached', timeout });
|
||||
await this.safeClick(selector, { timeout });
|
||||
}
|
||||
|
||||
@@ -2784,7 +2784,7 @@ export class PlaywrightAutomationAdapter implements IBrowserAutomation, Authenti
|
||||
}
|
||||
// Broaden trigger selector to match multiple fixture variants (buttons, anchors, data-action)
|
||||
const escaped = type.replace(/"/g, '\\"');
|
||||
const selector = `button:has-text("${escaped}"), a:has-text("${escaped}"), [aria-label*="${escaped}" i], [data-action="${escaped}"], [data-modal-trigger="${escaped}"]`;
|
||||
const _selector = `button:has-text("${escaped}"), a:has-text("${escaped}"), [aria-label*="${escaped}" i], [data-action="${escaped}"], [data-modal-trigger="${escaped}"]`;
|
||||
const timeout = this.isRealMode() ? IRACING_TIMEOUTS.elementWait : this.config.timeout;
|
||||
|
||||
// In mock mode, reveal typical hidden fixture containers so trigger buttons are discoverable.
|
||||
@@ -2802,7 +2802,7 @@ export class PlaywrightAutomationAdapter implements IBrowserAutomation, Authenti
|
||||
}
|
||||
|
||||
// Use 'attached' instead of 'visible' because iRacing wizard steps have class="hidden"
|
||||
await this.page.waitForSelector(selector, { state: 'attached', timeout });
|
||||
await this.page.waitForSelector(_selector, { state: 'attached', timeout });
|
||||
await this.safeClick(selector, { timeout });
|
||||
}
|
||||
|
||||
@@ -3355,7 +3355,7 @@ export class PlaywrightAutomationAdapter implements IBrowserAutomation, Authenti
|
||||
* @param currentStep Current step number to determine if modal should be visible
|
||||
* @throws Error with 'WIZARD_DISMISSED' message if modal was closed by user
|
||||
*/
|
||||
async checkWizardDismissed(currentStep: number): Promise<void> {
|
||||
async checkWizardDismissed(_currentStep: number): Promise<void> {
|
||||
if (!this.page || !this.isRealMode() || currentStep < 3) {
|
||||
// Don't check before step 3 (modal opens at step 2)
|
||||
return;
|
||||
@@ -3503,7 +3503,7 @@ export class PlaywrightAutomationAdapter implements IBrowserAutomation, Authenti
|
||||
const locator = this.page.locator(sel).first();
|
||||
const count = await locator.count().catch(() => 0);
|
||||
if (count > 0) {
|
||||
this.log('debug', 'Found checkout candidate button selector', { selector: sel });
|
||||
this.log('debug', 'Found checkout candidate button _selector', { _selector: sel });
|
||||
|
||||
// safeClick will no-op in mock mode if element is hidden and will enforce
|
||||
// verifyNotBlockedElement() in real mode to avoid dangerous clicks.
|
||||
|
||||
@@ -6,7 +6,7 @@ import * as path from 'path';
|
||||
|
||||
import type { LoggerPort } from '@core/automation/application/ports/LoggerPort';
|
||||
import { BrowserModeConfigLoader, BrowserMode } from '../../../config/BrowserModeConfig';
|
||||
import { getAutomationMode } from '../../../config/AutomationConfig';
|
||||
|
||||
import type { PlaywrightConfig } from './PlaywrightAutomationAdapter';
|
||||
import { PlaywrightAutomationAdapter } from './PlaywrightAutomationAdapter';
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ import { PlaywrightBrowserSession } from './PlaywrightBrowserSession';
|
||||
import { IRacingDomNavigator } from '../dom/IRacingDomNavigator';
|
||||
import { IRacingDomInteractor } from '../dom/IRacingDomInteractor';
|
||||
import { IRACING_SELECTORS } from '../dom/IRacingSelectors';
|
||||
import { getFixtureForStep } from '../engine/FixtureServer';
|
||||
|
||||
import type {
|
||||
PageStateValidation,
|
||||
PageStateValidationResult,
|
||||
@@ -167,7 +167,7 @@ export class WizardStepOrchestrator {
|
||||
await this.navigator.waitForWizardStep(stepName);
|
||||
}
|
||||
|
||||
private async checkWizardDismissed(currentStep: number): Promise<void> {
|
||||
private async checkWizardDismissed(_currentStep: number): Promise<void> {
|
||||
await this.navigator.checkWizardDismissed(currentStep);
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,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(
|
||||
@@ -66,10 +66,10 @@ export class IRacingDomInteractor {
|
||||
const selector = fieldMap[fieldName as keyof typeof fieldMap] ?? IRACING_SELECTORS.fields.textInput;
|
||||
const timeout = this.isRealMode() ? IRACING_TIMEOUTS.elementWait : this.config.timeout;
|
||||
|
||||
this.log('debug', 'Filling form field', { fieldName, selector, mode: this.config.mode });
|
||||
this.log('debug', 'Filling form field', { fieldName, _selector, mode: this.config.mode });
|
||||
|
||||
try {
|
||||
await page.waitForSelector(selector, { state: 'attached', timeout });
|
||||
await page.waitForSelector(_selector, { state: 'attached', timeout });
|
||||
|
||||
try {
|
||||
await page.fill(selector, value);
|
||||
@@ -115,8 +115,8 @@ export class IRacingDomInteractor {
|
||||
const selector = this.getActionSelector(target);
|
||||
const timeout = this.isRealMode() ? IRACING_TIMEOUTS.elementWait : this.config.timeout;
|
||||
|
||||
this.log('debug', 'Clicking element', { target, selector, mode: this.config.mode });
|
||||
await page.waitForSelector(selector, { state: 'attached', timeout });
|
||||
this.log('debug', 'Clicking element', { target, _selector, mode: this.config.mode });
|
||||
await page.waitForSelector(_selector, { state: 'attached', timeout });
|
||||
await page.click(selector);
|
||||
return { success: true, target };
|
||||
} catch (error) {
|
||||
@@ -165,7 +165,7 @@ export class IRacingDomInteractor {
|
||||
const selector = this.getFieldSelector(fieldName);
|
||||
const timeout = this.isRealMode() ? IRACING_TIMEOUTS.elementWait : this.config.timeout;
|
||||
|
||||
this.log('debug', 'fillField', { fieldName, selector, mode: this.config.mode });
|
||||
this.log('debug', 'fillField', { fieldName, _selector, mode: this.config.mode });
|
||||
|
||||
if (!this.isRealMode()) {
|
||||
try {
|
||||
@@ -182,7 +182,7 @@ export class IRacingDomInteractor {
|
||||
}
|
||||
}
|
||||
|
||||
await page.waitForSelector(selector, { state: 'attached', timeout });
|
||||
await page.waitForSelector(_selector, { state: 'attached', timeout });
|
||||
|
||||
try {
|
||||
await page.fill(selector, value);
|
||||
@@ -218,11 +218,11 @@ export class IRacingDomInteractor {
|
||||
const selector = this.getFieldSelector(fieldName);
|
||||
const timeout = this.isRealMode() ? IRACING_TIMEOUTS.elementWait : this.config.timeout;
|
||||
|
||||
const selectors = selector.split(', ').map((s) => s.trim());
|
||||
const selectors = _selector.split(', ').map((s) => s.trim());
|
||||
|
||||
for (const sel of selectors) {
|
||||
try {
|
||||
this.log('debug', `Trying selector for ${fieldName}`, { selector: sel });
|
||||
this.log('debug', `Trying _selector for ${fieldName}`, { _selector: sel });
|
||||
|
||||
const element = page.locator(sel).first();
|
||||
const isVisible = await element.isVisible().catch(() => false);
|
||||
@@ -230,22 +230,22 @@ export class IRacingDomInteractor {
|
||||
if (isVisible) {
|
||||
await element.waitFor({ state: 'attached', timeout });
|
||||
await element.fill(value);
|
||||
this.log('info', `Successfully filled ${fieldName}`, { selector: sel, value });
|
||||
this.log('info', `Successfully filled ${fieldName}`, { _selector: sel, value });
|
||||
return { success: true, fieldName, valueSet: value };
|
||||
}
|
||||
} catch (error) {
|
||||
this.log('debug', `Selector failed for ${fieldName}`, { selector: sel, error: String(error) });
|
||||
this.log('debug', `Selector failed for ${fieldName}`, { _selector: sel, error: String(error) });
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
this.log('debug', `Trying combined selector for ${fieldName}`, { selector });
|
||||
await page.waitForSelector(selector, { state: 'attached', timeout });
|
||||
await page.waitForSelector(_selector, { state: 'attached', timeout });
|
||||
await page.fill(selector, value);
|
||||
return { success: true, fieldName, valueSet: value };
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : String(error);
|
||||
this.log('error', `Failed to fill ${fieldName}`, { selector, error: message });
|
||||
this.log('error', `Failed to fill ${fieldName}`, { _selector, error: message });
|
||||
return { success: false, fieldName, valueSet: value, error: message };
|
||||
}
|
||||
}
|
||||
@@ -273,7 +273,7 @@ export class IRacingDomInteractor {
|
||||
selector = this.getActionSelector(action);
|
||||
}
|
||||
|
||||
await page.waitForSelector(selector, { state: 'attached', timeout });
|
||||
await page.waitForSelector(_selector, { state: 'attached', timeout });
|
||||
await this.safeClickService.safeClick(selector, { timeout });
|
||||
return { success: true, target: selector };
|
||||
}
|
||||
@@ -316,7 +316,7 @@ export class IRacingDomInteractor {
|
||||
const fallbackSelector = `.wizard-footer a.btn:has-text("${nextStepName}")`;
|
||||
|
||||
try {
|
||||
this.log('debug', 'Attempting next button (primary) with forced click', { selector: nextButtonSelector });
|
||||
this.log('debug', 'Attempting next button (primary) with forced click', { _selector: nextButtonSelector });
|
||||
try {
|
||||
await this.safeClickService.safeClick(nextButtonSelector, { timeout, force: true });
|
||||
this.log('info', `Clicked next button to ${nextStepName} (primary forced)`);
|
||||
@@ -325,7 +325,7 @@ export class IRacingDomInteractor {
|
||||
this.log('debug', 'Primary forced click failed, falling back', { error: String(e) });
|
||||
}
|
||||
|
||||
this.log('debug', 'Trying fallback next button (forced)', { selector: fallbackSelector });
|
||||
this.log('debug', 'Trying fallback next button (forced)', { _selector: fallbackSelector });
|
||||
try {
|
||||
await this.safeClickService.safeClick(fallbackSelector, { timeout, force: true });
|
||||
this.log('info', `Clicked next button (fallback) to ${nextStepName}`);
|
||||
@@ -350,7 +350,7 @@ export class IRacingDomInteractor {
|
||||
const timeout = this.isRealMode() ? IRACING_TIMEOUTS.elementWait : this.config.timeout;
|
||||
|
||||
try {
|
||||
await page.waitForSelector(selector, { state: 'attached', timeout });
|
||||
await page.waitForSelector(_selector, { state: 'attached', timeout });
|
||||
await page.selectOption(selector, value);
|
||||
return;
|
||||
} catch {
|
||||
@@ -754,14 +754,14 @@ export class IRacingDomInteractor {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
await page.waitForSelector(selector, { state: 'attached', timeout });
|
||||
await page.waitForSelector(_selector, { state: 'attached', timeout });
|
||||
await this.safeClickService.safeClick(selector, { timeout });
|
||||
}
|
||||
|
||||
async openModalTrigger(type: string): Promise<void> {
|
||||
const page = this.getPage();
|
||||
const escaped = type.replace(/"/g, '\\"');
|
||||
const selector = `button:has-text("${escaped}"), a:has-text("${escaped}"), [aria-label*="${escaped}" i], [data-action="${escaped}"], [data-modal-trigger="${escaped}"]`;
|
||||
const _selector = `button:has-text("${escaped}"), a:has-text("${escaped}"), [aria-label*="${escaped}" i], [data-action="${escaped}"], [data-modal-trigger="${escaped}"]`;
|
||||
const timeout = this.isRealMode() ? IRACING_TIMEOUTS.elementWait : this.config.timeout;
|
||||
|
||||
if (!this.isRealMode()) {
|
||||
@@ -779,7 +779,7 @@ export class IRacingDomInteractor {
|
||||
}
|
||||
}
|
||||
|
||||
await page.waitForSelector(selector, { state: 'attached', timeout });
|
||||
await page.waitForSelector(_selector, { state: 'attached', timeout });
|
||||
await this.safeClickService.safeClick(selector, { timeout });
|
||||
}
|
||||
|
||||
@@ -816,7 +816,7 @@ export class IRacingDomInteractor {
|
||||
timeout: this.isRealMode() ? IRACING_TIMEOUTS.elementWait : this.config.timeout,
|
||||
});
|
||||
await page.waitForTimeout(150);
|
||||
this.log('info', 'Add Car modal is visible', { selector: modalSelector });
|
||||
this.log('info', 'Add Car modal is visible', { _selector: modalSelector });
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : String(error);
|
||||
this.log('warn', 'Add Car modal not found with primary selector, dumping #create-race-wizard innerHTML and retrying', {
|
||||
@@ -832,7 +832,7 @@ export class IRacingDomInteractor {
|
||||
timeout: 10000,
|
||||
});
|
||||
await page.waitForTimeout(150);
|
||||
this.log('info', 'Add Car modal found after retry', { selector: modalSelectorRetry });
|
||||
this.log('info', 'Add Car modal found after retry', { _selector: modalSelectorRetry });
|
||||
} catch {
|
||||
this.log('warn', 'Add Car modal still not found after retry');
|
||||
}
|
||||
@@ -885,7 +885,7 @@ export class IRacingDomInteractor {
|
||||
for (const selector of directSelectors) {
|
||||
const button = page.locator(selector).first();
|
||||
if ((await button.count()) > 0 && (await button.isVisible())) {
|
||||
await this.safeClickService.safeClick(selector, { timeout: IRACING_TIMEOUTS.elementWait });
|
||||
await this.safeClickService.safeClick(_selector, { timeout: IRACING_TIMEOUTS.elementWait });
|
||||
this.log('info', 'Clicked direct Select button for first search result', { selector });
|
||||
return;
|
||||
}
|
||||
@@ -896,14 +896,14 @@ export class IRacingDomInteractor {
|
||||
|
||||
if ((await dropdownButton.count()) > 0 && (await dropdownButton.isVisible())) {
|
||||
await this.safeClickService.safeClick(dropdownSelector, { timeout: IRACING_TIMEOUTS.elementWait });
|
||||
this.log('debug', 'Clicked dropdown toggle, waiting for menu', { selector: dropdownSelector });
|
||||
this.log('debug', 'Clicked dropdown toggle, waiting for menu', { _selector: dropdownSelector });
|
||||
|
||||
await page.waitForSelector('.dropdown-menu.show', { timeout: 3000 }).catch(() => {});
|
||||
|
||||
const itemSelector = IRACING_SELECTORS.steps.trackSelectDropdownItem;
|
||||
await page.waitForTimeout(200);
|
||||
await this.safeClickService.safeClick(itemSelector, { timeout: IRACING_TIMEOUTS.elementWait });
|
||||
this.log('info', 'Clicked first dropdown item to select track config', { selector: itemSelector });
|
||||
this.log('info', 'Clicked first dropdown item to select track config', { _selector: itemSelector });
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -911,7 +911,7 @@ export class IRacingDomInteractor {
|
||||
'.car-row, .car-item, [data-testid*="car"], [id*="favorite_cars"], [id*="select-car"]';
|
||||
const carRow = page.locator(carRowSelector).first();
|
||||
if ((await carRow.count()) > 0) {
|
||||
this.log('info', 'Fallback: clicking car row/item to select', { selector: carRowSelector });
|
||||
this.log('info', 'Fallback: clicking car row/item to select', { _selector: carRowSelector });
|
||||
try {
|
||||
await this.safeClickService.safeClick(carRowSelector, { timeout: IRACING_TIMEOUTS.elementWait });
|
||||
this.log('info', 'Clicked car row fallback selector');
|
||||
@@ -1078,7 +1078,7 @@ export class IRacingDomInteractor {
|
||||
|
||||
if (isVisible) {
|
||||
await radioLabel.click({ timeout: IRACING_TIMEOUTS.elementWait });
|
||||
this.log('info', 'Selected weather type', { weatherType, selector: labelSelector });
|
||||
this.log('info', 'Selected weather type', { weatherType, _selector: labelSelector });
|
||||
} else {
|
||||
this.log('debug', 'Weather type radio not visible, may already be selected or step is different');
|
||||
}
|
||||
|
||||
@@ -102,7 +102,7 @@ export class IRacingDomNavigator {
|
||||
selector = IRACING_SELECTORS.wizard.modal;
|
||||
}
|
||||
|
||||
this.log('debug', 'Waiting for element', { target, selector, mode: this.config.mode });
|
||||
this.log('debug', 'Waiting for element', { target, _selector, mode: this.config.mode });
|
||||
await page.waitForSelector(selector, {
|
||||
state: 'attached',
|
||||
timeout: maxWaitMs ?? defaultTimeout,
|
||||
@@ -164,7 +164,7 @@ export class IRacingDomNavigator {
|
||||
}
|
||||
|
||||
try {
|
||||
this.log('debug', `Waiting for wizard step: ${stepName}`, { selector: containerSelector });
|
||||
this.log('debug', `Waiting for wizard step: ${stepName}`, { _selector: containerSelector });
|
||||
await page.waitForSelector(containerSelector, {
|
||||
state: 'attached',
|
||||
timeout: 15000,
|
||||
@@ -297,7 +297,7 @@ export class IRacingDomNavigator {
|
||||
}
|
||||
}
|
||||
|
||||
async checkWizardDismissed(currentStep: number): Promise<void> {
|
||||
async checkWizardDismissed(_currentStep: number): Promise<void> {
|
||||
if (!this.isRealMode() || currentStep < 3) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ export class SafeClickService {
|
||||
* @param elementText Optional text content of the element (should be direct text only)
|
||||
* @returns true if the selector/text matches a blocked pattern
|
||||
*/
|
||||
private isBlockedSelector(selector: string, elementText?: string): boolean {
|
||||
private isBlockedSelector(_selector: string, elementText?: string): boolean {
|
||||
const selectorLower = selector.toLowerCase();
|
||||
const textLower = elementText?.toLowerCase().trim() ?? '';
|
||||
|
||||
@@ -88,7 +88,7 @@ export class SafeClickService {
|
||||
* @param selector The CSS selector of the element to verify
|
||||
* @throws Error if element is a blocked checkout/payment button
|
||||
*/
|
||||
async verifyNotBlockedElement(selector: string): Promise<void> {
|
||||
async verifyNotBlockedElement(_selector: string): Promise<void> {
|
||||
const page = this.browserSession.getPage();
|
||||
if (!page) return;
|
||||
|
||||
@@ -191,7 +191,7 @@ export class SafeClickService {
|
||||
if (error instanceof Error && error.message.includes('BLOCKED')) {
|
||||
throw error;
|
||||
}
|
||||
this.log('debug', 'Could not verify element (may not exist yet)', { selector, error: String(error) });
|
||||
this.log('debug', 'Could not verify element (may not exist yet)', { _selector, error: String(error) });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -368,7 +368,7 @@ export class SafeClickService {
|
||||
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
||||
try {
|
||||
const useForce = options?.force || attempt === maxRetries;
|
||||
await page.click(selector, { timeout, force: useForce });
|
||||
await page.click(_selector, { timeout, force: useForce });
|
||||
return;
|
||||
} catch (error) {
|
||||
if (error instanceof Error && error.message.includes('BLOCKED')) {
|
||||
@@ -418,7 +418,7 @@ export class SafeClickService {
|
||||
this.log('debug', 'JS fallback click did not find element or failed', { selector });
|
||||
}
|
||||
} catch (e) {
|
||||
this.log('debug', 'JS fallback click error', { selector, error: String(e) });
|
||||
this.log('debug', 'JS fallback click error', { _selector, error: String(e) });
|
||||
}
|
||||
|
||||
this.log('error', 'Max retries reached, click still blocked', { selector });
|
||||
|
||||
@@ -70,7 +70,7 @@ export class MockBrowserAutomationAdapter implements IBrowserAutomation, IAutoma
|
||||
};
|
||||
}
|
||||
|
||||
async clickElement(selector: string): Promise<ClickResultDTO> {
|
||||
async clickElement(_selector: string): Promise<ClickResultDTO> {
|
||||
const delay = this.randomDelay(50, 300);
|
||||
await this.sleep(delay);
|
||||
return {
|
||||
@@ -79,7 +79,7 @@ export class MockBrowserAutomationAdapter implements IBrowserAutomation, IAutoma
|
||||
};
|
||||
}
|
||||
|
||||
async waitForElement(selector: string, maxWaitMs: number = 5000): Promise<WaitResultDTO> {
|
||||
async waitForElement(_selector: string, maxWaitMs: number = 5000): Promise<WaitResultDTO> {
|
||||
const delay = this.randomDelay(100, 1000);
|
||||
|
||||
await this.sleep(delay);
|
||||
|
||||
@@ -3,17 +3,17 @@ import type { LogContext } from '../../../application/ports/LoggerContext';
|
||||
import type { Logger } from '@core/shared/application';
|
||||
|
||||
export class NoOpLogAdapter implements LoggerPort, Logger {
|
||||
debug(_message: string, _context?: LogContext): void {}
|
||||
debug(__message: string, __context?: LogContext): void {}
|
||||
|
||||
info(_message: string, _context?: LogContext): void {}
|
||||
info(__message: string, __context?: LogContext): void {}
|
||||
|
||||
warn(_message: string, _context?: LogContext): void {}
|
||||
warn(__message: string, __context?: LogContext): void {}
|
||||
|
||||
error(_message: string, _error?: Error, _context?: LogContext): void {}
|
||||
error(__message: string, __error?: Error, __context?: LogContext): void {}
|
||||
|
||||
fatal(_message: string, _error?: Error, _context?: LogContext): void {}
|
||||
fatal(__message: string, __error?: Error, __context?: LogContext): void {}
|
||||
|
||||
child(_context: LogContext): LoggerPort {
|
||||
child(__context: LogContext): LoggerPort {
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { AutomationSession } from '../../domain/entities/AutomationSession';
|
||||
import { SessionStateValue } from '../../domain/value-objects/SessionState';
|
||||
|
||||
import type { SessionRepositoryPort } from '../../application/ports/SessionRepositoryPort';
|
||||
|
||||
export class InMemorySessionRepository implements SessionRepositoryPort {
|
||||
|
||||
@@ -39,7 +39,7 @@ export class GetMembershipFeesUseCase
|
||||
|
||||
const fee = await this.membershipFeeRepository.findByLeagueId(leagueId);
|
||||
|
||||
let payments: any[] = [];
|
||||
let payments: unknown[] = [];
|
||||
if (driverId && fee) {
|
||||
const memberPayments = await this.memberPaymentRepository.findByLeagueIdAndDriverId(leagueId, driverId, this.membershipFeeRepository);
|
||||
payments = memberPayments.map(p => ({
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ApproveLeagueJoinRequestUseCase } from '@core/racing/application/use-cases/ApproveLeagueJoinRequestUseCase';
|
||||
import { ApproveLeagueJoinRequestPresenter } from '@apps/api/src/modules/league/presenters/ApproveLeagueJoinRequestPresenter';
|
||||
import { ILeagueMembershipRepository } from '@core/racing/domain/repositories/ILeagueMembershipRepository';
|
||||
|
||||
|
||||
describe('ApproveLeagueJoinRequestUseCase', () => {
|
||||
let useCase: ApproveLeagueJoinRequestUseCase;
|
||||
@@ -12,7 +12,7 @@ describe('ApproveLeagueJoinRequestUseCase', () => {
|
||||
getJoinRequests: jest.fn(),
|
||||
removeJoinRequest: jest.fn(),
|
||||
saveMembership: jest.fn(),
|
||||
} as any;
|
||||
} as unknown;
|
||||
presenter = new ApproveLeagueJoinRequestPresenter();
|
||||
useCase = new ApproveLeagueJoinRequestUseCase(leagueMembershipRepository);
|
||||
});
|
||||
|
||||
@@ -6,7 +6,7 @@ import { Race } from '@core/racing/domain/entities/Race';
|
||||
import { Result } from '@core/racing/domain/entities/Result';
|
||||
import { League } from '@core/racing/domain/entities/League';
|
||||
import { Standing } from '@core/racing/domain/entities/Standing';
|
||||
import { LeagueMembership } from '@core/racing/domain/entities/LeagueMembership';
|
||||
|
||||
import type { FeedItem } from '@core/social/domain/types/FeedItem';
|
||||
import type {
|
||||
IDashboardOverviewPresenter,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { GetLeagueJoinRequestsUseCase } from '@core/racing/application/use-cases/GetLeagueJoinRequestsUseCase';
|
||||
import { LeagueJoinRequestsPresenter } from '@apps/api/src/modules/league/presenters/LeagueJoinRequestsPresenter';
|
||||
import { ILeagueMembershipRepository } from '@core/racing/domain/repositories/ILeagueMembershipRepository';
|
||||
|
||||
import { IDriverRepository } from '@core/racing/domain/repositories/IDriverRepository';
|
||||
|
||||
describe('GetLeagueJoinRequestsUseCase', () => {
|
||||
@@ -12,10 +12,10 @@ describe('GetLeagueJoinRequestsUseCase', () => {
|
||||
beforeEach(() => {
|
||||
leagueMembershipRepository = {
|
||||
getJoinRequests: jest.fn(),
|
||||
} as any;
|
||||
} as unknown;
|
||||
driverRepository = {
|
||||
findByIds: jest.fn(),
|
||||
} as any;
|
||||
} as unknown;
|
||||
presenter = new LeagueJoinRequestsPresenter();
|
||||
useCase = new GetLeagueJoinRequestsUseCase(leagueMembershipRepository, driverRepository);
|
||||
});
|
||||
|
||||
@@ -2,11 +2,7 @@ import { describe, it, expect, beforeEach } from 'vitest';
|
||||
|
||||
import { JoinLeagueUseCase } from '@core/racing/application/use-cases/JoinLeagueUseCase';
|
||||
import type { ILeagueMembershipRepository } from '@core/racing/domain/repositories/ILeagueMembershipRepository';
|
||||
import {
|
||||
LeagueMembership,
|
||||
type MembershipRole,
|
||||
type MembershipStatus,
|
||||
} from '@core/racing/domain/entities/LeagueMembership';
|
||||
|
||||
|
||||
class InMemoryLeagueMembershipRepository implements ILeagueMembershipRepository {
|
||||
private memberships: LeagueMembership[] = [];
|
||||
|
||||
@@ -17,7 +17,7 @@ import { Race } from '@core/racing/domain/entities/Race';
|
||||
import { League } from '@core/racing/domain/entities/League';
|
||||
import { Result } from '@core/racing/domain/entities/Result';
|
||||
import { Driver } from '@core/racing/domain/entities/Driver';
|
||||
import { LeagueMembership } from '@core/racing/domain/entities/LeagueMembership';
|
||||
|
||||
import { GetRaceDetailUseCase } from '@core/racing/application/use-cases/GetRaceDetailUseCase';
|
||||
import { CancelRaceUseCase } from '@core/racing/application/use-cases/CancelRaceUseCase';
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import { League } from '@core/racing/domain/entities/League';
|
||||
import { Result } from '@core/racing/domain/entities/Result';
|
||||
import { Penalty } from '@core/racing/domain/entities/Penalty';
|
||||
import { Standing } from '@core/racing/domain/entities/Standing';
|
||||
import { Driver } from '@core/racing/domain/entities/Driver';
|
||||
|
||||
|
||||
import { GetRaceResultsDetailUseCase } from '@core/racing/application/use-cases/GetRaceResultsDetailUseCase';
|
||||
import { ImportRaceResultsUseCase } from '@core/racing/application/use-cases/ImportRaceResultsUseCase';
|
||||
|
||||
@@ -5,11 +5,8 @@ import type { ILeagueMembershipRepository } from '@core/racing/domain/repositori
|
||||
import type { ITeamRepository } from '@core/racing/domain/repositories/ITeamRepository';
|
||||
import type { ITeamMembershipRepository } from '@core/racing/domain/repositories/ITeamMembershipRepository';
|
||||
import type { RaceRegistration } from '@core/racing/domain/entities/RaceRegistration';
|
||||
import {
|
||||
LeagueMembership,
|
||||
type MembershipStatus,
|
||||
} from '@core/racing/domain/entities/LeagueMembership';
|
||||
import { Team } from '@core/racing/domain/entities/Team';
|
||||
|
||||
|
||||
import { Driver } from '@core/racing/domain/entities/Driver';
|
||||
import type {
|
||||
TeamMembership,
|
||||
@@ -23,17 +20,17 @@ import { WithdrawFromRaceUseCase } from '@core/racing/application/use-cases/With
|
||||
import { IsDriverRegisteredForRaceUseCase } from '@core/racing/application/use-cases/IsDriverRegisteredForRaceUseCase';
|
||||
import { GetRaceRegistrationsUseCase } from '@core/racing/application/use-cases/GetRaceRegistrationsUseCase';
|
||||
|
||||
import { CreateTeamUseCase } from '@core/racing/application/use-cases/CreateTeamUseCase';
|
||||
import { JoinTeamUseCase } from '@core/racing/application/use-cases/JoinTeamUseCase';
|
||||
import { LeaveTeamUseCase } from '@core/racing/application/use-cases/LeaveTeamUseCase';
|
||||
import { ApproveTeamJoinRequestUseCase } from '@core/racing/application/use-cases/ApproveTeamJoinRequestUseCase';
|
||||
import { RejectTeamJoinRequestUseCase } from '@core/racing/application/use-cases/RejectTeamJoinRequestUseCase';
|
||||
import { UpdateTeamUseCase } from '@core/racing/application/use-cases/UpdateTeamUseCase';
|
||||
import { GetAllTeamsUseCase } from '@core/racing/application/use-cases/GetAllTeamsUseCase';
|
||||
import { GetTeamDetailsUseCase } from '@core/racing/application/use-cases/GetTeamDetailsUseCase';
|
||||
import { GetTeamMembersUseCase } from '@core/racing/application/use-cases/GetTeamMembersUseCase';
|
||||
import { GetTeamJoinRequestsUseCase } from '@core/racing/application/use-cases/GetTeamJoinRequestsUseCase';
|
||||
import { GetDriverTeamUseCase } from '@core/racing/application/use-cases/GetDriverTeamUseCase';
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
import type { IDriverRegistrationStatusPresenter } from '@core/racing/application/presenters/IDriverRegistrationStatusPresenter';
|
||||
import type { IRaceRegistrationsPresenter } from '@core/racing/application/presenters/IRaceRegistrationsPresenter';
|
||||
import type {
|
||||
@@ -510,9 +507,9 @@ describe('Racing application use-cases - teams', () => {
|
||||
description: team.description,
|
||||
memberCount: team.memberCount,
|
||||
leagues: team.leagues,
|
||||
specialization: (team as any).specialization,
|
||||
region: (team as any).region,
|
||||
languages: (team as any).languages,
|
||||
specialization: (team as unknown).specialization,
|
||||
region: (team as unknown).region,
|
||||
languages: (team as unknown).languages,
|
||||
})),
|
||||
totalCount: input.teams.length,
|
||||
};
|
||||
@@ -522,7 +519,7 @@ describe('Racing application use-cases - teams', () => {
|
||||
return this.viewModel;
|
||||
}
|
||||
|
||||
get teams(): any[] {
|
||||
get teams(): unknown[] {
|
||||
return this.viewModel?.teams ?? [];
|
||||
}
|
||||
}
|
||||
@@ -559,7 +556,7 @@ describe('Racing application use-cases - teams', () => {
|
||||
return {
|
||||
driverId,
|
||||
driverName,
|
||||
role: ((membership.role as any) === 'owner' ? 'owner' : (membership.role as any) === 'member' ? 'member' : (membership.role as any) === 'manager' ? 'manager' : (membership.role as any) === 'driver' ? 'member' : 'member') as "owner" | "member" | "manager",
|
||||
role: ((membership.role as unknown) === 'owner' ? 'owner' : (membership.role as unknown) === 'member' ? 'member' : (membership.role as unknown) === 'manager' ? 'manager' : (membership.role as unknown) === 'driver' ? 'member' : 'member') as "owner" | "member" | "manager",
|
||||
joinedAt: membership.joinedAt.toISOString(),
|
||||
isActive: membership.status === 'active',
|
||||
avatarUrl,
|
||||
@@ -568,7 +565,7 @@ describe('Racing application use-cases - teams', () => {
|
||||
|
||||
const ownerCount = members.filter((m) => m.role === 'owner').length;
|
||||
const managerCount = members.filter((m) => m.role === 'manager').length;
|
||||
const memberCount = members.filter((m) => (m.role as any) === 'member').length;
|
||||
const memberCount = members.filter((m) => (m.role as unknown) === 'member').length;
|
||||
|
||||
this.viewModel = {
|
||||
members,
|
||||
@@ -583,7 +580,7 @@ describe('Racing application use-cases - teams', () => {
|
||||
return this.viewModel;
|
||||
}
|
||||
|
||||
get members(): any[] {
|
||||
get members(): unknown[] {
|
||||
return this.viewModel?.members ?? [];
|
||||
}
|
||||
}
|
||||
@@ -625,7 +622,7 @@ describe('Racing application use-cases - teams', () => {
|
||||
return this.viewModel;
|
||||
}
|
||||
|
||||
get requests(): any[] {
|
||||
get requests(): unknown[] {
|
||||
return this.viewModel?.requests ?? [];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { RejectLeagueJoinRequestUseCase } from '@core/racing/application/use-cases/RejectLeagueJoinRequestUseCase';
|
||||
import { RejectLeagueJoinRequestPresenter } from '@apps/api/src/modules/league/presenters/RejectLeagueJoinRequestPresenter';
|
||||
import { ILeagueMembershipRepository } from '@core/racing/domain/repositories/ILeagueMembershipRepository';
|
||||
|
||||
|
||||
describe('RejectLeagueJoinRequestUseCase', () => {
|
||||
let useCase: RejectLeagueJoinRequestUseCase;
|
||||
@@ -10,7 +10,7 @@ describe('RejectLeagueJoinRequestUseCase', () => {
|
||||
beforeEach(() => {
|
||||
leagueMembershipRepository = {
|
||||
removeJoinRequest: jest.fn(),
|
||||
} as any;
|
||||
} as unknown;
|
||||
presenter = new RejectLeagueJoinRequestPresenter();
|
||||
useCase = new RejectLeagueJoinRequestUseCase(leagueMembershipRepository);
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { RemoveLeagueMemberUseCase } from '@core/racing/application/use-cases/RemoveLeagueMemberUseCase';
|
||||
import { RemoveLeagueMemberPresenter } from '@apps/api/src/modules/league/presenters/RemoveLeagueMemberPresenter';
|
||||
import { ILeagueMembershipRepository } from '@core/racing/domain/repositories/ILeagueMembershipRepository';
|
||||
|
||||
|
||||
describe('RemoveLeagueMemberUseCase', () => {
|
||||
let useCase: RemoveLeagueMemberUseCase;
|
||||
@@ -11,7 +11,7 @@ describe('RemoveLeagueMemberUseCase', () => {
|
||||
leagueMembershipRepository = {
|
||||
getLeagueMembers: jest.fn(),
|
||||
saveMembership: jest.fn(),
|
||||
} as any;
|
||||
} as unknown;
|
||||
presenter = new RemoveLeagueMemberPresenter();
|
||||
useCase = new RemoveLeagueMemberUseCase(leagueMembershipRepository);
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { UpdateLeagueMemberRoleUseCase } from '@core/racing/application/use-cases/UpdateLeagueMemberRoleUseCase';
|
||||
import { UpdateLeagueMemberRolePresenter } from '@apps/api/src/modules/league/presenters/UpdateLeagueMemberRolePresenter';
|
||||
import { ILeagueMembershipRepository } from '@core/racing/domain/repositories/ILeagueMembershipRepository';
|
||||
|
||||
|
||||
describe('UpdateLeagueMemberRoleUseCase', () => {
|
||||
let useCase: UpdateLeagueMemberRoleUseCase;
|
||||
@@ -11,7 +11,7 @@ describe('UpdateLeagueMemberRoleUseCase', () => {
|
||||
leagueMembershipRepository = {
|
||||
getLeagueMembers: jest.fn(),
|
||||
saveMembership: jest.fn(),
|
||||
} as any;
|
||||
} as unknown;
|
||||
presenter = new UpdateLeagueMemberRolePresenter();
|
||||
useCase = new UpdateLeagueMemberRoleUseCase(leagueMembershipRepository);
|
||||
});
|
||||
|
||||
@@ -14,7 +14,7 @@ export interface GetLeagueJoinRequestsViewModel {
|
||||
}
|
||||
|
||||
export interface GetLeagueJoinRequestsResultDTO {
|
||||
joinRequests: any[];
|
||||
joinRequests: unknown[];
|
||||
drivers: { id: string; name: string }[];
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ export interface GetLeagueMembershipsViewModel {
|
||||
}
|
||||
|
||||
export interface GetLeagueMembershipsResultDTO {
|
||||
memberships: any[];
|
||||
memberships: unknown[];
|
||||
drivers: { id: string; name: string }[];
|
||||
}
|
||||
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import type { Presenter } from '@core/shared/presentation/Presenter';
|
||||
|
||||
export interface GetLeagueProtestsViewModel {
|
||||
protests: any[];
|
||||
protests: unknown[];
|
||||
racesById: Record<string, any>;
|
||||
driversById: Record<string, any>;
|
||||
}
|
||||
|
||||
export interface GetLeagueProtestsResultDTO {
|
||||
protests: any[];
|
||||
races: any[];
|
||||
protests: unknown[];
|
||||
races: unknown[];
|
||||
drivers: { id: string; name: string }[];
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ export interface GetLeagueSeasonsViewModel {
|
||||
}
|
||||
|
||||
export interface GetLeagueSeasonsResultDTO {
|
||||
seasons: any[];
|
||||
seasons: unknown[];
|
||||
}
|
||||
|
||||
export interface IGetLeagueSeasonsPresenter extends Presenter<GetLeagueSeasonsResultDTO, GetLeagueSeasonsViewModel> {}
|
||||
@@ -28,7 +28,7 @@ export interface RacesPageViewModel {
|
||||
}
|
||||
|
||||
export interface RacesPageResultDTO {
|
||||
races: any[];
|
||||
races: unknown[];
|
||||
}
|
||||
|
||||
export interface IRacesPagePresenter
|
||||
|
||||
@@ -96,7 +96,7 @@ export class AcceptSponsorshipRequestUseCase
|
||||
platformFee: acceptedRequest.getPlatformFee().amount,
|
||||
netAmount: acceptedRequest.getNetAmount().amount,
|
||||
};
|
||||
} catch (error: any) {
|
||||
} catch (error) {
|
||||
this.logger.error(`Failed to accept sponsorship request ${dto.requestId}: ${error.message}`, { requestId: dto.requestId, error: error.message, stack: error.stack });
|
||||
throw error;
|
||||
}
|
||||
|
||||
@@ -128,7 +128,7 @@ export class CreateLeagueWithSeasonAndScoringUseCase
|
||||
};
|
||||
this.logger.debug('CreateLeagueWithSeasonAndScoringUseCase completed successfully.', { result });
|
||||
return result;
|
||||
} catch (error: any) {
|
||||
} catch (error) {
|
||||
this.logger.error('Error during CreateLeagueWithSeasonAndScoringUseCase execution.', {
|
||||
command,
|
||||
error: error.message,
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* Creates a new sponsor.
|
||||
*/
|
||||
|
||||
import { Sponsor, type SponsorProps } from '../../domain/entities/Sponsor';
|
||||
|
||||
import type { ISponsorRepository } from '../../domain/repositories/ISponsorRepository';
|
||||
import type {
|
||||
ICreateSponsorPresenter,
|
||||
@@ -41,7 +41,7 @@ export class CreateSponsorUseCase
|
||||
contactEmail: input.contactEmail,
|
||||
...(input.websiteUrl !== undefined ? { websiteUrl: input.websiteUrl } : {}),
|
||||
...(input.logoUrl !== undefined ? { logoUrl: input.logoUrl } : {}),
|
||||
} as any);
|
||||
} as unknown);
|
||||
|
||||
await this.sponsorRepository.create(sponsor);
|
||||
|
||||
|
||||
@@ -138,8 +138,8 @@ export class GetDashboardOverviewUseCase {
|
||||
presenter.present(viewModel);
|
||||
}
|
||||
|
||||
private async getDriverLeagues(allLeagues: any[], driverId: string): Promise<any[]> {
|
||||
const driverLeagues: any[] = [];
|
||||
private async getDriverLeagues(allLeagues: unknown[], driverId: string): Promise<any[]> {
|
||||
const driverLeagues: unknown[] = [];
|
||||
|
||||
for (const league of allLeagues) {
|
||||
const membership = await this.leagueMembershipRepository.getMembership(league.id, driverId);
|
||||
@@ -152,7 +152,7 @@ export class GetDashboardOverviewUseCase {
|
||||
}
|
||||
|
||||
private async partitionUpcomingRacesByRegistration(
|
||||
upcomingRaces: any[],
|
||||
upcomingRaces: unknown[],
|
||||
driverId: string,
|
||||
leagueMap: Map<string, string>,
|
||||
): Promise<{
|
||||
@@ -194,9 +194,9 @@ export class GetDashboardOverviewUseCase {
|
||||
}
|
||||
|
||||
private buildRecentResults(
|
||||
allResults: any[],
|
||||
allRaces: any[],
|
||||
allLeagues: any[],
|
||||
allResults: unknown[],
|
||||
allRaces: unknown[],
|
||||
allLeagues: unknown[],
|
||||
driverId: string,
|
||||
): DashboardRecentResultViewModel[] {
|
||||
const raceById = new Map(allRaces.map(race => [race.id, race]));
|
||||
@@ -237,7 +237,7 @@ export class GetDashboardOverviewUseCase {
|
||||
}
|
||||
|
||||
private async buildLeagueStandingsSummaries(
|
||||
driverLeagues: any[],
|
||||
driverLeagues: unknown[],
|
||||
driverId: string,
|
||||
): Promise<DashboardLeagueStandingSummaryViewModel[]> {
|
||||
const summaries: DashboardLeagueStandingSummaryViewModel[] = [];
|
||||
@@ -277,7 +277,7 @@ export class GetDashboardOverviewUseCase {
|
||||
return activeLeagueIds.size;
|
||||
}
|
||||
|
||||
private buildFeedSummary(feedItems: any[]): DashboardFeedSummaryViewModel {
|
||||
private buildFeedSummary(feedItems: unknown[]): DashboardFeedSummaryViewModel {
|
||||
const items: DashboardFeedItemSummaryViewModel[] = feedItems.map(item => ({
|
||||
id: item.id,
|
||||
type: item.type,
|
||||
@@ -297,7 +297,7 @@ export class GetDashboardOverviewUseCase {
|
||||
};
|
||||
}
|
||||
|
||||
private buildFriendsSummary(friends: any[]): DashboardFriendSummaryViewModel[] {
|
||||
private buildFriendsSummary(friends: unknown[]): DashboardFriendSummaryViewModel[] {
|
||||
return friends.map(friend => ({
|
||||
id: friend.id,
|
||||
name: friend.name,
|
||||
|
||||
@@ -8,7 +8,7 @@ export interface GetLeagueJoinRequestsUseCaseParams {
|
||||
}
|
||||
|
||||
export interface GetLeagueJoinRequestsResultDTO {
|
||||
joinRequests: any[];
|
||||
joinRequests: unknown[];
|
||||
drivers: { id: string; name: string }[];
|
||||
}
|
||||
|
||||
|
||||
@@ -9,8 +9,8 @@ export interface GetLeagueProtestsUseCaseParams {
|
||||
}
|
||||
|
||||
export interface GetLeagueProtestsResultDTO {
|
||||
protests: any[];
|
||||
races: any[];
|
||||
protests: unknown[];
|
||||
races: unknown[];
|
||||
drivers: { id: string; name: string }[];
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ export interface GetLeagueSeasonsUseCaseParams {
|
||||
}
|
||||
|
||||
export interface GetLeagueSeasonsResultDTO {
|
||||
seasons: any[];
|
||||
seasons: unknown[];
|
||||
}
|
||||
|
||||
export class GetLeagueSeasonsUseCase implements UseCase<GetLeagueSeasonsUseCaseParams, GetLeagueSeasonsResultDTO, GetLeagueSeasonsViewModel, IGetLeagueSeasonsPresenter> {
|
||||
|
||||
@@ -202,7 +202,7 @@ export class GetProfileOverviewUseCase {
|
||||
|
||||
private async buildTeamMemberships(
|
||||
driverId: string,
|
||||
teams: any[],
|
||||
teams: unknown[],
|
||||
): Promise<ProfileOverviewTeamMembershipViewModel[]> {
|
||||
const memberships: ProfileOverviewTeamMembershipViewModel[] = [];
|
||||
|
||||
@@ -231,7 +231,7 @@ export class GetProfileOverviewUseCase {
|
||||
return memberships;
|
||||
}
|
||||
|
||||
private buildSocialSummary(friends: any[]): ProfileOverviewSocialSummaryViewModel {
|
||||
private buildSocialSummary(friends: unknown[]): ProfileOverviewSocialSummaryViewModel {
|
||||
return {
|
||||
friendsCount: friends.length,
|
||||
friends: friends.map(friend => ({
|
||||
|
||||
@@ -32,7 +32,7 @@ export class GetTeamsLeaderboardUseCase
|
||||
|
||||
async execute(_input: void, presenter: ITeamsLeaderboardPresenter): Promise<void> {
|
||||
const allTeams = await this.teamRepository.findAll();
|
||||
const teams: any[] = [];
|
||||
const teams: unknown[] = [];
|
||||
|
||||
await Promise.all(
|
||||
allTeams.map(async (team) => {
|
||||
|
||||
@@ -3,11 +3,7 @@ import type {
|
||||
ILeagueMembershipRepository,
|
||||
} from '@core/racing/domain/repositories/ILeagueMembershipRepository';
|
||||
import type { AsyncUseCase } from '@core/shared/application';
|
||||
import {
|
||||
LeagueMembership,
|
||||
type MembershipRole,
|
||||
type MembershipStatus,
|
||||
} from '@core/racing/domain/entities/LeagueMembership';
|
||||
|
||||
import type { JoinLeagueCommandDTO } from '../dto/JoinLeagueCommandDTO';
|
||||
import { BusinessRuleViolationError } from '../errors/RacingApplicationError';
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { ITeamRepository } from '../../domain/repositories/ITeamRepository';
|
||||
import type { ITeamMembershipRepository } from '../../domain/repositories/ITeamMembershipRepository';
|
||||
import { Team } from '../../domain/entities/Team';
|
||||
|
||||
import type { UpdateTeamCommandDTO } from '../dto/TeamCommandAndQueryDTO';
|
||||
|
||||
export class UpdateTeamUseCase {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* Represents a driver's custom livery for a specific car.
|
||||
* Includes user-placed decals and league-specific overrides.
|
||||
*/
|
||||
import { RacingDomainValidationError, RacingDomainInvariantError, RacingDomainError } from '../errors/RacingDomainError';
|
||||
|
||||
import type { IEntity } from '@core/shared/domain';
|
||||
|
||||
import type { LiveryDecal } from '../value-objects/LiveryDecal';
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* Represents an admin-defined livery template for a specific car.
|
||||
* Contains base image and sponsor decal placements.
|
||||
*/
|
||||
import { RacingDomainValidationError, RacingDomainInvariantError, RacingDomainError } from '../errors/RacingDomainError';
|
||||
|
||||
import type { IEntity } from '@core/shared/domain';
|
||||
|
||||
import type { LiveryDecal } from '../value-objects/LiveryDecal';
|
||||
|
||||
@@ -4,10 +4,7 @@ import {
|
||||
RacingDomainInvariantError,
|
||||
RacingDomainValidationError,
|
||||
} from '@core/racing/domain/errors/RacingDomainError';
|
||||
import {
|
||||
Season,
|
||||
type SeasonStatus,
|
||||
} from '@core/racing/domain/entities/Season';
|
||||
|
||||
import { SeasonScoringConfig } from '@core/racing/domain/value-objects/SeasonScoringConfig';
|
||||
import {
|
||||
SeasonDropPolicy,
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* Immutable entity with factory methods and domain validation.
|
||||
*/
|
||||
|
||||
import { RacingDomainError, RacingDomainValidationError } from '../errors/RacingDomainError';
|
||||
|
||||
import type { IEntity } from '@core/shared/domain';
|
||||
|
||||
export class Standing implements IEntity<string> {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { SeasonSchedule } from '../value-objects/SeasonSchedule';
|
||||
import { ScheduledRaceSlot } from '../value-objects/ScheduledRaceSlot';
|
||||
import type { RecurrenceStrategy } from '../value-objects/RecurrenceStrategy';
|
||||
import { RacingDomainError, RacingDomainValidationError } from '../errors/RacingDomainError';
|
||||
|
||||
import { RaceTimeOfDay } from '../value-objects/RaceTimeOfDay';
|
||||
import type { Weekday } from '../types/Weekday';
|
||||
import { weekdayToIndex } from '../types/Weekday';
|
||||
|
||||
Reference in New Issue
Block a user