diff options
| author | Adam Mathes <adam@adammathes.com> | 2026-02-13 11:45:02 -0800 |
|---|---|---|
| committer | Adam Mathes <adam@adammathes.com> | 2026-02-13 11:45:02 -0800 |
| commit | f8fcc0be57fa7f471ffd22d4b9559cb6d0ff20bf (patch) | |
| tree | ca2d51b24b0908e1c857618f114ce6fa5593041f /frontend/src/components/FeedItems.test.tsx | |
| parent | fc2bc854f4e3bae3503d5000f1fbc414bfa7e0cc (diff) | |
| download | neko-f8fcc0be57fa7f471ffd22d4b9559cb6d0ff20bf.tar.gz neko-f8fcc0be57fa7f471ffd22d4b9559cb6d0ff20bf.tar.bz2 neko-f8fcc0be57fa7f471ffd22d4b9559cb6d0ff20bf.zip | |
Implement infinite scroll for feed items view (NK-5ocxgm)
Diffstat (limited to 'frontend/src/components/FeedItems.test.tsx')
| -rw-r--r-- | frontend/src/components/FeedItems.test.tsx | 55 |
1 files changed, 53 insertions, 2 deletions
diff --git a/frontend/src/components/FeedItems.test.tsx b/frontend/src/components/FeedItems.test.tsx index 00118fa..ea68a7c 100644 --- a/frontend/src/components/FeedItems.test.tsx +++ b/frontend/src/components/FeedItems.test.tsx @@ -53,8 +53,6 @@ describe('FeedItems Component', () => { await waitFor(() => { expect(screen.getByText('Item One')).toBeInTheDocument(); - // Title should now be "Feed Items" based on logic - expect(screen.getByText('Feed Items')).toBeInTheDocument(); }); const params = new URLSearchParams(); @@ -171,4 +169,57 @@ describe('FeedItems Component', () => { })); }); }); + + it('loads more items when sentinel becomes visible', async () => { + const initialItems = [{ _id: 101, title: 'Item 1', url: 'u1', read: true, starred: false }]; + const moreItems = [{ _id: 100, title: 'Item 0', url: 'u0', read: true, starred: false }]; + + (global.fetch as any) + .mockResolvedValueOnce({ ok: true, json: async () => initialItems }) + .mockResolvedValueOnce({ ok: true, json: async () => moreItems }); + + let observerCallback: IntersectionObserverCallback = () => { }; + class MockIntersectionObserver { + constructor(callback: IntersectionObserverCallback) { + observerCallback = callback; + } + observe = vi.fn(); + unobserve = vi.fn(); + disconnect = vi.fn(); + } + window.IntersectionObserver = MockIntersectionObserver as any; + + render( + <MemoryRouter> + <FeedItems /> + </MemoryRouter> + ); + + await waitFor(() => { + expect(screen.getByText('Item 1')).toBeInTheDocument(); + }); + + // Simulate sentinel becoming visible + const entry = { + isIntersecting: true, + target: { id: 'load-more-sentinel' } as unknown as Element, + boundingClientRect: {} as DOMRectReadOnly, + intersectionRatio: 1, + time: 0, + rootBounds: null, + intersectionRect: {} as DOMRectReadOnly, + } as IntersectionObserverEntry; + + act(() => { + observerCallback([entry], {} as IntersectionObserver); + }); + + await waitFor(() => { + expect(screen.getByText('Item 0')).toBeInTheDocument(); + const params = new URLSearchParams(); + params.append('max_id', '101'); + params.append('read_filter', 'unread'); + expect(global.fetch).toHaveBeenCalledWith(`/api/stream?${params.toString()}`); + }); + }); }); |
