import { describe, it, expect, beforeEach, vi } from 'vitest' import { render, screen, act } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { MemoryRouter } from 'react-router-dom' import { BuildFlash } from './BuildFlash' import { useSession } from '@/store/session' import type { WsEvent } from '@/types' // Capture the live-activity callback so tests can push node events. const sendPrompt = vi.fn() let liveOnEvent: ((e: WsEvent) => void) | null = null const closeSpy = vi.fn() vi.mock('@/lib/api', () => ({ AGENT: 'default', sendPrompt: (...args: unknown[]) => sendPrompt(...args), openTeamActivity: (_teamId: string, onEvent: (e: WsEvent) => void) => { liveOnEvent = onEvent return closeSpy }, // OpenYourNode (rendered here) reads the runtime mode. getMode: () => Promise.resolve({ localMode: false }), })) describe('BuildFlash', () => { beforeEach(() => { useSession.getState().reset() sessionStorage.clear() sendPrompt.mockReset() sendPrompt.mockResolvedValue(undefined) closeSpy.mockReset() liveOnEvent = null }) it('disables Send until there is a prompt', () => { render() expect(screen.getByRole('button', { name: /send/i })).toBeDisabled() }) it('shows the Live board badge', () => { render() expect(screen.getByText(/live board/i)).toBeInTheDocument() }) it('sends the prompt to the single agent and renders streamed board activity', async () => { const user = userEvent.setup() render() await user.type(screen.getByLabelText(/prompt your board/i), 'scroll HELLO') await user.click(screen.getByRole('button', { name: /working|send/i })) expect(sendPrompt).toHaveBeenCalledWith(useSession.getState().teamId, 'scroll HELLO', 'default') // a flash event streams in over the (mocked) SSE feed act(() => { liveOnEvent?.({ type: 'node:activity', teamId: 't', kind: 'flash', label: 'Flashed to 0x80F0000', ts: 'T' }) }) expect(screen.getByTestId('activity-log')).toHaveTextContent(/flashed to 0x80F0000/i) // terminal event re-enables Send expect(screen.getByRole('button', { name: /send/i })).toBeEnabled() }) it('closes the activity stream on unmount', () => { const { unmount } = render() unmount() expect(closeSpy).toHaveBeenCalled() }) })