Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -37,19 +37,21 @@ const newestPageIds = idsOf(allReplies.slice(TOTAL - PAGE_SIZE));

type GetThreadMessagesParams = { tmid: string; offset?: number; count?: number; aroundId?: string; sort?: string };

const setup = () => {
const setup = ({ serverLimit = Infinity }: { serverLimit?: number } = {}) => {
const getThreadMessages = jest.fn(({ offset = 0, count = PAGE_SIZE, aroundId }: GetThreadMessagesParams) => {
const effectiveCount = Math.min(count, serverLimit);

if (aroundId) {
const index = allReplies.findIndex(({ _id }) => _id === aroundId);
const start = Math.max(0, index - Math.floor(count / 2));
const start = Math.max(0, index - Math.floor(effectiveCount / 2));

return { messages: allReplies.slice(start, start + count), count, offset: start, total: TOTAL };
return { messages: allReplies.slice(start, start + effectiveCount), count: effectiveCount, offset: start, total: TOTAL };
}

const end = TOTAL - offset;
const start = Math.max(0, end - count);
const start = Math.max(0, end - effectiveCount);

return { messages: allReplies.slice(start, end), count, offset, total: TOTAL };
return { messages: allReplies.slice(start, end), count: effectiveCount, offset, total: TOTAL };
});

const wrapper = mockAppRoot()
Expand Down Expand Up @@ -129,4 +131,55 @@ describe('useThreadMessagesQuery', () => {
expect(idsOf(result.current.data?.messages ?? [])).toEqual(newestPageIds);
});
});

describe('when the server clamps the response size (e.g. "Max Record Amount")', () => {
const SERVER_LIMIT = 20;
const AROUND_INDEX = 60;

it('does not skip a batch of messages when loading the next page after jumping to an old reply', async () => {
const { result } = setup({ serverLimit: SERVER_LIMIT });

await waitForLoaded(result);

await act(async () => {
await result.current.loadMessageAround(`reply-${AROUND_INDEX}`);
});
await waitFor(() => expect(result.current.hasNextPage).toBe(true));

const idsBeforeNextPage = idsOf(result.current.data?.messages ?? []);
const oldestLoadedIndex = allReplies.findIndex(({ _id }) => _id === idsBeforeNextPage[0]);
const newestLoadedIndex = allReplies.findIndex(({ _id }) => _id === idsBeforeNextPage[idsBeforeNextPage.length - 1]);

await act(async () => {
await result.current.fetchNextPage();
});
await waitFor(() => expect(result.current.isFetchingNextPage).toBe(false));

// The newly-loaded batch must continue immediately after the previously loaded one, with no gap.
const idsAfterNextPage = idsOf(result.current.data?.messages ?? []);
expect(idsAfterNextPage).toEqual(idsOf(allReplies.slice(oldestLoadedIndex, newestLoadedIndex + 1 + SERVER_LIMIT)));
});

it('reaches the newest message without gaps after repeatedly loading next pages', async () => {
const { result } = setup({ serverLimit: SERVER_LIMIT });

await waitForLoaded(result);

await act(async () => {
await result.current.loadMessageAround(`reply-${AROUND_INDEX}`);
});
await waitFor(() => expect(result.current.hasNextPage).toBe(true));

const oldestLoadedIndex = allReplies.findIndex(({ _id }) => _id === (result.current.data?.messages ?? [])[0]._id);

while (result.current.hasNextPage) {
await act(async () => {
await result.current.fetchNextPage();
});
await waitFor(() => expect(result.current.isFetchingNextPage).toBe(false));
}

expect(idsOf(result.current.data?.messages ?? [])).toEqual(idsOf(allReplies.slice(oldestLoadedIndex)));
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,8 @@ export const useThreadMessagesQuery = (tmid: IThreadMainMessage['_id'], rid?: IR
const filtered = filterThreadMessages(messages, tmid);
const processed = (await processMessages(filtered)) as IThreadMessage[];

const pageParam = Math.max(0, total - offset - count);
const pageSize = Math.min(processed.length, count);
const pageParam = Math.max(0, total - offset - pageSize);

queryClient.setQueryData<ThreadMessagesInfiniteData>(currentQueryKey, {
pages: [{ items: processed, itemCount: total }],
Expand Down Expand Up @@ -178,8 +179,15 @@ export const useThreadMessagesQuery = (tmid: IThreadMainMessage['_id'], rid?: IR
};
},
initialPageParam: 0,
getNextPageParam: (_lastPage, _allPages, lastPageParam) => {
return lastPageParam > 0 ? Math.max(0, lastPageParam - count) : undefined;
getNextPageParam: (lastPage, _allPages, lastPageParam) => {
if (lastPageParam <= 0) {
return undefined;
}
const pageSize = Math.min(lastPage.items.length, count);
if (pageSize <= 0) {
return undefined;
}
return Math.max(0, lastPageParam - pageSize);
},
getPreviousPageParam: (firstPage, _allPages, firstPageParam) => {
const pageSize = Math.min(firstPage.items.length, count);
Expand Down
Loading