import React from 'react'
import { useChannelStateContext, useMessageContext } from 'stream-chat-react'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { renderWithProviders, screen } from '../../test/utils'
import { OutboundContext } from './OutboundContext'
import { isTipMessage } from './TipMessage'
import { CustomMessage } from './index'
vi.mock('stream-chat-react', () => ({
Attachment: () => null,
EditMessageModal: () => null,
MessageBounceModal: () => null,
MessageBouncePrompt: () => null,
MessageBlocked: () => null,
MessageDeleted: () => null,
MessageErrorIcon: () => null,
MessageIsThreadReplyInChannelButtonIndicator: () => null,
MessageRepliesCountButton: () => null,
MessageStatus: ({
MessageSentStatus,
}: {
MessageSentStatus: React.ComponentType
}) => ,
MessageText: () => Message,
Poll: () => null,
ReminderNotification: () => null,
StreamedMessageText: () => null,
areMessageUIPropsEqual: () => true,
isDateSeparatorMessage: () => false,
isMessageBlocked: () => false,
isMessageBounced: () => false,
messageHasAttachments: () => false,
messageHasReactions: () => false,
useChannelStateContext: vi.fn(),
useChatContext: () => ({ client: { polls: { fromState: vi.fn() } } }),
useComponentContext: () => ({
Attachment: () => null,
MessageRepliesCountButton: () => null,
}),
useMessageContext: vi.fn(),
useMessageReminder: () => undefined,
}))
vi.mock('./context', () => ({
useCustomMessage: () => ({
isUnlocking: () => false,
}),
}))
vi.mock('../Avatar', () => ({
Avatar: () => null,
}))
vi.mock('./MessageTag', () => ({
MessageTag: () => null,
isAttachmentMessage: () => false,
isChatbotMessage: () => false,
isMediaAttachmentMessage: () => false,
isPaidMessage: () => false,
isTextAttachmentMessage: () => false,
hasPaidDeliveryTag: () => false,
}))
vi.mock('./TipMessage', () => ({
TipMessage: () => null,
isTipMessage: vi.fn(() => false),
}))
vi.mock('./LockedAttachment', () => ({
default: () => null,
}))
vi.mock('./StreamAttachmentMessage', () => ({
default: () => null,
buildOrderedAttachmentSegments: () => [],
}))
vi.mock('../MediaMessage', () => ({
isLinkAttachment: () => false,
}))
const mockedUseChannelStateContext = vi.mocked(useChannelStateContext)
const mockedUseMessageContext = vi.mocked(useMessageContext)
const mockedIsTipMessage = vi.mocked(isTipMessage)
describe('CustomMessage', () => {
beforeEach(() => {
mockedIsTipMessage.mockReturnValue(false)
mockedUseChannelStateContext.mockReturnValue({
messages: [{ id: 'message-1', user: { id: 'me' } }],
} as never)
mockedUseMessageContext.mockReturnValue({
message: {
id: 'message-1',
text: 'Hello',
type: 'regular',
status: 'received',
user: { id: 'me', name: 'Me' },
metadata: {
outbound_id: 'outbound-1',
},
},
isMyMessage: () => true,
threadList: false,
editing: false,
endOfGroup: true,
firstOfGroup: true,
groupedByUser: true,
handleAction: vi.fn(),
handleOpenThread: vi.fn(),
handleRetry: vi.fn(),
highlighted: false,
renderText: undefined,
isMessageAIGenerated: undefined,
} as never)
})
it('uses the latest outbound click handler after rerendering', () => {
const firstHandler = vi.fn()
const secondHandler = vi.fn()
const { rerender } = renderWithProviders(
)
rerender(
)
screen
.getByRole('button', {
name: 'View broadcast July 9th Class attendees',
})
.click()
expect(firstHandler).not.toHaveBeenCalled()
expect(secondHandler).toHaveBeenCalledWith({
id: 'automation-1',
name: 'July 9th Class attendees',
})
})
it('renders the current source returned for the outbound id', () => {
renderWithProviders(
)
expect(
screen.getByTestId('sent-message-outbound-status')
).toHaveTextContent('July 9th Class absentee')
})
it('hides the label when the outbound record cannot be resolved', () => {
renderWithProviders(
)
expect(
screen.queryByTestId('sent-message-outbound-status')
).not.toBeInTheDocument()
})
it('renders an outbound source when its lookup later resolves', () => {
const { rerender } = renderWithProviders(
)
rerender(
)
expect(
screen.getByTestId('sent-message-outbound-status')
).toHaveTextContent('July 9th Class absentee')
})
it('does not render an accompanying text bubble for a whitespace-only tip message', () => {
mockedIsTipMessage.mockReturnValue(true)
mockedUseMessageContext.mockReturnValue({
message: {
id: 'message-1',
text: ' \n ',
type: 'regular',
status: 'received',
user: { id: 'me', name: 'Me' },
metadata: {},
},
isMyMessage: () => true,
threadList: false,
editing: false,
endOfGroup: true,
firstOfGroup: true,
groupedByUser: true,
handleAction: vi.fn(),
handleOpenThread: vi.fn(),
handleRetry: vi.fn(),
highlighted: false,
renderText: undefined,
isMessageAIGenerated: undefined,
} as never)
renderWithProviders(
)
expect(screen.queryByText('Message')).not.toBeInTheDocument()
})
it('renders an accompanying text bubble for a tip message with real text', () => {
mockedIsTipMessage.mockReturnValue(true)
// Default mocked message.text ('Hello') from beforeEach.
renderWithProviders(
)
expect(screen.getByText('Message')).toBeInTheDocument()
})
})