avoid offset race cycle in groups as well

This commit is contained in:
Min RK
2024-05-15 10:42:58 +02:00
parent 2af252c4c3
commit cedf237852
3 changed files with 28 additions and 18 deletions

View File

@@ -14,8 +14,7 @@ const Groups = (props) => {
const dispatch = useDispatch(); const dispatch = useDispatch();
const navigate = useNavigate(); const navigate = useNavigate();
const { setOffset, offset, handleLimit, limit, setPagination } = const { offset, handleLimit, limit, setPagination } = usePaginationParams();
usePaginationParams();
const total = groups_page ? groups_page.total : undefined; const total = groups_page ? groups_page.total : undefined;
@@ -32,11 +31,22 @@ const Groups = (props) => {
}); });
}; };
// single callback to reload the page
// uses current state, or params can be specified if state
// should be updated _after_ load, e.g. offset
const loadPageData = (params) => {
params = params || {};
return updateGroups(
params.offset === undefined ? offset : params.offset,
params.limit === undefined ? limit : params.limit,
)
.then((data) => dispatchPageUpdate(data.items, data._pagination))
.catch((err) => setErrorAlert("Failed to update group list."));
};
useEffect(() => { useEffect(() => {
updateGroups(offset, limit).then((data) => loadPageData();
dispatchPageUpdate(data.items, data._pagination), }, [limit]);
);
}, [offset, limit]);
if (!groups_data || !groups_page) { if (!groups_data || !groups_page) {
return <div data-testid="no-show"></div>; return <div data-testid="no-show"></div>;
@@ -72,8 +82,10 @@ const Groups = (props) => {
limit={limit} limit={limit}
visible={groups_data.length} visible={groups_data.length}
total={total} total={total}
next={() => setOffset(offset + limit)} next={() => loadPageData({ offset: offset + limit })}
prev={() => setOffset(offset - limit)} prev={() =>
loadPageData({ offset: limit > offset ? 0 : offset - limit })
}
handleLimit={handleLimit} handleLimit={handleLimit}
/> />
</Card.Body> </Card.Body>

View File

@@ -112,8 +112,8 @@ test("Renders nothing if required data is not available", async () => {
expect(noShow).toBeVisible(); expect(noShow).toBeVisible();
}); });
test("Interacting with PaginationFooter causes state update and refresh via useEffect call", async () => { test("Interacting with PaginationFooter causes page refresh", async () => {
let upgradeGroupsSpy = mockAsync(); let updateGroupsSpy = mockAsync();
let setSearchParamsSpy = mockAsync(); let setSearchParamsSpy = mockAsync();
let searchParams = new URLSearchParams({ limit: "2" }); let searchParams = new URLSearchParams({ limit: "2" });
useSearchParams.mockImplementation(() => [ useSearchParams.mockImplementation(() => [
@@ -125,11 +125,11 @@ test("Interacting with PaginationFooter causes state update and refresh via useE
]); ]);
let _, setSearchParams; let _, setSearchParams;
await act(async () => { await act(async () => {
render(groupsJsx(upgradeGroupsSpy)); render(groupsJsx(updateGroupsSpy));
[_, setSearchParams] = useSearchParams(); [_, setSearchParams] = useSearchParams();
}); });
expect(upgradeGroupsSpy).toBeCalledWith(0, 2); expect(updateGroupsSpy).toBeCalledWith(0, 2);
var lastState = var lastState =
mockReducers.mock.results[mockReducers.mock.results.length - 1].value; mockReducers.mock.results[mockReducers.mock.results.length - 1].value;
@@ -140,9 +140,7 @@ test("Interacting with PaginationFooter causes state update and refresh via useE
await act(async () => { await act(async () => {
fireEvent.click(next); fireEvent.click(next);
}); });
expect(setSearchParamsSpy).toBeCalledWith("limit=2&offset=2"); expect(updateGroupsSpy).toBeCalledWith(2, 2);
// mocked updateGroups means callback after load doesn't fire
// FIXME: mocked useSelector, state seem to prevent updateGroups from being called // expect(setSearchParamsSpy).toBeCalledWith("limit=2&offset=2");
// making the test environment not representative
// expect(callbackSpy).toHaveBeenCalledWith(2, 2);
}); });

View File

@@ -155,7 +155,7 @@ const ServerDashboard = (props) => {
useEffect(() => { useEffect(() => {
loadPageData(); loadPageData();
}, [offset, limit, name_filter, sort, state_filter]); }, [limit, name_filter, sort, state_filter]);
if (!user_data || !user_page) { if (!user_data || !user_page) {
return <div data-testid="no-show"></div>; return <div data-testid="no-show"></div>;