Skip to content

Conversation

@niko-exo
Copy link

@niko-exo niko-exo commented Dec 30, 2025

ref: https://app.clickup.com/t/86b7kbjcf

86b7kbjcf - Fix: item counter when deleting form item on second page

Changelog

  • Update reducer test
  • Dont update total count on delete item reducer
  • Test delete sponsor form item
  • Request sponsor form items to update total value correctly

Links

86b7kbjcf - Item counter does not refresh after deleting item until page refresh

Evidence

2025-12-30_13-34-24.mp4

Summary by CodeRabbit

  • Bug Fixes

    • Sponsor form item list now automatically refreshes after deletion so displayed items reflect the current state.
    • The displayed total count is no longer adjusted as part of the delete flow.
  • Tests

    • Added test coverage for sponsor form item deletion to validate deletion requests and success notifications.

✏️ Tip: You can customize this high-level summary in your review settings.

Copy link

@smarcet smarcet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@niko-exo please review comments

@niko-exo niko-exo added the COMMENTS This PR has comments to solve label Jan 6, 2026
@niko-exo niko-exo force-pushed the fix/refresh-item-counter branch from 1a81b2a to 156ba5b Compare January 9, 2026 13:23
@coderabbitai
Copy link

coderabbitai bot commented Jan 9, 2026

📝 Walkthrough

Walkthrough

Adds a unit test for sponsor form item deletion, makes the page refresh sponsor form items after a successful delete, and removes totalCount updates from the sponsor form items reducer and its tests.

Changes

Cohort / File(s) Summary
Tests
src/actions/__tests__/sponsor-forms-actions.test.js
New unit test for the DeleteSponsorFormItem thunk; mocks deleteRequest, stubs token retrieval, and spies on snackbar success handler; asserts token retrieval, delete request, and snackbar invocation.
Page & Action Logic
src/pages/sponsors/sponsor-form-item-list-page/index.js, src/actions/sponsor-forms-actions.js
SponsorFormItemListPage.handleRowDelete now chains a .then to dispatch getSponsorFormItems with current pagination/sort/archive to refresh the list after deletion. Minor whitespace change in actions file.
Reducer & Reducer Tests
src/reducers/sponsors/sponsor-form-items-list-reducer.js, src/reducers/sponsors/__tests__/sponsor-form-items-list-reducer.test.js
SPONSOR_FORM_ITEM_DELETED no longer updates or returns totalCount; tests updated to remove expectations for totalCount.

Sequence Diagram(s)

sequenceDiagram
  participant Page as SponsorFormItemListPage
  participant Thunk as deleteSponsorFormItem (thunk)
  participant API as openstack-uicore-foundation.deleteRequest
  participant Action as getSponsorFormItems
  participant Reducer as SponsorFormItemsListReducer

  Page->>Thunk: dispatch(deleteSponsorFormItem(formId, itemId))
  Thunk->>API: deleteRequest(..., token)
  API-->>Thunk: 200 OK
  Thunk->>Page: snackbarSuccessHandler()
  Thunk->>Action: dispatch(getSponsorFormItems(pagination, sort, archive))
  Action->>Reducer: dispatch(LOAD_SPONSOR_FORM_ITEMS_SUCCESS)
  Reducer-->>Page: updated items state
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Suggested reviewers

  • smarcet

Poem

🐰 I hopped in quick to clear the slate,
Deleted an item, then fetched the state.
Totals dropped silent, the list is neat,
Tests gave a nod—everything's complete.
Hop, snack, commit, and repeat! 🥕

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title references a ClickUp task ID and describes the main fix: refreshing the item counter when deleting a form item on subsequent pages, which aligns with the changeset's core objective.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Comment @coderabbitai help to get the list of available commands and usage tips.

@niko-exo
Copy link
Author

niko-exo commented Jan 9, 2026

Branch rebased on master.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In @src/actions/__tests__/sponsor-forms-actions.test.js:
- Around line 25-64: Test has a typo in the expectation message and is missing
stronger assertions: fix the typo "acces" -> "access" in the comment/assertion,
remove the unused sponsorFormItemsListState from the mockedGetState return, and
add assertions inside the "execute" test to verify deleteRequest was called with
the correct URL and handlers and that the SPONSOR_FORM_ITEM_DELETED action (or
the action creator used by deleteSponsorFormItem) was dispatched with the
expected itemId; use the existing spies/mocks (spyOnGetAccessTokenSafely,
spyOnSnackbarSuccessHandler, OpenStackUiCoreActions.deleteRequest) and the
deleteSponsorFormItem invocation to assert the exact parameters and dispatched
action.
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c119116 and 156ba5b.

