/** * Steer handler unit tests (no Playwright). * Run with: node --test tests/live-e2e-steer-agent.test.mjs */ import { describe, it, before, after } from 'node:test'; import assert from 'node:assert/strict'; import { readFileSync } from 'node:fs'; import { join } from 'node:path'; import { addSteerMarkerToSource, createFakeAgent, findSteerTargetFile, runAgentLoop, STEER_MARKER_ATTR } from './live-e2e/agent.mjs'; import { stageFixture, startLiveServer, stopLiveServer, ENGINE_BIN, ENGINE_MISSING_MESSAGE, FIXTURES_DIR } from './live-e2e/session.mjs'; const FIXTURE_NAME = 'vite8-react-plain'; // The loop drives live-server and live-poll through the engine binary. describe('live-e2e steer agent handler', { skip: ENGINE_BIN ? false : ENGINE_MISSING_MESSAGE }, () => { let tmp; let live; let abort; let loopDone; before(async () => { const fixture = JSON.parse(readFileSync(join(FIXTURES_DIR, FIXTURE_NAME, 'fixture.json'), 'utf-8')); tmp = stageFixture(FIXTURE_NAME, fixture); live = startLiveServer(tmp); abort = new AbortController(); loopDone = runAgentLoop({ tmp, engineBin: ENGINE_BIN, port: live.port, token: live.token, agent: createFakeAgent(), signal: abort.signal, log: () => {}, }); }); after(async () => { abort?.abort(); await loopDone?.catch(() => {}); if (live) stopLiveServer(tmp); }); it('findSteerTargetFile locates the hero source file', () => { const file = findSteerTargetFile(tmp); assert.match(file, /App\.jsx$/); const body = readFileSync(file, 'utf-8'); assert.match(body, /hero-title/); }); it('marks JSX template-expression className attributes', () => { const source = [ 'export default function App() {', ' return