import * as React from 'react'; import { createElement } from 'react'; import { createRoot, type Root } from 'react-dom/client'; import { MemoryRouter } from 'react-router-dom'; import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import { useFeedStateString } from '../../../../hooks/use-state-string'; import PopularThreadsBox from '../popular-threads-box'; (globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true; const act = (React as { act?: (cb: () => void | Promise) => void | Promise }).act as (cb: () => void | Promise) => void | Promise; const testState = vi.hoisted(() => ({ communities: [] as unknown[], feedStateString: 'Downloading boards', isLoading: false, requestedCommunityIdentifiers: [] as string[][], requestedCommunities: [] as unknown[][], revealedPopularPosts: undefined as | Array<{ cid: string; communityAddress: string; content: string; link: string; thumbnailUrl: string; title: string; }> | undefined, popularPosts: [] as Array<{ cid: string; communityAddress: string; content: string; link: string; thumbnailUrl: string; title: string; }>, })); vi.mock('react-i18next', () => ({ useTranslation: () => ({ t: (key: string) => key, }), })); vi.mock('@bitsocialnet/bitsocial-react-hooks', () => ({ useCommunities: ({ communities }: { communities: unknown[] }) => { testState.requestedCommunities.push(communities); return { communities: testState.communities }; }, })); vi.mock('../../../../hooks/use-community-identifiers', () => ({ useCommunityIdentifiers: (addresses?: string[]) => { testState.requestedCommunityIdentifiers.push(addresses || []); return addresses || []; }, })); vi.mock('../../../../hooks/use-state-string', () => ({ useFeedStateString: vi.fn(() => testState.feedStateString), })); vi.mock('../../../../hooks/use-popular-posts', () => ({ getRevealedPopularPosts: vi.fn(() => testState.revealedPopularPosts), default: vi.fn(() => ({ error: null, isLoading: testState.isLoading, popularPosts: testState.popularPosts, })), })); vi.mock('../../../../components/catalog-row', () => ({ CatalogPostMedia: ({ cid }: { cid: string }) => createElement('div', { 'data-testid': 'popular-thread-media' }, cid), })); vi.mock('../../box-modal', () => ({ default: () => createElement('button', { 'aria-label': 'filters' }), })); const directories = [ { address: 'music-posting.eth', title: '/mu/ - Music' }, { address: 'tech-posting.eth', title: '/g/ - Technology' }, ]; let container: HTMLDivElement; let root: Root; const renderPopularThreadsBox = () => { act(() => { root.render(createElement(MemoryRouter, {}, createElement(PopularThreadsBox, { directories, directoryAddresses: directories.map((entry) => entry.address) }))); }); }; describe('PopularThreadsBox', () => { beforeEach(() => { vi.clearAllMocks(); testState.communities = directories.map((entry) => ({ address: entry.address })); testState.feedStateString = 'Downloading boards'; testState.isLoading = false; testState.requestedCommunityIdentifiers = []; testState.requestedCommunities = []; testState.revealedPopularPosts = undefined; testState.popularPosts = [ { cid: 'thread-1', communityAddress: 'music-posting.eth', content: 'thread content', link: 'https://cdn.example/thread-1.jpg', thumbnailUrl: 'https://cdn.example/thread-1-thumb.jpg', title: 'thread title', }, ]; container = document.createElement('div'); document.body.appendChild(container); root = createRoot(container); }); afterEach(() => { act(() => root.unmount()); container.remove(); }); it('does not subscribe to feed state once popular threads are visible', () => { renderPopularThreadsBox(); expect(container.textContent).toContain('Music'); expect(container.textContent).toContain('thread title'); expect(vi.mocked(useFeedStateString)).not.toHaveBeenCalled(); }); it('does not subscribe to board communities once the popular posts cache is revealed', () => { testState.revealedPopularPosts = testState.popularPosts; renderPopularThreadsBox(); expect(testState.requestedCommunityIdentifiers).toEqual([[]]); expect(testState.requestedCommunities).toEqual([[]]); expect(container.textContent).toContain('thread title'); }); it('subscribes to feed state only while popular threads are loading', () => { testState.isLoading = true; testState.popularPosts = []; renderPopularThreadsBox(); expect(container.textContent).toContain('Downloading boards'); expect(vi.mocked(useFeedStateString)).toHaveBeenCalledWith(['music-posting.eth', 'tech-posting.eth']); }); });