Skip to content

fix(content-sharing): getContact error handler#4467

Merged
mergify[bot] merged 1 commit intomasterfrom
fix-getContact-error-handler
Mar 6, 2026
Merged

fix(content-sharing): getContact error handler#4467
mergify[bot] merged 1 commit intomasterfrom
fix-getContact-error-handler

Conversation

@reneshen0328
Copy link
Contributor

@reneshen0328 reneshen0328 commented Mar 5, 2026

If get user or group contacts API fail, we want to resolve the response so that the dropdown render empty state UI with no results instead of loading infinitely.
Screenshot 2026-03-05 at 3 41 08 PM

Summary by CodeRabbit

  • Bug Fixes

    • Error paths for contact/group lookups now consistently resolve with empty results on API failures, preventing unresolved/rejected calls and improving stability.
  • Tests

    • Updated tests to match the corrected failure behavior (expecting empty array/object responses where API calls fail).

@reneshen0328 reneshen0328 requested review from a team as code owners March 5, 2026 23:41
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 5, 2026

Walkthrough

Error handling in content-sharing contact hooks was changed so API errors now resolve with empty fallback values (arrays/objects). Corresponding tests were updated to assert these resolved empty values and to await hook results deterministically.

Changes

Cohort / File(s) Summary
Hook Tests
src/elements/content-sharing/__tests__/SharingModal.test.js, src/elements/content-sharing/__tests__/useContacts.test.js, src/elements/content-sharing/__tests__/useContactsByEmail.test.js
Updated test expectations to assert empty arrays/objects instead of falsy values on API failure paths. useContactsByEmail.test.js now awaits hook results inside act and removes artificial timeouts.
Hook Implementations
src/elements/content-sharing/hooks/useContacts.js, src/elements/content-sharing/hooks/useContactsByEmail.js
Error callbacks wrapped to call handleError(error) and then resolve with empty values (empty array [] or empty object {}) so failing API calls return resolved fallbacks instead of rejecting.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • tjuanitas
  • jfox-box

Poem

