import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'; import { render, act, waitFor } from '@testing-library/react'; // A voiceStore arrasta o AudioManager, que carrega um AudioWorklet inexistente // no jsdom. Mesmo stub que os outros testes que tocam nesta store usam. vi.mock('../../audio/AudioManager', () => ({ AudioManager: { getInstance: () => ({ resumeContext: vi.fn() }) }, })); import { AndroidVoiceService } from './AndroidVoiceService'; import { useVoiceStore } from '../../stores/voiceStore'; const start = vi.fn(() => Promise.resolve()); const stop = vi.fn(() => Promise.resolve()); let hangupHandler: (() => void) | null = null; function installCapacitor(platform = 'android') { (globalThis as { Capacitor?: unknown }).Capacitor = { isNativePlatform: () => true, getPlatform: () => platform, Plugins: { VoiceForeground: { start, stop, addListener: (_e: string, h: () => void) => { hangupHandler = h; return Promise.resolve({ remove: () => { hangupHandler = null; } }); }, }, }, }; } describe('AndroidVoiceService', () => { beforeEach(() => { start.mockClear(); stop.mockClear(); hangupHandler = null; useVoiceStore.setState({ isLiveKitConnected: false, currentVoiceChannelId: null }); }); afterEach(() => { delete (globalThis as { Capacitor?: unknown }).Capacitor; }); it('starts the service when a call connects and stops it when it ends', async () => { installCapacitor(); render(); expect(start).not.toHaveBeenCalled(); act(() => { useVoiceStore.setState({ isLiveKitConnected: true, currentVoiceChannelId: 'c-1' }); }); await waitFor(() => expect(start).toHaveBeenCalledTimes(1)); act(() => { useVoiceStore.setState({ isLiveKitConnected: false, currentVoiceChannelId: null }); }); await waitFor(() => expect(stop).toHaveBeenCalledTimes(1)); }); it('starts on mount when a call is already in progress', async () => { // A WebView pode recarregar no meio da chamada. Se o servico so subisse na // proxima transicao, a call seguiria desprotegida ate alguem sair e entrar // de novo — e cairia ao trancar a tela. installCapacitor(); useVoiceStore.setState({ isLiveKitConnected: true, currentVoiceChannelId: 'c-1' }); render(); await waitFor(() => expect(start).toHaveBeenCalledTimes(1)); }); it('leaves the call when the notification hangup is tapped', async () => { installCapacitor(); const disconnectFn = vi.fn(() => Promise.resolve()); useVoiceStore.setState({ disconnectFn }); render(); await waitFor(() => expect(hangupHandler).not.toBeNull()); act(() => hangupHandler!()); expect(disconnectFn).toHaveBeenCalled(); }); it('does nothing outside the Android app', async () => { // Mesmo componente montado no navegador e no desktop: nao pode tocar em // nada nativo nem quebrar. render(); act(() => { useVoiceStore.setState({ isLiveKitConnected: true, currentVoiceChannelId: 'c-1' }); }); expect(start).not.toHaveBeenCalled(); expect(stop).not.toHaveBeenCalled(); }); it('ignores a web build of Capacitor', async () => { installCapacitor('web'); render(); act(() => { useVoiceStore.setState({ isLiveKitConnected: true, currentVoiceChannelId: 'c-1' }); }); expect(start).not.toHaveBeenCalled(); }); });