inbox-section.test.tsx3.7 KBView on GitHub import React from 'react';
import { act, fireEvent, render } from '@testing-library/react';
import { MemoryRouter } from 'react-router';
import { InboxSection } from '@/modules/threads/components/inbox-section';
const inbox = {
id: 'important',
name: 'Important',
position: 0,
system: true,
rule: { kind: 'all' } as const,
};
const mockPage1 = Array.from({ length: 25 }, (_, i) => ({
id: `t-mockPage1-${i}`,
$raw: { latestReceivedOn: '2026-05-24T00:00:00Z', subject: `mockPage1-${i}` },
}));
const mockPage2 = Array.from({ length: 25 }, (_, i) => ({
id: `t-mockPage2-${i}`,
$raw: { latestReceivedOn: '2026-05-24T00:00:00Z', subject: `mockPage2-${i}` },
}));
const mockFetchNextPage = jest.fn().mockResolvedValue(undefined);
const mockToggleInboxCollapsed = jest.fn();
let mockCollapsedState: Record<string, boolean> = {};
jest.mock('@/modules/threads/threadList/hooks/use-inbox-threads', () => ({
useInboxThreads: () => ({
threadsByPage: [mockPage1, mockPage2],
pageCount: 2,
hasNextPage: false,
isFetchingNextPage: false,
mockFetchNextPage,
isLoading: false,
isFetching: false,
}),
}));
jest.mock('@/hooks/use-inbox-counts', () => ({
useInboxCounts: () => ({
byId: { important: { count: 42, isExact: true } },
done: { count: 0, isExact: true },
}),
}));
jest.mock('@/modules/store', () => ({
useCedarStore: (selector: (state: unknown) => unknown) =>
selector({
collapsedInboxIds: mockCollapsedState,
mockToggleInboxCollapsed: (id: string) => {
mockToggleInboxCollapsed(id);
mockCollapsedState = { ...mockCollapsedState, [id]: !mockCollapsedState[id] };
},
selectThreadId: jest.fn(),
setIsThreadOpen: jest.fn(),
}),
}));
jest.mock('@/modules/threads/threadList/threadItem', () => ({
Thread: ({ message }: { message: { id: string } }) => (
<div data-testid="thread-row">{message.id}</div>
),
}));
jest.mock('@/lib/thread-open-profiler', () => ({
startThreadOpenProfiling: jest.fn(),
}));
describe('InboxSection', () => {
beforeEach(() => {
mockFetchNextPage.mockClear();
mockToggleInboxCollapsed.mockClear();
mockCollapsedState = {};
});
it('renders only the current page of threads', () => {
const view = render(
<MemoryRouter>
<InboxSection inbox={inbox} />
</MemoryRouter>,
);
const rows = view.getAllByTestId('thread-row');
expect(rows).toHaveLength(25);
expect(rows[0].textContent).toBe('t-mockPage1-0');
});
it('shows the inbox name in the header and the total next to the pager', () => {
const view = render(
<MemoryRouter>
<InboxSection inbox={inbox} />
</MemoryRouter>,
);
expect(view.getByText('Important')).toBeInTheDocument();
expect(view.getByText('1-25 of 42')).toBeInTheDocument();
});
it('renders the range with total on the first page', () => {
const view = render(
<MemoryRouter>
<InboxSection inbox={inbox} />
</MemoryRouter>,
);
expect(view.getByText('1-25 of 42')).toBeInTheDocument();
});
it('updates the range when next is clicked', async () => {
const view = render(
<MemoryRouter>
<InboxSection inbox={inbox} />
</MemoryRouter>,
);
await act(async () => {
fireEvent.click(view.getByLabelText('Next page'));
});
expect(view.getByText('26-50 of 42')).toBeInTheDocument();
});
it('advances to the next page when next is clicked', async () => {
const view = render(
<MemoryRouter>
<InboxSection inbox={inbox} />
</MemoryRouter>,
);
await act(async () => {
fireEvent.click(view.getByLabelText('Next page'));
});
const rows = view.getAllByTestId('thread-row');
expect(rows[0].textContent).toBe('t-mockPage2-0');
});
});