Files
gridpilot.gg/tests/unit/application/services/OverlaySyncService.test.ts

48 lines
2.0 KiB
TypeScript

import { describe, expect, test } from 'vitest'
import { OverlayAction, ActionAck } from '../../../../packages/application/ports/IOverlaySyncPort'
import { IAutomationEventPublisher, AutomationEvent } from '../../../../packages/application/ports/IAutomationEventPublisher'
import { IAutomationLifecycleEmitter, LifecycleCallback } from '../../../../packages/infrastructure/adapters/IAutomationLifecycleEmitter'
import { OverlaySyncService } from '../../../../packages/application/services/OverlaySyncService'
class MockLifecycleEmitter implements IAutomationLifecycleEmitter {
private callbacks: Set<LifecycleCallback> = new Set()
onLifecycle(cb: LifecycleCallback): void {
this.callbacks.add(cb)
}
offLifecycle(cb: LifecycleCallback): void {
this.callbacks.delete(cb)
}
async emit(event: AutomationEvent) {
for (const cb of Array.from(this.callbacks)) {
// fire without awaiting to simulate async emitter
cb(event)
}
}
}
describe('OverlaySyncService (unit)', () => {
test('startAction resolves as confirmed only after action-started event is emitted', async () => {
const emitter = new MockLifecycleEmitter()
// create service wiring: pass emitter as dependency (constructor shape expected)
const svc = new OverlaySyncService({ lifecycleEmitter: emitter as any, logger: console as any, publisher: { publish: async () => {} } as any })
const action: OverlayAction = { id: 'add-car', label: 'Adding...' }
// start the action but don't emit event yet
const promise = svc.startAction(action)
// wait a small tick to ensure promise hasn't resolved prematurely
await new Promise((r) => setTimeout(r, 10))
let resolved = false
promise.then(() => (resolved = true))
expect(resolved).toBe(false)
// now emit action-started
await emitter.emit({ type: 'action-started', actionId: 'add-car', timestamp: Date.now() })
const ack = await promise
expect(ack.status).toBe('confirmed')
expect(ack.id).toBe('add-car')
})
})