159 lines
3.8 KiB
TypeScript
159 lines
3.8 KiB
TypeScript
import { StepId } from '../../../../automation-domain/value-objects/StepId';
|
|
import type { IBrowserAutomation } from '../../../../automation-application/ports/IScreenAutomation';
|
|
import {
|
|
NavigationResult,
|
|
FormFillResult,
|
|
ClickResult,
|
|
WaitResult,
|
|
ModalResult,
|
|
AutomationResult,
|
|
} from '../../../../automation-application/ports/AutomationResults';
|
|
|
|
interface MockConfig {
|
|
simulateFailures?: boolean;
|
|
failureRate?: number;
|
|
}
|
|
|
|
interface StepExecutionResult {
|
|
success: boolean;
|
|
stepId: number;
|
|
wasModalStep?: boolean;
|
|
shouldStop?: boolean;
|
|
executionTime: number;
|
|
metrics: {
|
|
totalDelay: number;
|
|
operationCount: number;
|
|
};
|
|
}
|
|
|
|
export class MockBrowserAutomationAdapter implements IBrowserAutomation {
|
|
private config: MockConfig;
|
|
private connected: boolean = false;
|
|
|
|
constructor(config: MockConfig = {}) {
|
|
this.config = {
|
|
simulateFailures: config.simulateFailures ?? false,
|
|
failureRate: config.failureRate ?? 0.1,
|
|
};
|
|
}
|
|
|
|
async connect(): Promise<AutomationResult> {
|
|
this.connected = true;
|
|
return { success: true };
|
|
}
|
|
|
|
async disconnect(): Promise<void> {
|
|
this.connected = false;
|
|
}
|
|
|
|
isConnected(): boolean {
|
|
return this.connected;
|
|
}
|
|
|
|
async navigateToPage(url: string): Promise<NavigationResult> {
|
|
const delay = this.randomDelay(200, 800);
|
|
await this.sleep(delay);
|
|
return {
|
|
success: true,
|
|
url,
|
|
loadTime: delay,
|
|
};
|
|
}
|
|
|
|
async fillFormField(fieldName: string, value: string): Promise<FormFillResult> {
|
|
const delay = this.randomDelay(100, 500);
|
|
await this.sleep(delay);
|
|
return {
|
|
success: true,
|
|
fieldName,
|
|
valueSet: value,
|
|
};
|
|
}
|
|
|
|
async clickElement(selector: string): Promise<ClickResult> {
|
|
const delay = this.randomDelay(50, 300);
|
|
await this.sleep(delay);
|
|
return {
|
|
success: true,
|
|
target: selector,
|
|
};
|
|
}
|
|
|
|
async waitForElement(selector: string, maxWaitMs: number = 5000): Promise<WaitResult> {
|
|
const delay = this.randomDelay(100, 1000);
|
|
|
|
await this.sleep(delay);
|
|
|
|
return {
|
|
success: true,
|
|
target: selector,
|
|
waitedMs: delay,
|
|
found: true,
|
|
};
|
|
}
|
|
|
|
async handleModal(stepId: StepId, action: string): Promise<ModalResult> {
|
|
if (!stepId.isModalStep()) {
|
|
throw new Error(`Step ${stepId.value} is not a modal step`);
|
|
}
|
|
|
|
const delay = this.randomDelay(200, 600);
|
|
await this.sleep(delay);
|
|
return {
|
|
success: true,
|
|
stepId: stepId.value,
|
|
action,
|
|
};
|
|
}
|
|
|
|
async executeStep(stepId: StepId, config: Record<string, unknown>): Promise<AutomationResult> {
|
|
if (this.shouldSimulateFailure()) {
|
|
throw new Error(`Simulated failure at step ${stepId.value}`);
|
|
}
|
|
|
|
const startTime = Date.now();
|
|
let totalDelay = 0;
|
|
let operationCount = 0;
|
|
|
|
const navigationDelay = this.randomDelay(200, 500);
|
|
await this.sleep(navigationDelay);
|
|
totalDelay += navigationDelay;
|
|
operationCount++;
|
|
|
|
if (stepId.isModalStep()) {
|
|
const modalDelay = this.randomDelay(200, 400);
|
|
await this.sleep(modalDelay);
|
|
totalDelay += modalDelay;
|
|
operationCount++;
|
|
}
|
|
|
|
const executionTime = Date.now() - startTime;
|
|
|
|
return {
|
|
success: true,
|
|
metadata: {
|
|
stepId: stepId.value,
|
|
wasModalStep: stepId.isModalStep(),
|
|
shouldStop: stepId.isFinalStep(),
|
|
executionTime,
|
|
totalDelay,
|
|
operationCount,
|
|
},
|
|
};
|
|
}
|
|
|
|
private randomDelay(min: number, max: number): number {
|
|
return Math.floor(Math.random() * (max - min + 1)) + min;
|
|
}
|
|
|
|
private async sleep(ms: number): Promise<void> {
|
|
return new Promise(resolve => setTimeout(resolve, ms));
|
|
}
|
|
|
|
private shouldSimulateFailure(): boolean {
|
|
if (!this.config.simulateFailures) {
|
|
return false;
|
|
}
|
|
return Math.random() < (this.config.failureRate || 0.1);
|
|
}
|
|
} |