📒 Files selected for processing (5)
  • src/actions/__tests__/sponsor-forms-actions.test.js
  • src/actions/sponsor-forms-actions.js
  • src/pages/sponsors/sponsor-form-item-list-page/index.js
  • src/reducers/sponsors/__tests__/sponsor-form-items-list-reducer.test.js
  • src/reducers/sponsors/sponsor-form-items-list-reducer.js
💤 Files with no reviewable changes (2)
  • src/actions/sponsor-forms-actions.js
  • src/reducers/sponsors/tests/sponsor-form-items-list-reducer.test.js
🧰 Additional context used
🧬 Code graph analysis (1)
src/pages/sponsors/sponsor-form-item-list-page/index.js (1)
src/actions/sponsor-forms-actions.js (4)
  • deleteSponsorFormItem (933-959)
  • deleteSponsorFormItem (933-959)
  • getSponsorFormItems (862-909)
  • getSponsorFormItems (862-909)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: build
  • GitHub Check: build
  • GitHub Check: build
  • GitHub Check: build
  • GitHub Check: build
  • GitHub Check: build
🔇 Additional comments (5)
src/actions/__tests__/sponsor-forms-actions.test.js (3)

1-5: LGTM!

The imports are well-organized and include all necessary dependencies for testing the DeleteSponsorFormItem action flow.


6-16: LGTM!

The mock correctly preserves the original module while stubbing deleteRequest with a triple-nested function that matches the thunk pattern used in the codebase: deleteRequest(...args)(params)(dispatch).


18-24: LGTM!

The test suite structure is clean, with proper cleanup using jest.restoreAllMocks() in afterEach to prevent test interference.

src/pages/sponsors/sponsor-form-item-list-page/index.js (1)

104-115: LGTM! This correctly fixes the item counter refresh issue.

The change properly addresses the root cause by refetching the list after deletion, ensuring totalCount and the items array are synchronized with the backend state. This approach is more reliable than attempting to calculate totalCount locally in the reducer.

The refresh preserves all current filters, sorting, and pagination parameters, maintaining the user's view state.

src/reducers/sponsors/sponsor-form-items-list-reducer.js (1)

131-136: LGTM! Simplifying the reducer is the right approach.

Removing the local totalCount recalculation eliminates the source of the bug. The subsequent refetch (added in the page component) ensures totalCount is updated accurately from the backend.

This change follows the single-source-of-truth principle: instead of attempting to maintain synchronization locally, rely on the server response via RECEIVE_SPONSOR_FORM_ITEMS to update both items and totalCount correctly.

Comment on lines +25 to +64
it("execute", async () => {
const mockedDispatch = jest.fn();
const mockedGetState = jest.fn(() => ({
currentSummitState: {
currentSummit: "SSS"
},
sponsorFormItemsListState: {
currentPage: 1,
perPage: 10,
order: "asc",
orderDir: 1,
hideArchived: false
}
}));

const params = {
formId: "AAA",
itemId: "III"
};

const spyOnGetAccessTokenSafely = jest
.spyOn(UtilsMethods, "getAccessTokenSafely")
.mockImplementation(() => "access _token");
const spyOnSnackbarSuccessHandler = jest.spyOn(
BaseActions,
"snackbarSuccessHandler"
);

await deleteSponsorFormItem(params.formId, params.itemId)(
mockedDispatch,
mockedGetState
);

// gets acces token safely
expect(spyOnGetAccessTokenSafely).toHaveBeenCalled();
// calls delete request
expect(OpenStackUiCoreActions.deleteRequest).toHaveBeenCalled();
// shows snackbar
expect(spyOnSnackbarSuccessHandler).toHaveBeenCalled();
});
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix typo and consider more comprehensive assertions.

Minor typo on line 58: "acces" should be "access".

The test validates the observable side effects but could be more thorough. Consider adding assertions to verify:

  • The correct parameters are passed to deleteRequest (URL, action creator, error handler)
  • The SPONSOR_FORM_ITEM_DELETED action is dispatched with the correct itemId

Additionally, sponsorFormItemsListState in the mocked state (lines 31-37) is not used by deleteSponsorFormItem and can be removed for clarity.

📝 Proposed fix for typo
-      // gets acces token safely
+      // gets access token safely
       expect(spyOnGetAccessTokenSafely).toHaveBeenCalled();
♻️ Optional: More comprehensive assertions
       const mockedGetState = jest.fn(() => ({
         currentSummitState: {
           currentSummit: "SSS"
-        },
-        sponsorFormItemsListState: {
-          currentPage: 1,
-          perPage: 10,
-          order: "asc",
-          orderDir: 1,
-          hideArchived: false
         }
       }));

And add more specific assertions:

       // gets access token safely
       expect(spyOnGetAccessTokenSafely).toHaveBeenCalled();
       // calls delete request
       expect(OpenStackUiCoreActions.deleteRequest).toHaveBeenCalled();
+      // verify deleteRequest was called with correct action creator
+      const deleteRequestCall = OpenStackUiCoreActions.deleteRequest.mock.calls[0];
+      expect(deleteRequestCall[1]).toBeDefined(); // action creator
+      expect(deleteRequestCall[2]).toContain('/show-forms/AAA/items/III'); // URL
       // shows snackbar
       expect(spyOnSnackbarSuccessHandler).toHaveBeenCalled();
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
it("execute", async () => {
const mockedDispatch = jest.fn();
const mockedGetState = jest.fn(() => ({
currentSummitState: {
currentSummit: "SSS"
},
sponsorFormItemsListState: {
currentPage: 1,
perPage: 10,
order: "asc",
orderDir: 1,
hideArchived: false
}
}));
const params = {
formId: "AAA",
itemId: "III"
};
const spyOnGetAccessTokenSafely = jest
.spyOn(UtilsMethods, "getAccessTokenSafely")
.mockImplementation(() => "access _token");
const spyOnSnackbarSuccessHandler = jest.spyOn(
BaseActions,
"snackbarSuccessHandler"
);
await deleteSponsorFormItem(params.formId, params.itemId)(
mockedDispatch,
mockedGetState
);
// gets acces token safely
expect(spyOnGetAccessTokenSafely).toHaveBeenCalled();
// calls delete request
expect(OpenStackUiCoreActions.deleteRequest).toHaveBeenCalled();
// shows snackbar
expect(spyOnSnackbarSuccessHandler).toHaveBeenCalled();
});
it("execute", async () => {
const mockedDispatch = jest.fn();
const mockedGetState = jest.fn(() => ({
currentSummitState: {
currentSummit: "SSS"
}
}));
const params = {
formId: "AAA",
itemId: "III"
};
const spyOnGetAccessTokenSafely = jest
.spyOn(UtilsMethods, "getAccessTokenSafely")
.mockImplementation(() => "access _token");
const spyOnSnackbarSuccessHandler = jest.spyOn(
BaseActions,
"snackbarSuccessHandler"
);
await deleteSponsorFormItem(params.formId, params.itemId)(
mockedDispatch,
mockedGetState
);
// gets access token safely
expect(spyOnGetAccessTokenSafely).toHaveBeenCalled();
// calls delete request
expect(OpenStackUiCoreActions.deleteRequest).toHaveBeenCalled();
// verify deleteRequest was called with correct action creator
const deleteRequestCall = OpenStackUiCoreActions.deleteRequest.mock.calls[0];
expect(deleteRequestCall[1]).toBeDefined(); // action creator
expect(deleteRequestCall[2]).toContain('/show-forms/AAA/items/III'); // URL
// shows snackbar
expect(spyOnSnackbarSuccessHandler).toHaveBeenCalled();
});
🤖 Prompt for AI Agents
In @src/actions/__tests__/sponsor-forms-actions.test.js around lines 25 - 64,
Test has a typo in the expectation message and is missing stronger assertions:
fix the typo "acces" -> "access" in the comment/assertion, remove the unused
sponsorFormItemsListState from the mockedGetState return, and add assertions
inside the "execute" test to verify deleteRequest was called with the correct
URL and handlers and that the SPONSOR_FORM_ITEM_DELETED action (or the action
creator used by deleteSponsorFormItem) was dispatched with the expected itemId;
use the existing spies/mocks (spyOnGetAccessTokenSafely,
spyOnSnackbarSuccessHandler, OpenStackUiCoreActions.deleteRequest) and the
deleteSponsorFormItem invocation to assert the exact parameters and dispatched
action.

@niko-exo
Copy link
Author

niko-exo commented Jan 9, 2026

Ready for review

@niko-exo niko-exo removed the COMMENTS This PR has comments to solve label Jan 9, 2026
@niko-exo niko-exo requested a review from smarcet January 9, 2026 13:37
@niko-exo niko-exo force-pushed the fix/refresh-item-counter branch from 156ba5b to e44ae59 Compare January 19, 2026 14:13
@niko-exo
Copy link
Author

Branch rebased on master

@niko-exo
Copy link
Author

@smarcet Ready for review

@niko-exo
Copy link
Author

Parameter replaced with constant! My bad I understood something different.

Copy link

@smarcet smarcet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@smarcet smarcet merged commit e29ade6 into master Jan 19, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants