import React from 'react'; import { render, screen, fireEvent, waitFor } from '@testing-library/react'; import { BrowserRouter } from 'react-router-dom'; import { AuthContext } from '../../context/AuthContext'; import { SocketContext } from '../../context/SocketContext'; import SocialFeed from '../SocialFeed'; import axios from 'axios'; // Mock the contexts const mockAuthContext = { auth: { isAuthenticated: true, loading: false, user: { id: 'user123', name: 'Test User' } }, login: jest.fn(), logout: jest.fn(), }; const mockSocketContext = { socket: null, connected: true, on: jest.fn(), off: jest.fn(), }; // Mock axios jest.mock('axios'); describe('SocialFeed Component', () => { const mockPosts = [ { _id: 'post1', content: 'Just cleaned up Main Street! ๐Ÿงน', type: 'text', user: { userId: 'user123', name: 'Test User', profilePicture: 'avatar.jpg' }, likes: [], likesCount: 0, comments: [], commentsCount: 0, createdAt: '2023-01-01T00:00:00.000Z', }, { _id: 'post2', content: 'Beautiful sunset on Oak Street ๐ŸŒ…', type: 'image', imageUrl: 'https://example.com/sunset.jpg', cloudinaryPublicId: 'sunset_123', user: { userId: 'user456', name: 'Other User', profilePicture: 'avatar2.jpg' }, likes: ['user123', 'user789'], likesCount: 2, comments: [ { _id: 'comment1', content: 'Great work!', user: { userId: 'user789', name: 'Another User' }, createdAt: '2023-01-01T01:00:00.000Z', } ], commentsCount: 1, createdAt: '2023-01-01T12:00:00.000Z', }, ]; beforeEach(() => { jest.clearAllMocks(); // Mock axios.get to return posts axios.get.mockResolvedValue({ data: mockPosts }); // Mock axios.post for creating posts axios.post.mockResolvedValue({ data: { ...mockPosts[0], _id: 'post3' } }); // Mock axios.put for liking posts axios.put.mockResolvedValue({ data: { ...mockPosts[0], likes: ['user123'], likesCount: 1 } }); }); const renderSocialFeed = () => { return render( ); }; it('renders social feed correctly', async () => { renderSocialFeed(); await waitFor(() => { expect(screen.getByText('Just cleaned up Main Street! ๐Ÿงน')).toBeInTheDocument(); expect(screen.getByText('Beautiful sunset on Oak Street ๐ŸŒ…')).toBeInTheDocument(); }); }); it('shows loading state initially', () => { // Mock axios to delay response axios.get.mockImplementation(() => new Promise(resolve => setTimeout(() => resolve({ data: [] }), 100))); renderSocialFeed(); expect(screen.getByText('Loading posts...')).toBeInTheDocument(); }); it('displays user information for posts', async () => { renderSocialFeed(); await waitFor(() => { expect(screen.getByText('Test User')).toBeInTheDocument(); expect(screen.getByText('Other User')).toBeInTheDocument(); }); }); it('displays post timestamps', async () => { renderSocialFeed(); await waitFor(() => { expect(screen.getByText(/Jan 1, 2023/)).toBeInTheDocument(); }); }); it('handles post creation', async () => { renderSocialFeed(); await waitFor(() => { const createButton = screen.getByText('Create Post'); const contentInput = screen.getByPlaceholderText('What\'s on your mind?'); expect(createButton).toBeInTheDocument(); expect(contentInput).toBeInTheDocument(); }); }); it('creates new post successfully', async () => { renderSocialFeed(); await waitFor(() => { const createButton = screen.getByText('Create Post'); const contentInput = screen.getByPlaceholderText('What\'s on your mind?'); fireEvent.change(contentInput, { target: { value: 'New test post' } }); fireEvent.click(createButton); expect(axios.post).toHaveBeenCalledWith('/api/posts', { content: 'New test post' }); }); }); it('validates post creation form', async () => { renderSocialFeed(); await waitFor(() => { const createButton = screen.getByText('Create Post'); // Try to create post without content fireEvent.click(createButton); expect(screen.getByText('Content is required')).toBeInTheDocument(); }); }); it('handles post liking', async () => { renderSocialFeed(); await waitFor(() => { const likeButtons = screen.getAllByLabelText('Like'); const firstLikeButton = likeButtons[0]; expect(firstLikeButton).toBeInTheDocument(); // Click like button fireEvent.click(firstLikeButton); expect(axios.put).toHaveBeenCalledWith('/api/posts/post1/like'); }); }); it('updates like count correctly', async () => { renderSocialFeed(); await waitFor(() => { // Initial like count should be 2 expect(screen.getByText('2 likes')).toBeInTheDocument(); }); }); it('displays comments correctly', async () => { renderSocialFeed(); await waitFor(() => { expect(screen.getByText('Great work!')).toBeInTheDocument(); expect(screen.getByText('Another User')).toBeInTheDocument(); }); }); it('shows comment count', async () => { renderSocialFeed(); await waitFor(() => { expect(screen.getByText('1 comment')).toBeInTheDocument(); expect(screen.getByText('0 comments')).toBeInTheDocument(); }); }); it('handles comment submission', async () => { renderSocialFeed(); await waitFor(() => { const commentInput = screen.getByPlaceholderText('Add a comment...'); const submitButton = screen.getByText('Post Comment'); expect(commentInput).toBeInTheDocument(); expect(submitButton).toBeInTheDocument(); }); }); it('submits comment successfully', async () => { // Mock axios.post for comment creation axios.post.mockResolvedValue({ data: { _id: 'comment2', content: 'Test comment' } }); renderSocialFeed(); await waitFor(() => { const commentInput = screen.getByPlaceholderText('Add a comment...'); const submitButton = screen.getByText('Post Comment'); fireEvent.change(commentInput, { target: { value: 'Test comment' } }); fireEvent.click(submitButton); expect(axios.post).toHaveBeenCalledWith('/api/posts/post1/comments', { content: 'Test comment' }); }); }); it('displays image posts correctly', async () => { renderSocialFeed(); await waitFor(() => { const postImages = screen.getAllByAltText('Post image'); expect(postImages.length).toBeGreaterThan(0); }); }); it('shows error message when API fails', async () => { // Mock axios.get to throw error axios.get.mockRejectedValue(new Error('Network error')); renderSocialFeed(); await waitFor(() => { expect(screen.getByText(/Failed to load posts/)).toBeInTheDocument(); }); }); it('displays empty state when no posts', async () => { // Mock empty response axios.get.mockResolvedValue({ data: [] }); renderSocialFeed(); await waitFor(() => { expect(screen.getByText('No posts yet. Be the first to share!')).toBeInTheDocument(); }); }); it('handles real-time updates', async () => { const { on } = mockSocketContext; renderSocialFeed(); await waitFor(() => { // Simulate receiving a new post via socket const socketCallback = on.mock.calls[0][1]; const newPostData = { type: 'new_post', data: { ...mockPosts[0], _id: 'post3', content: 'New real-time post!' } }; socketCallback(newPostData); // Verify the new post appears in the feed expect(screen.getByText('New real-time post!')).toBeInTheDocument(); }); }); it('filters posts by type', async () => { renderSocialFeed(); await waitFor(() => { // Look for filter buttons const filterButtons = screen.getAllByRole('button'); const allFilter = filterButtons.find(btn => btn.textContent.includes('All')); const textFilter = filterButtons.find(btn => btn.textContent.includes('Text')); const imageFilter = filterButtons.find(btn => btn.textContent.includes('Images')); expect(allFilter).toBeInTheDocument(); expect(textFilter).toBeInTheDocument(); expect(imageFilter).toBeInTheDocument(); }); }); it('searches posts', async () => { renderSocialFeed(); await waitFor(() => { const searchInput = screen.getByPlaceholderText('Search posts...'); expect(searchInput).toBeInTheDocument(); // Test search functionality fireEvent.change(searchInput, { target: { value: 'cleaned' } }); // Should filter posts to show only relevant content expect(screen.getByText('Just cleaned up Main Street! ๐Ÿงน')).toBeInTheDocument(); }); }); it('shows post engagement statistics', async () => { renderSocialFeed(); await waitFor(() => { // Look for engagement stats expect(screen.getByText('Total Posts: 2')).toBeInTheDocument(); expect(screen.getByText('Total Likes: 2')).toBeInTheDocument(); expect(screen.getByText('Total Comments: 1')).toBeInTheDocument(); }); }); it('handles infinite scroll', async () => { renderSocialFeed(); await waitFor(() => { // Look for load more indicator expect(screen.getByText('Load more posts')).toBeInTheDocument(); }); }); it('displays user avatars', async () => { renderSocialFeed(); await waitFor(() => { const avatars = screen.getAllByAltText('User avatar'); expect(avatars.length).toBeGreaterThan(0); }); }); });