Files
orca/mobile/src/session/MobileNativeChatView.rows.test.ts
T

69 lines
2.7 KiB
TypeScript

import { describe, expect, it, vi } from 'vitest'
import {
installChatViewHooks,
assistantTurn,
listIds,
render,
renderedRow,
update
} from './MobileNativeChatView.harness.test-fixture'
vi.mock('react-native', async () => {
const { reactNativeStub } = await import('./MobileNativeChatView.render-stubs.test-fixture')
return reactNativeStub()
})
vi.mock('react-native-safe-area-context', () => ({
useSafeAreaInsets: () => ({ top: 0, bottom: 0, left: 0, right: 0 })
}))
vi.mock('react-native-gesture-handler', async () => {
const { gestureHandlerStub } = await import('./MobileNativeChatView.render-stubs.test-fixture')
return gestureHandlerStub()
})
vi.mock('lucide-react-native', () => ({
ArrowDown: 'ArrowDown',
ChevronsDownUp: 'ChevronsDownUp',
ChevronsUpDown: 'ChevronsUpDown',
Square: 'Square'
}))
vi.mock('./MobileNativeChatMessage', () => ({ MobileNativeChatMessage: 'ChatMessage' }))
vi.mock('./MobileNativeChatLiveLine', () => ({ MobileNativeChatLiveLine: 'LiveStatus' }))
vi.mock('./MobileNativeChatAsk', () => ({ MobileNativeChatAsk: 'ChatAsk' }))
vi.mock('./MobileNativeChatPermission', () => ({ MobileNativeChatPermission: 'ChatPermission' }))
vi.mock('./MobileNativeChatQuestion', () => ({ MobileNativeChatQuestion: 'ChatQuestion' }))
vi.mock('../components/ActionSheetModal', () => ({ ActionSheetModal: 'ActionSheetModal' }))
vi.mock('./native-chat/composer/MobileNativeChatComposer', async () => {
const { composerStub } = await import('./MobileNativeChatView.render-stubs.test-fixture')
return composerStub()
})
describe('MobileNativeChatView: rows and the streaming bubble', () => {
installChatViewHooks()
// Streaming eligibility is tested in the overlay, which stays mounted across chat-view toggles.
it('appends the gated streaming bubble after the folded transcript', async () => {
const folded = [assistantTurn('a1', 'The tests pass.')]
await render({ folded })
expect(listIds()).toEqual(['a1'])
await update({ folded, streaming: 'The tests' })
expect(listIds()).toEqual(['a1', 'streaming'])
})
it('tells a row whether the host still waits on the prompt it stands for', async () => {
const rows = [assistantTurn('asked', 'Tea or coffee?'), assistantTurn('open', 'Which branch?')]
await render({ messages: rows, folded: rows, actionablePromptIds: ['open'] })
expect(renderedRow('asked').props.awaiting).toBe(false)
expect(renderedRow('open').props.awaiting).toBe(true)
})
it('renders an accepted optimistic image send without a queued state', async () => {
await render({
pending: [{ id: 'pending-1', text: 'look', images: ['file:///phone-photo.jpg'] }]
})
expect(listIds()).toEqual(['pending-1'])
expect(renderedRow('pending-1').props).not.toHaveProperty('queued')
})
})