import React from 'react' import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' import { act, cleanup, render, screen, waitFor } from '@testing-library/react' import axios from 'axios' import ArtworkComments from './ArtworkComments' vi.mock('axios', () => ({ default: { get: vi.fn() } })) vi.mock('../comments/CommentForm', () => ({ default: () =>
})) vi.mock('../comments/ReactionBar', () => ({ default: () =>
})) vi.mock('../xp/LevelBadge', () => ({ default: () => null })) vi.mock('../../utils/emojiFlood', () => ({ isFlood: () => false })) describe('ArtworkComments deferred loading', () => { let observerCallback beforeEach(() => { axios.get.mockResolvedValue({ data: { data: [{ id: 1, content: 'Loaded comment', replies: [], user: {}, reactions: {} }], meta: { current_page: 1, last_page: 1, total: 1 }, }, }) window.IntersectionObserver = vi.fn((callback) => { observerCallback = callback return { observe: vi.fn(), disconnect: vi.fn() } }) }) afterEach(() => { cleanup() vi.restoreAllMocks() delete window.IntersectionObserver }) it('does not fetch until the comments section approaches the viewport', async () => { render() await new Promise((resolve) => setTimeout(resolve, 20)) expect(axios.get).not.toHaveBeenCalled() await act(async () => observerCallback([{ isIntersecting: true }])) await waitFor(() => expect(axios.get).toHaveBeenCalledTimes(1)) expect(axios.get).toHaveBeenCalledWith( '/api/artworks/9357/comments?page=1', expect.objectContaining({ signal: expect.any(AbortSignal) }), ) expect(screen.getByText('Loaded comment')).not.toBeNull() }) it('uses the delayed compatibility fallback when IntersectionObserver is unavailable', async () => { delete window.IntersectionObserver vi.useFakeTimers() render() expect(axios.get).not.toHaveBeenCalled() await act(async () => vi.advanceTimersByTime(1200)) expect(axios.get).toHaveBeenCalledTimes(1) vi.useRealTimers() }) it('resets on artwork changes and ignores stale responses', async () => { let resolveRequest axios.get.mockImplementation(() => new Promise((resolve) => { resolveRequest = resolve })) const { rerender } = render() await act(async () => observerCallback([{ isIntersecting: true }])) await waitFor(() => expect(axios.get).toHaveBeenCalledTimes(1)) rerender() await act(async () => { resolveRequest({ data: { data: [{ id: 1, content: 'stale', replies: [], user: {}, reactions: {} }], meta: {} } }) await Promise.resolve() }) expect(screen.queryByText('stale')).toBeNull() }) })