import React from 'react'; import { render, screen } from '@testing-library/react'; import { MCPUIResourceCarousel } from '../MCPUIResourceCarousel'; import { useMessageContext, useChatContext } from '~/Providers'; import { useGetMessagesByConvoId } from '~/data-provider'; // Mock dependencies jest.mock('~/Providers'); jest.mock('~/data-provider'); jest.mock('../../Chat/Messages/Content/UIResourceCarousel', () => ({ __esModule: true, default: ({ uiResources }: any) => (
{uiResources.map((resource: any, index: number) => (
))}
), })); const mockUseMessageContext = useMessageContext as jest.MockedFunction; const mockUseChatContext = useChatContext as jest.MockedFunction; const mockUseGetMessagesByConvoId = useGetMessagesByConvoId as jest.MockedFunction< typeof useGetMessagesByConvoId >; describe('MCPUIResourceCarousel', () => { beforeEach(() => { jest.clearAllMocks(); mockUseMessageContext.mockReturnValue({ messageId: 'msg123' } as any); mockUseChatContext.mockReturnValue({ conversation: { conversationId: 'conv123' }, } as any); }); describe('multiple resource fetching', () => { it('should fetch multiple resources by indices', () => { const mockMessages = [ { messageId: 'msg123', attachments: [ { type: 'ui_resources', ui_resources: [ { uri: 'ui://test/resource0', mimeType: 'text/html', text: '

Resource 0 content

', }, { uri: 'ui://test/resource1', mimeType: 'text/html', text: '

Resource 1 content

', }, { uri: 'ui://test/resource2', mimeType: 'text/html', text: '

Resource 2 content

', }, { uri: 'ui://test/resource3', mimeType: 'text/html', text: '

Resource 3 content

', }, ], }, ], }, ]; mockUseGetMessagesByConvoId.mockReturnValue({ data: mockMessages, } as any); render(); const carousel = screen.getByTestId('ui-resource-carousel'); expect(carousel).toBeInTheDocument(); expect(carousel).toHaveAttribute('data-resource-count', '3'); expect(screen.getByTestId('resource-0')).toHaveAttribute( 'data-resource-uri', 'ui://test/resource0', ); expect(screen.getByTestId('resource-1')).toHaveAttribute( 'data-resource-uri', 'ui://test/resource2', ); expect(screen.getByTestId('resource-2')).toHaveAttribute( 'data-resource-uri', 'ui://test/resource3', ); expect(screen.queryByTestId('resource-3')).not.toBeInTheDocument(); }); it('should preserve resource order based on indices', () => { const mockMessages = [ { messageId: 'msg123', attachments: [ { type: 'ui_resources', ui_resources: [ { uri: 'ui://test/resource0', mimeType: 'text/html', text: '

Resource 0 content

', }, { uri: 'ui://test/resource1', mimeType: 'text/html', text: '

Resource 1 content

', }, { uri: 'ui://test/resource2', mimeType: 'text/html', text: '

Resource 2 content

', }, ], }, ], }, ]; mockUseGetMessagesByConvoId.mockReturnValue({ data: mockMessages, } as any); render(); const resources = screen.getAllByTestId(/resource-\d/); expect(resources[0]).toHaveAttribute('data-resource-uri', 'ui://test/resource2'); expect(resources[1]).toHaveAttribute('data-resource-uri', 'ui://test/resource0'); expect(resources[2]).toHaveAttribute('data-resource-uri', 'ui://test/resource1'); }); }); describe('partial matches', () => { it('should only include valid resource indices', () => { const mockMessages = [ { messageId: 'msg123', attachments: [ { type: 'ui_resources', ui_resources: [ { uri: 'ui://test/resource0', mimeType: 'text/html', text: '

Resource 0 content

', }, { uri: 'ui://test/resource1', mimeType: 'text/html', text: '

Resource 1 content

', }, ], }, ], }, ]; mockUseGetMessagesByConvoId.mockReturnValue({ data: mockMessages, } as any); // Request indices 0, 1, 2, 3 but only 0 and 1 exist render(); const carousel = screen.getByTestId('ui-resource-carousel'); expect(carousel).toHaveAttribute('data-resource-count', '2'); expect(screen.getByTestId('resource-0')).toHaveAttribute( 'data-resource-uri', 'ui://test/resource0', ); expect(screen.getByTestId('resource-1')).toHaveAttribute( 'data-resource-uri', 'ui://test/resource1', ); }); it('should handle all invalid indices', () => { const mockMessages = [ { messageId: 'msg123', attachments: [ { type: 'ui_resources', ui_resources: [ { uri: 'ui://test/resource0', mimeType: 'text/html', text: '

Resource 0 content

', }, { uri: 'ui://test/resource1', mimeType: 'text/html', text: '

Resource 1 content

', }, ], }, ], }, ]; mockUseGetMessagesByConvoId.mockReturnValue({ data: mockMessages, } as any); // Request indices that don't exist render(); expect(screen.queryByTestId('ui-resource-carousel')).not.toBeInTheDocument(); }); }); describe('error handling', () => { it('should return null when no attachments', () => { const mockMessages = [ { messageId: 'msg123', attachments: undefined, }, ]; mockUseGetMessagesByConvoId.mockReturnValue({ data: mockMessages, } as any); const { container } = render( , ); expect(container.firstChild).toBeNull(); expect(screen.queryByTestId('ui-resource-carousel')).not.toBeInTheDocument(); }); it('should return null when message not found', () => { const mockMessages = [ { messageId: 'different-msg', attachments: [ { type: 'ui_resources', ui_resources: [ { uri: 'ui://test/resource', mimeType: 'text/html', text: '

Resource content

', }, ], }, ], }, ]; mockUseGetMessagesByConvoId.mockReturnValue({ data: mockMessages, } as any); const { container } = render( , ); expect(container.firstChild).toBeNull(); }); it('should return null when no ui_resources attachments', () => { const mockMessages = [ { messageId: 'msg123', attachments: [ { type: 'web_search', web_search: { results: [] }, }, ], }, ]; mockUseGetMessagesByConvoId.mockReturnValue({ data: mockMessages, } as any); const { container } = render( , ); expect(container.firstChild).toBeNull(); }); }); describe('edge cases', () => { it('should handle empty resourceIndices array', () => { const mockMessages = [ { messageId: 'msg123', attachments: [ { type: 'ui_resources', ui_resources: [ { uri: 'ui://test/resource', mimeType: 'text/html', text: '

Resource content

', }, ], }, ], }, ]; mockUseGetMessagesByConvoId.mockReturnValue({ data: mockMessages, } as any); const { container } = render( , ); expect(container.firstChild).toBeNull(); }); it('should handle duplicate indices', () => { const mockMessages = [ { messageId: 'msg123', attachments: [ { type: 'ui_resources', ui_resources: [ { uri: 'ui://test/resource0', mimeType: 'text/html', text: '

Resource 0 content

', }, { uri: 'ui://test/resource1', mimeType: 'text/html', text: '

Resource 1 content

', }, ], }, ], }, ]; mockUseGetMessagesByConvoId.mockReturnValue({ data: mockMessages, } as any); // Request same index multiple times render(); // Should render each resource multiple times const carousel = screen.getByTestId('ui-resource-carousel'); expect(carousel).toHaveAttribute('data-resource-count', '5'); const resources = screen.getAllByTestId(/resource-\d/); expect(resources).toHaveLength(5); expect(resources[0]).toHaveAttribute('data-resource-uri', 'ui://test/resource0'); expect(resources[1]).toHaveAttribute('data-resource-uri', 'ui://test/resource0'); expect(resources[2]).toHaveAttribute('data-resource-uri', 'ui://test/resource1'); expect(resources[3]).toHaveAttribute('data-resource-uri', 'ui://test/resource1'); expect(resources[4]).toHaveAttribute('data-resource-uri', 'ui://test/resource0'); }); it('should handle multiple ui_resources attachments', () => { const mockMessages = [ { messageId: 'msg123', attachments: [ { type: 'ui_resources', ui_resources: [ { uri: 'ui://test/resource0', mimeType: 'text/html', text: '

Resource 0 content

', }, { uri: 'ui://test/resource1', mimeType: 'text/html', text: '

Resource 1 content

', }, ], }, { type: 'ui_resources', ui_resources: [ { uri: 'ui://test/resource2', mimeType: 'text/html', text: '

Resource 2

' }, { uri: 'ui://test/resource3', mimeType: 'text/html', text: '

Resource 3

' }, ], }, ], }, ]; mockUseGetMessagesByConvoId.mockReturnValue({ data: mockMessages, } as any); // Resources from both attachments should be accessible render(); const carousel = screen.getByTestId('ui-resource-carousel'); expect(carousel).toHaveAttribute('data-resource-count', '3'); // Note: indices 2 and 3 are from the second attachment and become accessible in the flattened array expect(screen.getByTestId('resource-0')).toHaveAttribute( 'data-resource-uri', 'ui://test/resource0', ); expect(screen.getByTestId('resource-1')).toHaveAttribute( 'data-resource-uri', 'ui://test/resource2', ); expect(screen.getByTestId('resource-2')).toHaveAttribute( 'data-resource-uri', 'ui://test/resource3', ); }); it('should handle null messages data', () => { mockUseGetMessagesByConvoId.mockReturnValue({ data: null, } as any); const { container } = render( , ); expect(container.firstChild).toBeNull(); }); it('should handle missing conversation', () => { mockUseChatContext.mockReturnValue({ conversation: null, } as any); mockUseGetMessagesByConvoId.mockReturnValue({ data: null, } as any); const { container } = render( , ); expect(container.firstChild).toBeNull(); }); }); });