import React from 'react'; import { render, waitFor } from '@testing-library/react'; import '@testing-library/jest-dom'; import { AlgoliaSearchProvider, useAlgoliaSearch } from '../AlgoliaSearchProvider'; jest.mock('algoliasearch', () => { return jest.fn(() => ({ initIndex: jest.fn() })); }); jest.mock('../algoliaRelatedArticles', () => ({ searchRelatedArticles: jest.fn() })); import algoliasearch from 'algoliasearch'; import { searchRelatedArticles } from '../algoliaRelatedArticles'; const mockAlgoliasearch = algoliasearch as jest.MockedFunction< typeof algoliasearch >; const mockSearchRelatedArticles = searchRelatedArticles as jest.MockedFunction< typeof searchRelatedArticles >; const TestComponent: React.FC = () => { const { getRelatedArticles } = useAlgoliaSearch(); React.useEffect( () => { if (getRelatedArticles) { getRelatedArticles(); } }, [getRelatedArticles] ); return
Test Component
; }; const mockAnalyticsStream = jest.fn(); const mockAlgoliaSearchKeys = { applicationId: 'test-app-id', apiKey: 'test-api-key', indexName: 'test-index' }; const mockArticle = { id: 'test-article-123', label: 'Test Article Label', headline: 'Test Article Headline', section: 'news', topics: [{ name: 'Technology' }], bylines: [] }; describe('AlgoliaSearchProvider', () => { let mockIndex: any; beforeEach(() => { jest.clearAllMocks(); mockIndex = { search: jest.fn() }; mockAlgoliasearch.mockReturnValue({ initIndex: jest.fn().mockReturnValue(mockIndex) } as any); }); describe('Provider functionality', () => { it('should render children correctly', () => { const { getByTestId } = render(
Child Content
); expect(getByTestId('child-component')).toBeInTheDocument(); }); it('should create algolia index with correct parameters', () => { render(
Content
); expect(mockAlgoliasearch).toHaveBeenCalledWith( 'test-app-id', 'test-api-key' ); expect( mockAlgoliasearch('test-app-id', 'test-api-key').initIndex ).toHaveBeenCalledWith('test-index'); }); it('should handle null algoliaSearchKeys', () => { render(
Content
); expect(mockAlgoliasearch).not.toHaveBeenCalled(); }); it('should recreate index when algoliaSearchKeys change', () => { const { rerender } = render(
Content
); expect(mockAlgoliasearch).toHaveBeenCalledTimes(1); const newKeys = { ...mockAlgoliaSearchKeys, applicationId: 'new-app-id' }; rerender(
Content
); expect(mockAlgoliasearch).toHaveBeenCalledTimes(2); expect(mockAlgoliasearch).toHaveBeenLastCalledWith( 'new-app-id', 'test-api-key' ); }); }); describe('getRelatedArticles functionality', () => { it('should call searchRelatedArticles with correct parameters when index and article exist', async () => { const mockResults = { query: 'test query', sliceName: 'test slice', items: [], count: 5 }; mockSearchRelatedArticles.mockResolvedValue(mockResults); render( ); await waitFor(() => { expect(mockSearchRelatedArticles).toHaveBeenCalledWith( mockIndex, mockArticle, mockAnalyticsStream ); }); }); it('should return null when no index is available', async () => { let resultFromHook: any; const TestComponentWithResult: React.FC = () => { const { getRelatedArticles } = useAlgoliaSearch(); React.useEffect( () => { const fetchResults = async () => { if (getRelatedArticles) { resultFromHook = await getRelatedArticles(); } }; fetchResults(); }, [getRelatedArticles] ); return
Test
; }; render( ); await waitFor(() => { expect(resultFromHook).toBeNull(); }); expect(mockSearchRelatedArticles).not.toHaveBeenCalled(); }); it('should return null when no article is provided', async () => { let resultFromHook: any; const TestComponentWithResult: React.FC = () => { const { getRelatedArticles } = useAlgoliaSearch(); React.useEffect( () => { const fetchResults = async () => { if (getRelatedArticles) { resultFromHook = await getRelatedArticles(); } }; fetchResults(); }, [getRelatedArticles] ); return
Test
; }; render( ); await waitFor(() => { expect(resultFromHook).toBeNull(); }); expect(mockSearchRelatedArticles).not.toHaveBeenCalled(); }); it('should return results from searchRelatedArticles', async () => { const mockResults = { query: 'test query', sliceName: 'test slice', items: [{ id: 1 }, { id: 2 }, { id: 3 }], count: 3 }; mockSearchRelatedArticles.mockResolvedValue(mockResults); let resultFromHook: any; const TestComponentWithResult: React.FC = () => { const { getRelatedArticles } = useAlgoliaSearch(); React.useEffect( () => { const fetchResults = async () => { if (getRelatedArticles) { resultFromHook = await getRelatedArticles(); } }; fetchResults(); }, [getRelatedArticles] ); return
Test
; }; render( ); await waitFor(() => { expect(resultFromHook).toEqual(mockResults); }); }); it('should memoize getRelatedArticles callback based on dependencies', () => { let firstCallback: any; let secondCallback: any; const CallbackCapture: React.FC = () => { const { getRelatedArticles } = useAlgoliaSearch(); if (!firstCallback) { firstCallback = getRelatedArticles; } else if (!secondCallback) { secondCallback = getRelatedArticles; } return
Test
; }; const { rerender } = render( ); rerender( ); expect(firstCallback).toBe(secondCallback); }); }); describe('useAlgoliaSearch hook', () => { it('should provide context value when used within provider', () => { let contextValue: any; const TestComponentInsideProvider: React.FC = () => { contextValue = useAlgoliaSearch(); return
Test
; }; render( ); expect(contextValue).toHaveProperty('getRelatedArticles'); expect(typeof contextValue.getRelatedArticles).toBe('function'); }); }); });