import { describe, it, expect, beforeAll, afterAll, beforeEach, afterEach } from 'vitest'; import path from 'path'; import { PlaywrightAutomationAdapter, FixtureServer } from 'packages/infrastructure/adapters/automation'; import { StepId } from 'packages/domain/value-objects/StepId'; import { PinoLogAdapter } from 'packages/infrastructure/adapters/logging/PinoLogAdapter'; describe('Step 9 – add car', () => { describe('happy path', () => { let adapter: PlaywrightAutomationAdapter; const fixtureBaseUrl = `file://${path.resolve(process.cwd(), 'html-dumps')}`; beforeAll(async () => { adapter = new PlaywrightAutomationAdapter({ headless: true, timeout: 5000, baseUrl: fixtureBaseUrl, mode: 'mock', }); await adapter.connect(); }); afterAll(async () => { await adapter.disconnect(); }); it('executes on Add Car modal from Cars step', async () => { await adapter.navigateToPage(`${fixtureBaseUrl}/step-09-add-car.html`); const page = adapter.getPage(); expect(page).not.toBeNull(); const modalTitleBefore = await page!.textContent('[data-indicator="add-car"]'); expect(modalTitleBefore).toContain('Add a Car'); const result = await adapter.executeStep( StepId.create(9), { carSearch: 'Porsche 911 GT3 R' }, ); expect(result.success).toBe(true); expect(result.error).toBeUndefined(); }); }); describe('state validation', () => { let server: FixtureServer; let adapter: PlaywrightAutomationAdapter; let logger: PinoLogAdapter; beforeEach(async () => { server = new FixtureServer(); const serverInfo = await server.start(); logger = new PinoLogAdapter(); adapter = new PlaywrightAutomationAdapter( { headless: true, timeout: 5000, mode: 'mock', baseUrl: serverInfo.url, }, logger, ); await adapter.connect(); }); afterEach(async () => { await adapter.disconnect(); await server.stop(); }); it('throws when executed on Track page instead of Cars page', async () => { await adapter.navigateToPage(server.getFixtureUrl(11)); await adapter.getPage()?.waitForLoadState('domcontentloaded'); await expect(async () => { await adapter.executeStep(StepId.create(9), { carSearch: 'Mazda MX-5', }); }).rejects.toThrow(/Step 9 FAILED validation/i); }); it('detects state mismatch when Cars button is missing', async () => { await adapter.navigateToPage(server.getFixtureUrl(11)); await adapter.getPage()?.waitForLoadState('domcontentloaded'); await expect(async () => { await adapter.executeStep(StepId.create(9), { carSearch: 'Porsche 911', }); }).rejects.toThrow(/Expected cars step/i); }); it('detects when Track container is present instead of Cars page', async () => { await adapter.navigateToPage(server.getFixtureUrl(11)); await adapter.getPage()?.waitForLoadState('domcontentloaded'); await expect(async () => { await adapter.executeStep(StepId.create(9), { carSearch: 'Ferrari 488', }); }).rejects.toThrow(/3 steps ahead|Track page/i); }); it('passes validation when on Cars page', async () => { await adapter.navigateToPage(server.getFixtureUrl(8)); await adapter.getPage()?.waitForLoadState('domcontentloaded'); const result = await adapter.executeStep(StepId.create(9), { carSearch: 'Mazda MX-5', }); expect(result.success).toBe(true); }); it('provides detailed error context in validation failure', async () => { await adapter.navigateToPage(server.getFixtureUrl(11)); await adapter.getPage()?.waitForLoadState('domcontentloaded'); let errorMessage = ''; try { await adapter.executeStep(StepId.create(9), { carSearch: 'BMW M4', }); } catch (error) { errorMessage = error instanceof Error ? error.message : String(error); } expect(errorMessage).toContain('Step 9'); expect(errorMessage).toMatch(/validation|mismatch|wrong page/i); }); it('validates page state before attempting any Step 9 actions', async () => { await adapter.navigateToPage(server.getFixtureUrl(11)); await adapter.getPage()?.waitForLoadState('domcontentloaded'); const page = adapter.getPage(); if (!page) { throw new Error('Page not available'); } let carModalOpened = false; page.on('framenavigated', () => { carModalOpened = true; }); let validationError = false; try { await adapter.executeStep(StepId.create(9), { carSearch: 'Audi R8', }); } catch { validationError = true; } expect(validationError).toBe(true); expect(carModalOpened).toBe(false); }); it('checks wizard footer state in Step 9', async () => { await adapter.navigateToPage(server.getFixtureUrl(11)); await adapter.getPage()?.waitForLoadState('domcontentloaded'); await expect(async () => { await adapter.executeStep(StepId.create(9), { carSearch: 'McLaren 720S', }); }).rejects.toThrow(); }); }); });