feat: finalize pretext feed sizing rollout (#1120)

* feat(feeds): add pretext-backed item sizing across board, catalog, and thread replies

* feat: finalize pretext feed sizing rollout

* fix(catalog): raise multiboard viewport buffer

* fix(board): preserve pretext query overrides
This commit is contained in:
Tommaso Casaburi
2026-04-02 19:45:55 +07:00
committed by GitHub
parent 4fb7739991
commit 251e103db3
21 changed files with 2733 additions and 179 deletions
@@ -45,9 +45,11 @@ type TestComment = {
const testState = vi.hoisted(() => ({
addChallengeMock: vi.fn(),
hasMoreReplies: false,
openReplyModalMock: vi.fn(),
replyComments: [] as Array<TestComment | undefined>,
setResetFunctionMock: vi.fn(),
virtuosoProps: [] as Array<{ defaultItemHeight?: number; heightEstimates?: number[]; itemSize?: unknown }>,
}));
const getMockPreloadedReplies = (comment?: TestComment, sortType?: string) => {
@@ -89,7 +91,7 @@ vi.mock('@bitsocialnet/bitsocial-react-hooks', () => ({
useReplies: ({ comment, sortType }: { comment?: TestComment; sortType?: string }) => {
testState.replyComments.push(comment);
return {
hasMore: false,
hasMore: testState.hasMoreReplies,
loadMore: vi.fn(),
replies: getMockPreloadedReplies(comment, sortType),
};
@@ -102,14 +104,22 @@ vi.mock('react-virtuoso', () => ({
{
components,
data = [],
defaultItemHeight,
heightEstimates,
itemSize,
itemContent,
}: {
components?: { Footer?: React.ComponentType };
data?: TestComment[];
defaultItemHeight?: number;
heightEstimates?: number[];
itemSize?: unknown;
itemContent: (index: number, item: TestComment) => React.ReactNode;
},
ref: React.ForwardedRef<{ getState: (cb: (snapshot: { ranges: number[]; scrollTop: number }) => void) => void }>,
) => {
testState.virtuosoProps.push({ defaultItemHeight, heightEstimates, itemSize });
React.useImperativeHandle(ref, () => ({
getState: (cb) => cb({ ranges: [0], scrollTop: 0 }),
}));
@@ -315,6 +325,14 @@ vi.mock('../../hooks/use-fresh-replies', () => ({
default: (replies: TestComment[]) => replies,
}));
vi.mock('../../hooks/use-reply-height-estimates', () => ({
default: ({ isMobile, replies }: { isMobile: boolean; replies: TestComment[] }) => ({
defaultItemHeight: isMobile ? 222 : 111,
heightEstimates: replies.map((_, index) => (isMobile ? 200 : 100) + index),
itemSize: vi.fn(),
}),
}));
vi.mock('../../lib/constants', () => ({
BOARD_REPLIES_PREVIEW_FETCH_SIZE: 5,
BOARD_REPLIES_PREVIEW_VISIBLE_COUNT: 3,
@@ -406,10 +424,24 @@ const makeLegacyThread = (): TestComment => ({
timestamp: 1_710_000_000,
});
const makeLegacyThreadWithoutReplies = (): TestComment => ({
...makeLegacyThread(),
replyCount: 0,
replies: {
pages: {
new: {
comments: [],
},
},
},
});
describe('post community address compatibility', () => {
beforeEach(() => {
vi.clearAllMocks();
testState.hasMoreReplies = false;
testState.replyComments = [];
testState.virtuosoProps = [];
container = document.createElement('div');
document.body.appendChild(container);
@@ -444,4 +476,39 @@ describe('post community address compatibility', () => {
expect(container.querySelector('[data-testid="comment-media"]')).toBeTruthy();
expect(container.textContent).toContain('reply-1');
});
it('forwards Pretext-backed reply estimates into Virtuoso for desktop and mobile thread views', async () => {
testState.hasMoreReplies = true;
await renderWithRoute(createElement(PostDesktop, { post: makeLegacyThread(), showAllReplies: true }), '/mu/thread/post-1');
expect(testState.virtuosoProps.at(-1)).toEqual({
defaultItemHeight: 111,
heightEstimates: [100],
itemSize: expect.any(Function),
});
testState.virtuosoProps = [];
await renderWithRoute(createElement(PostMobile, { post: makeLegacyThread(), showAllReplies: true }), '/mu/thread/post-1');
expect(testState.virtuosoProps.at(-1)).toEqual({
defaultItemHeight: 222,
heightEstimates: [200],
itemSize: expect.any(Function),
});
});
it('keeps board-card Pretext heights when preview replies are rendered', async () => {
await renderWithRoute(createElement(PostDesktop, { post: makeLegacyThread() }));
expect(container.querySelector('.postDesktop')?.getAttribute('data-pretext-height')).toBeTruthy();
await renderWithRoute(createElement(PostMobile, { post: makeLegacyThread() }));
expect(container.querySelector('.postMobile')?.getAttribute('data-pretext-height')).toBeTruthy();
});
it('keeps board-card Pretext heights for simple cards without preview replies', async () => {
await renderWithRoute(createElement(PostDesktop, { post: makeLegacyThreadWithoutReplies() }));
expect(container.querySelector('.postDesktop')?.getAttribute('data-pretext-height')).toBeTruthy();
await renderWithRoute(createElement(PostMobile, { post: makeLegacyThreadWithoutReplies() }));
expect(container.querySelector('.postMobile')?.getAttribute('data-pretext-height')).toBeTruthy();
});
});