import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { render } from '@testing-library/react-native'
import React from 'react'
import { buildTestQueryClient } from '../../../__utils__/query_client'
import { ChatProvider } from '../../../contexts/chat_context'
import { useConversationMessage } from '../../../hooks/use_conversation_message'
import type { MessageResource } from '../../../types/resources/message'
import type { PersonResource } from '../../../types/resources/person'
import { ReplyShadowMessage } from '../reply_shadow_message'
jest.mock('../../../hooks/use_conversation_message')
jest.mock('@react-navigation/native', () => ({
useNavigation: () => ({ navigate: jest.fn() }),
}))
const mockedUseConversationMessage = useConversationMessage as jest.MockedFunction<
typeof useConversationMessage
>
const author = { id: 1, type: 'Person', name: 'A', avatar: null } as unknown as PersonResource
const root = (text: string): MessageResource =>
({
type: 'Message',
id: 'rootA',
text,
html: '',
createdAt: '2026-01-01T00:00:00Z',
deletedAt: null,
textEditedAt: null,
mine: false,
attachments: [],
author,
reactionCounts: [],
replyCount: 1,
replyRootId: 'rootA',
messageType: 'message',
}) as MessageResource
let queryClient: QueryClient
const hookResult = (overrides: { message?: MessageResource; isError?: boolean }) =>
({ message: undefined, isError: false, isLoading: false, ...overrides }) as ReturnType<
typeof useConversationMessage
>
const Wrapper = ({ children }: { children: React.ReactNode }) => (
{},
theme: { theme: { colors: { interaction: 'rgb(0, 0, 255)' } } },
}}
>
{children}
)
const renderShadow = (replyRoot: MessageResource | null) =>
render(
,
{ wrapper: Wrapper }
)
beforeEach(() => {
queryClient = buildTestQueryClient()
mockedUseConversationMessage.mockReturnValue(hookResult({}))
})
afterEach(() => {
queryClient.clear()
jest.clearAllMocks()
})
describe('ReplyShadowMessage', () => {
it('renders the inline root without enabling the root fetch', () => {
const view = renderShadow(root('inline root'))
expect(view.getByText('inline root')).toBeTruthy()
expect(mockedUseConversationMessage).toHaveBeenCalledWith(
expect.objectContaining({ enabled: false })
)
})
it('falls back to fetching the root when none is inline', () => {
mockedUseConversationMessage.mockReturnValue(hookResult({ message: root('fetched root') }))
const view = renderShadow(null)
expect(view.getByText('fetched root')).toBeTruthy()
expect(mockedUseConversationMessage).toHaveBeenCalledWith(
expect.objectContaining({ messageId: 'rootA', enabled: true })
)
})
it('shows the deleted placeholder when the fallback fetch finds nothing', () => {
mockedUseConversationMessage.mockReturnValue(hookResult({ isError: true }))
const view = renderShadow(null)
expect(view.getByText('Message deleted')).toBeTruthy()
})
})