🐰
Promises that once fell apart,
Now settle gently, calm at heart.
Empty arrays and objects sing,
Tests now wait — no dangling string.
Hooray — the sharing hooks take wing!

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: fixing error handling for the getContact API calls to properly resolve responses on failure.
Description check ✅ Passed The description provides a clear explanation of the issue and solution, including a visual example of the desired empty-state behavior, though it lacks detail on the implementation approach.
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 (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix-getContact-error-handler

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Copy link
Contributor

@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: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/elements/content-sharing/__tests__/SharingModal.test.js`:
- Line 1081: The test uses a promise matcher but doesn't await it; update the
assertion in SharingModal.test.js to await the promise matcher so Jest waits for
it to resolve (i.e., change the `expect(response).resolves.toEqual({})`
assertion to use `await`), keeping the test async and targeting the `response`
variable used in the failing assertion.

In `@src/elements/content-sharing/__tests__/useContacts.test.js`:
- Around line 273-274: The promise assertion is not being returned so Jest may
finish the test before the .resolves matcher runs; update the failing test in
useContacts.test.js to either prepend return to the promise assertion (return
expect(contacts).resolves.toEqual([])) or make the test async and await the
assertion (await expect(contacts).resolves.toEqual([])); reference the test's
handleError mock and the contacts promise to locate the assertion to change.

In `@src/elements/content-sharing/hooks/useContacts.js`:
- Around line 54-57: The per-branch error handlers currently call resolve([])
which lets the other successful branch be concatenated and yields partial
contacts; instead, make each branch propagate failure to the combined lookup so
the overall result becomes empty on any single lookup failure: replace the
per-branch resolve([]) with a reject(error) (or set a shared failure flag) from
the callbacks that call handleError, and then catch that rejection in the outer
combined Promise.all (the code that currently concatenates the results around
the line that resolves to the final contacts) and resolve there to [] so
ContactsField receives an empty array when either users or groups lookup fails.
Use the existing symbols handleError, resolve/reject in the branch callbacks and
the combined Promise.all concatenation point to locate and implement this
change.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 3d135cdd-cb48-4491-bdba-60045f5163e5

📥 Commits

Reviewing files that changed from the base of the PR and between df7c1af and 1ef64b0.

📒 Files selected for processing (5)
  • src/elements/content-sharing/__tests__/SharingModal.test.js
  • src/elements/content-sharing/__tests__/useContacts.test.js
  • src/elements/content-sharing/__tests__/useContactsByEmail.test.js
  • src/elements/content-sharing/hooks/useContacts.js
  • src/elements/content-sharing/hooks/useContactsByEmail.js

@mergify
Copy link
Contributor

mergify bot commented Mar 6, 2026

Merge Queue Status

Rule: Automatic strict merge


  • Entered queue2026-03-06 02:06 UTC
  • Checks started · in-place
  • 🚫 Left the queue2026-03-06 17:44 UTC · at 18258d81d4bd86d73f732194b47b22e1108d85a6

This pull request spent 15 hours 37 minutes 59 seconds in the queue, with no time running CI.

Required conditions to merge

Reason

Pull request #4467 has been dequeued. The pull request rule doesn't match anymore

Hint

You should look at the reason for the failure and decide if the pull request needs to be fixed or if you want to requeue it.
If you do update this pull request, it will automatically be requeued once the queue conditions match again.
If you think this was a flaky issue instead, you can requeue the pull request, without updating it, by posting a @mergifyio queue comment.

@reneshen0328 reneshen0328 force-pushed the fix-getContact-error-handler branch from 18258d8 to 6ccc72e Compare March 6, 2026 18:10
@mergify mergify bot removed the dequeued label Mar 6, 2026
Copy link
Contributor

@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.

♻️ Duplicate comments (1)
src/elements/content-sharing/hooks/useContacts.js (1)

54-57: ⚠️ Potential issue | 🟠 Major

Propagate single-branch failures so the combined lookup can return a true empty state.

Resolving [] here still lets Line 75 concatenate whichever side succeeded, so a users-only or groups-only failure yields partial contacts instead of the PR’s intended empty-state behavior. Reject the branch promise here and collapse to [] once around the combined Promise.all.

💡 Proposed fix
-            const getUsers = new Promise((resolve: (result: Array<UserMini>) => void) => {
+            const getUsers = new Promise((resolve: (result: Array<UserMini>) => void, reject) => {
                 api.getMarkerBasedUsersAPI(false).getUsersInEnterprise(
                     itemID,
                     (response: UserCollection) => resolveAPICall(resolve, response, transformUsers),
                     error => {
                         handleError(error);
-                        resolve([]);
+                        reject(error);
                     },
                     { filter_term: filterTerm },
                 );
             });
-            const getGroups = new Promise((resolve: (result: Array<GroupMini>) => void) => {
+            const getGroups = new Promise((resolve: (result: Array<GroupMini>) => void, reject) => {
                 api.getMarkerBasedGroupsAPI(false).getGroupsInEnterprise(
                     itemID,
                     (response: GroupCollection) => resolveAPICall(resolve, response, transformGroups),
                     error => {
                         handleError(error);
-                        resolve([]);
+                        reject(error);
                     },
                     {
                         fields: [FIELD_NAME, FIELD_PERMISSIONS].toString(),
                         filter_term: filterTerm,
                     },
                 );
             });
-            return Promise.all([getUsers, getGroups]).then(contactArrays => [...contactArrays[0], ...contactArrays[1]]);
+            return Promise.all([getUsers, getGroups])
+                .then(([users, groups]) => [...users, ...groups])
+                .catch(() => []);

Also applies to: 65-68

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/elements/content-sharing/hooks/useContacts.js` around lines 54 - 57, The
branch-level error handlers currently call resolve([]) which lets Promise.all
succeed with partial results; change those branch handlers to reject(error)
(i.e., throw the error from the branch promise instead of resolving an empty
array) in the error callback that calls handleError so a single-branch failure
will cause the combined Promise.all to reject; then wrap the combined
Promise.all (inside useContacts) with a single .catch that returns [] (or
otherwise collapses to an empty state) so the overall lookup yields a true empty
result; apply the same change to the sibling error handler referenced at the
other branch (the error handler around lines 65-68).
🧹 Nitpick comments (1)
src/elements/content-sharing/__tests__/useContactsByEmail.test.js (1)

218-240: Cover the new V2 failure wrapper too.

This only protects the legacy { emails: [...] } path. Since useContactsByEmail now has separate error wrappers for both legacy and isContentSharingV2Enabled, add a companion V2 failure case here and pass a real error object so the handleError(error) forwarding is covered as well.

🧪 Suggested test expansion
         beforeEach(() => {
+            const apiError = new Error('lookup failed');
             getUsersInEnterprise = jest
                 .fn()
                 .mockImplementation((itemID, getUsersInEnterpriseSuccess, getUsersInEnterpriseError) => {
-                    return getUsersInEnterpriseError();
+                    return getUsersInEnterpriseError(apiError);
                 });
             mockAPI = createAPIMock({ getUsersInEnterprise });
         });
@@
-            expect(handleError).toHaveBeenCalled();
+            expect(handleError).toHaveBeenCalledWith(apiError);
             expect(contacts).toEqual({});
         });
