This commit is contained in:
2025-12-01 17:27:56 +01:00
parent e7ada8aa23
commit 98a09a3f2b
41 changed files with 2341 additions and 1525 deletions

View File

@@ -0,0 +1,18 @@
import { StepId } from 'packages/domain/value-objects/StepId';
import type { PlaywrightAutomationAdapter } from 'packages/infrastructure/adapters/automation';
import type { AutomationResult } from 'packages/application/ports/AutomationResults';
export function assertAutoNavigationConfig(config: Record<string, unknown>): void {
if ((config as any).__skipFixtureNavigation) {
throw new Error('__skipFixtureNavigation is forbidden in auto-navigation suites');
}
}
export async function executeStepWithAutoNavigationGuard(
adapter: PlaywrightAutomationAdapter,
step: number,
config: Record<string, unknown>,
): Promise<AutomationResult> {
assertAutoNavigationConfig(config);
return adapter.executeStep(StepId.create(step), config);
}

View File

@@ -13,13 +13,40 @@ export interface StepHarness {
getFixtureUrl(step: number): string;
navigateToFixtureStep(step: number): Promise<void>;
executeStep(step: number, config: Record<string, unknown>): Promise<AutomationResult>;
executeStepWithAutoNavigation(
step: number,
config: Record<string, unknown>,
): Promise<AutomationResult>;
executeStepWithFixtureMismatch(
step: number,
config: Record<string, unknown>,
): Promise<AutomationResult>;
dispose(): Promise<void>;
}
export async function createStepHarness(): Promise<StepHarness> {
const server = new FixtureServer();
const { url } = await server.start();
async function createRealAdapter(baseUrl: string): Promise<PlaywrightAutomationAdapter> {
const logger = new PinoLogAdapter();
const adapter = new PlaywrightAutomationAdapter(
{
headless: true,
timeout: 8000,
mode: 'real',
baseUrl,
userDataDir: '',
},
logger,
);
const result = await adapter.connect(false);
if (!result.success) {
throw new Error(result.error || 'Failed to connect Playwright adapter');
}
return adapter;
}
async function createMockAdapter(): Promise<PlaywrightAutomationAdapter> {
const logger = new PinoLogAdapter();
const adapter = new PlaywrightAutomationAdapter(
@@ -31,18 +58,52 @@ export async function createStepHarness(): Promise<StepHarness> {
logger,
);
await adapter.connect();
const result = await adapter.connect();
if (!result.success) {
throw new Error(result.error || 'Failed to connect mock Playwright adapter');
}
return adapter;
}
export async function createStepHarness(useMock: boolean = false): Promise<StepHarness> {
const server = new FixtureServer();
const { url } = await server.start();
const adapter = useMock ? await createMockAdapter() : await createRealAdapter(url);
async function navigateToFixtureStep(step: number): Promise<void> {
await adapter.navigateToPage(server.getFixtureUrl(step));
await adapter.getPage()?.waitForLoadState('domcontentloaded');
}
async function executeStepWithAutoNavigation(
step: number,
config: Record<string, unknown>,
): Promise<AutomationResult> {
if ((config as any).__skipFixtureNavigation) {
throw new Error(
'__skipFixtureNavigation is not allowed in auto-navigation path',
);
}
return adapter.executeStep(StepId.create(step), config);
}
async function executeStepWithFixtureMismatch(
step: number,
config: Record<string, unknown>,
): Promise<AutomationResult> {
return adapter.executeStep(StepId.create(step), {
...config,
__skipFixtureNavigation: true,
});
}
async function executeStep(
step: number,
config: Record<string, unknown>,
): Promise<AutomationResult> {
return adapter.executeStep(StepId.create(step), config);
return executeStepWithFixtureMismatch(step, config);
}
async function dispose(): Promise<void> {
@@ -57,6 +118,8 @@ export async function createStepHarness(): Promise<StepHarness> {
getFixtureUrl: (step) => server.getFixtureUrl(step),
navigateToFixtureStep,
executeStep,
executeStepWithAutoNavigation,
executeStepWithFixtureMismatch,
dispose,
};
}