+
+        test('should resolve to an empty object in the V2 failure path', async () => {
+            const { result } = renderHook(() =>
+                useContactsByEmail(mockAPI, MOCK_ITEM_ID, {
+                    isContentSharingV2Enabled: true,
+                    handleSuccess,
+                    handleError,
+                    transformUsers: mockTransformUsers,
+                }),
+            );
+
+            let contacts;
+            await act(async () => {
+                contacts = await result.current(MOCK_EMAIL);
+            });
+
+            expect(handleError).toHaveBeenCalledWith(apiError);
+            expect(contacts).toEqual({});
+        });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/elements/content-sharing/__tests__/useContactsByEmail.test.js` around
lines 218 - 240, Add a new test in the same file that mirrors the existing
failure case but exercises the V2 path: call useContactsByEmail with the
isContentSharingV2Enabled flag set (via the hook options) and mock the V2
failure path to reject/invoke the error callback with a real Error instance;
then invoke result.current({ emails: [MOCK_EMAIL] }) inside act, assert the V2
API/mock was called, assert handleError was called with the Error object, and
assert the returned contacts is {} so the V2 error wrapper forwarding is
covered.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@src/elements/content-sharing/hooks/useContacts.js`:
- Around line 54-57: The branch-level error handlers currently call resolve([])
which lets Promise.all succeed with partial results; change those branch
handlers to reject(error) (i.e., throw the error from the branch promise instead
of resolving an empty array) in the error callback that calls handleError so a
single-branch failure will cause the combined Promise.all to reject; then wrap
the combined Promise.all (inside useContacts) with a single .catch that returns
[] (or otherwise collapses to an empty state) so the overall lookup yields a
true empty result; apply the same change to the sibling error handler referenced
at the other branch (the error handler around lines 65-68).

---

Nitpick comments:
In `@src/elements/content-sharing/__tests__/useContactsByEmail.test.js`:
- Around line 218-240: Add a new test in the same file that mirrors the existing
failure case but exercises the V2 path: call useContactsByEmail with the
isContentSharingV2Enabled flag set (via the hook options) and mock the V2
failure path to reject/invoke the error callback with a real Error instance;
then invoke result.current({ emails: [MOCK_EMAIL] }) inside act, assert the V2
API/mock was called, assert handleError was called with the Error object, and
assert the returned contacts is {} so the V2 error wrapper forwarding is
covered.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 01347f04-9bb3-4b21-8ef3-2dfe64b43cca

📥 Commits

Reviewing files that changed from the base of the PR and between 1ef64b0 and 6ccc72e.

📒 Files selected for processing (5)
  • src/elements/content-sharing/__tests__/SharingModal.test.js
  • src/elements/content-sharing/__tests__/useContacts.test.js
  • src/elements/content-sharing/__tests__/useContactsByEmail.test.js
  • src/elements/content-sharing/hooks/useContacts.js
  • src/elements/content-sharing/hooks/useContactsByEmail.js
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/elements/content-sharing/tests/useContacts.test.js
  • src/elements/content-sharing/tests/SharingModal.test.js

@mergify mergify bot added the queued label Mar 6, 2026
@mergify mergify bot merged commit 8ec7928 into master Mar 6, 2026
12 checks passed
@mergify mergify bot deleted the fix-getContact-error-handler branch March 6, 2026 18:22
@mergify
Copy link
Contributor

mergify bot commented Mar 6, 2026

Merge Queue Status

Rule: Automatic strict merge


  • Entered queue2026-03-06 18:21 UTC
  • Checks passed · in-place
  • Merged2026-03-06 18:22 UTC · at 6ccc72e59268d8e54b77647f31d08d42d1b43c03

This pull request spent 7 seconds in the queue, with no time running CI.

Required conditions to merge

@mergify mergify bot removed the queued label Mar 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants