Skip to content

Conversation

@aleksandernsilva
Copy link
Contributor

@aleksandernsilva aleksandernsilva commented Sep 18, 2025

Proposed changes (including videos or screenshots)

This PR restricts shortcut access to the outbound message flow for unknown contacts.

  • It disables the outbound message shortcut in the contact info contextual bar for unknown contacts (providing reason as tooltip).
  • It errors out the contact request in the unlikely case the modal is accessed with a default contact id and said contact is unknown. (This is provisory while the BE implementation is adjusted.)
Screenshot 2025-09-18 at 17 12 56 Screenshot 2025-09-18 at 17 13 36

Issue(s)

CTZ-341

Steps to test or reproduce

Further comments

Summary by CodeRabbit

  • New Features

    • Outbound message actions now show an informative tooltip and disable controls when a contact is unknown.
    • Recipient form surfaces an error state for unknown contacts with a Retry option.
  • Bug Fixes

    • Prevents sending outbound messages to unknown contacts, avoiding failed attempts.
  • Improvements

    • Contact information and channels views updated for greater consistency and clarity.
  • Security/Permissions

    • Outbound message button now respects license and permission checks and is hidden when not allowed.

@dionisio-bot
Copy link
Contributor

dionisio-bot bot commented Sep 18, 2025

Looks like this PR is ready to merge! 🎉
If you have any trouble, please check the PR guidelines

@changeset-bot
Copy link

changeset-bot bot commented Sep 18, 2025

⚠️ No Changeset found

Latest commit: e789c0b

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 18, 2025

Walkthrough

Updates outbound messaging and contact info flows: unknown contacts are treated as “not found” in RecipientForm, and several ContactInfo components now pass full contact objects instead of IDs. UI elements related to outbound messages become disabled with tooltips for unknown contacts. Tests add coverage for the unknown-contact scenario.

Changes

Cohort / File(s) Summary of changes
OutboundMessage: unknown-contact handling
apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/forms/RecipientForm/RecipientForm.tsx
Query now throws ContactNotFoundError when fetched contact has unknown=true, triggering existing error path; TODO left to remove once endpoint handles unknowns.
Tests for unknown-contact
apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/forms/RecipientForm/RecipientForm.spec.tsx
Mocks updated to include unknown:false; new test asserts retry button shown when contact is unknown.
ContactInfo parent prop changes
apps/meteor/client/views/omnichannel/contactInfo/ContactInfo/ContactInfo.tsx
Passes full contact object to children; removes separate contactId extraction; adjusts child props accordingly.
ContactInfo Channels: shift to contact object
apps/meteor/client/views/omnichannel/contactInfo/tabs/ContactInfoChannels/ContactInfoChannels.tsx
Props now accept contact Pick<_id, unknown>; queryKey and endpoint use contact._id; forwards contact to items.
ContactInfo Channels item behavior
apps/meteor/client/views/omnichannel/contactInfo/tabs/ContactInfoChannels/ContactInfoChannelsItem.tsx
Props now include contact Pick<_id, unknown>; disables outbound-message action and shows tooltip when contact.unknown; uses contact._id for modal.
ContactInfo Details: shift to contact object
apps/meteor/client/views/omnichannel/contactInfo/tabs/ContactInfoDetails/ContactInfoDetails.tsx
Props now accept contact Pick<_id, unknown>; replaces contactId usage in labels/ARIA; passes contact to phone entry.
Outbound message button gating
apps/meteor/client/views/omnichannel/contactInfo/tabs/ContactInfoDetails/ContactInfoOutboundMessageButton.tsx
Adds title and disabled props; checks license and permission before rendering; forwards disabled/title to IconButton; unchanged modal open behavior.
ContactInfo phone entry behavior
apps/meteor/client/views/omnichannel/contactInfo/tabs/ContactInfoDetails/ContactInfoPhoneEntry.tsx
Props now accept contact Pick<_id, unknown>; outbound message button disabled with tooltip when contact.unknown; defaultValues use contact._id.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor U as User
  participant RF as RecipientForm
  participant API as getContact endpoint

  U->>RF: Open Outbound Message (with contactId)
  RF->>API: getContact({ contactId })
  API-->>RF: { contact: { _id, unknown: true } }
  RF->>RF: Throw ContactNotFoundError
  RF-->>U: Show error state + Retry
  Note over RF,U: Unknown contacts treated as "not found"
Loading
sequenceDiagram
  autonumber
  actor U as User
  participant CI as ContactInfo*
  participant Btn as Outbound Message Button

  U->>CI: View Contact Info (contact passed to children)
  CI->>Btn: Render with contact { _id, unknown }
  alt contact.unknown == true
    Btn-->>U: Disabled + tooltip "error-unknown-contact"
  else contact.unknown == false
    U->>Btn: Click
    Btn-->>U: Open Outbound Message modal (prefilled)
  end
  Note over CI: Applies to ChannelsItem and PhoneEntry actions
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • lucas-a-pelegrino
  • tassoevan
  • sampaiodiego

Poem

In burrows of code I hop and peek,
Unknown contacts play hide-and-seek.
I flag them gently, “try again,”
While passing full contacts end-to-end.
A tooltip twinkles, buttons wait—
Then outbound chats can radiate.
Thump-thump! Ship it—neat and great. 🐇✨

Pre-merge checks and finishing touches

✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title "fix: Unknown contacts able to access outbound message" is concise and accurately summarizes the primary change — preventing unknown contacts from accessing the outbound message flow by disabling the shortcut and adding error handling.
Linked Issues Check ✅ Passed The changes address CTZ-341: UI-level gating is added (ContactInfoChannelsItem, ContactInfoPhoneEntry, ContactInfoOutboundMessageButton disable outbound actions and show a tooltip for contact.unknown) and RecipientForm's contact fetch now treats unknown contacts as "not found" so the modal enters its error path; the new test verifies the retry UI for unknown contacts. These modifications prevent exposing the outbound flow when no contact exists and avoid presenting a phone number as a contact identifier.
Out of Scope Changes Check ✅ Passed All modified files shown in the raw summary are directly related to the omnichannel contact/outbound message flow (prop/type changes from contactId→contact, UI gating, RecipientForm error handling, and tests). The added license/permission checks and prop signature updates are relevant to access control for outbound messages and not unrelated scope creep; I did not find unrelated modules or functionality changed.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/outbound-unknown-contact

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

@codecov
Copy link

codecov bot commented Sep 18, 2025

Codecov Report

❌ Patch coverage is 70.83333% with 7 lines in your changes missing coverage. Please review.
✅ Project coverage is 66.35%. Comparing base (93b6474) to head (e789c0b).
⚠️ Report is 1 commits behind head on develop.

Additional details and impacted files

Impacted file tree graph

@@           Coverage Diff            @@
##           develop   #36992   +/-   ##
========================================
  Coverage    66.34%   66.35%           
========================================
  Files         3391     3391           
  Lines       115300   115313   +13     
  Branches     21131    21139    +8     
========================================
+ Hits         76499    76512   +13     
+ Misses       36188    36185    -3     
- Partials      2613     2616    +3     
Flag Coverage Δ
e2e 56.92% <38.88%> (+0.02%) ⬆️
unit 71.40% <100.00%> (-0.01%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@aleksandernsilva aleksandernsilva marked this pull request as ready for review September 18, 2025 22:32
@aleksandernsilva aleksandernsilva requested a review from a team as a code owner September 18, 2025 22:32
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: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
apps/meteor/client/views/omnichannel/contactInfo/ContactInfo/ContactInfo.tsx (1)

37-41: hasConflicts can infer non-boolean type

The expression may resolve to string[] | boolean, which can trip TS when used in disabled props. Prefer a boolean-only expression.

Apply:

-  const hasConflicts = conflictingFields && conflictingFields?.length > 0;
+  const hasConflicts = (conflictingFields?.length ?? 0) > 0;
apps/meteor/client/views/omnichannel/contactInfo/tabs/ContactInfoDetails/ContactInfoPhoneEntry.tsx (1)

1-18: Make ILivechatContact import consistent: use @rocket.chat/core-typings

ContactInfoPhoneEntry.tsx imports ILivechatContact from '@rocket.chat/apps-engine/definition/livechat' while the rest of contactInfo views import it from '@rocket.chat/core-typings' — change the import to: import type { ILivechatContact } from '@rocket.chat/core-typings'. File: apps/meteor/client/views/omnichannel/contactInfo/tabs/ContactInfoDetails/ContactInfoPhoneEntry.tsx:1

🧹 Nitpick comments (10)
apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/forms/RecipientForm.spec.tsx (1)

175-185: Test covers unknown-contact path; guard against react-query retry flakiness

If the QueryClient retries failed queries, a single mockImplementationOnce can cause the second attempt to succeed and skip the error UI. Either:

  • Disable retries for the contact query (preferred; see suggested diff in RecipientForm.tsx), or
  • Make the mock return an unknown contact for all attempts in this test and reset the mock after the assertion.

Also consider asserting that “To*” and “From*” remain disabled in this state to harden UX expectations.

Would you confirm whether the test harness sets retry: false globally for TanStack Query? If not, I recommend adjusting the query’s retry policy as suggested below.

apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/forms/RecipientForm/RecipientForm.tsx (2)

81-90: Avoid retry loops for deterministic unknown contacts

Throwing ContactNotFoundError is correct. However, TanStack Query retries by default; this will spam the endpoint and can cause UI flicker. Add a retry predicate that skips retries for ContactNotFoundError.

Apply this diff inside the contact useQuery options:

  } = useQuery({
     queryKey: omnichannelQueryKeys.contact(contactId),
     queryFn: async () => {
       const data = await getContact({ contactId });

       // TODO: Can be safely removed once unknown contacts handling is added to the endpoint
       if (data?.contact && data.contact.unknown) {
         throw new ContactNotFoundError();
       }

       return data;
     },
     staleTime: 5 * 60 * 1000,
     select: (data) => data?.contact || undefined,
     enabled: !!contactId,
+    retry: (failureCount, error) => !(error instanceof ContactNotFoundError) && failureCount < 3,
   });

199-206: Gate channel selection on successful contact load

Currently ChannelField is only disabled when !contactId. With an unknown or failed contact fetch, users can still change channels even though the flow can’t proceed. Disable the channel field when the contact isn’t successfully loaded.

Apply this diff:

   <ChannelField
     control={control}
     contact={contact}
-    disabled={!contactId}
+    disabled={!contactId || isErrorContact || isContactNotFound || !contact}
     isFetching={isFetchingProvider}
     isError={isErrorProvider || isProviderNotFound}
     onRetry={refetchProvider}
   />
apps/meteor/client/views/omnichannel/contactInfo/tabs/ContactInfoDetails/ContactInfoOutboundMessageButton.tsx (2)

26-34: Avoid trailing space and improve a11y label

Current string interpolation leaves a trailing space when no title. Also add an explicit aria-label for SRs.

Apply:

-      title={`${t('Outbound_message')} ${title ? `(${title})` : ''}`}
+      title={title ? `${t('Outbound_message')} (${title})` : t('Outbound_message')}
+      aria-label={title ? `${t('Outbound_message')} (${title})` : t('Outbound_message')}

10-12: Prop naming clarity

"title" here represents a tooltip/reason. Consider renaming to "tooltip" for intent clarity across callers. Non-blocking.

apps/meteor/client/views/omnichannel/contactInfo/tabs/ContactInfoDetails/ContactInfoPhoneEntry.tsx (1)

30-35: Guard against missing contact

If contact is ever undefined, defaultValues would pass an undefined contactId. Disable the action in that case.

Apply:

-        <ContactInfoOutboundMessageButton
+        <ContactInfoOutboundMessageButton
           key={`${value}-outbound-message`}
           title={contact?.unknown ? t('error-unknown-contact') : undefined}
-          disabled={contact?.unknown}
-          defaultValues={{ contactId: contact?._id, recipient: value }}
+          disabled={contact?.unknown || !contact?._id}
+          defaultValues={contact?._id ? { contactId: contact._id, recipient: value } : undefined}
         />
apps/meteor/client/views/omnichannel/contactInfo/tabs/ContactInfoChannels/ContactInfoChannelsItem.tsx (2)

54-62: Also gate menu item by license/permission

Else users without permission may still see the option (even if the modal later blocks). Mirror the button’s gating for consistent UX.

Apply inside the unshift block:

-      items.unshift({
+      items.unshift({
         id: 'outbound-message',
         icon: 'send',
         disabled: contact?.unknown,
         tooltip: contact?.unknown ? t('error-unknown-contact') : undefined,
         content: t('Outbound_message'),
         onClick: () => outboundMessageModal.open({ contactId: contact?._id, providerId: details.id }),
       });

And above, compute license/permission and fold into the if:

+  // optionally import/use the same hooks used elsewhere:
+  // const hasLicense = useHasLicenseModule('livechat-enterprise') === true;
+  // const hasPermission = usePermission('outbound.send-messages');
-  if (canSendOutboundMessage) {
+  if (canSendOutboundMessage /* && hasLicense && hasPermission */) {

If you prefer not to add hooks here, pass a precomputed canSendOutboundMessage from the parent that already accounts for license/permission.


65-66: Memo deps completeness

If you add license/permission gating as suggested, include them in deps to keep memoization correct.

apps/meteor/client/views/omnichannel/contactInfo/tabs/ContactInfoChannels/ContactInfoChannels.tsx (2)

26-28: Fold license/permission into canSendOutboundMessage at the source

Compute canSendOutboundMessage in this container so items don’t need to know about permissions.

Illustrative changes:

+import { useHasLicenseModule } from '../../../../../hooks/useHasLicenseModule';
+import { usePermission } from '@rocket.chat/ui-contexts';
...
+  const hasLicense = useHasLicenseModule('livechat-enterprise') === true;
+  const hasPermission = usePermission('outbound.send-messages');
...
-  canSendOutboundMessage={data.details.id ? providers.includes(data.details.id) : false}
+  canSendOutboundMessage={
+    !!(data.details.id && providers.includes(data.details.id) && hasLicense && hasPermission)
+  }

68-74: Key stability

Using index as key can cause UI glitches on reordering. Prefer a stable id if available (e.g., data._id).

-  key={index}
+  key={data._id ?? index}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between d8f4217 and 978cc7f.

📒 Files selected for processing (8)
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/forms/RecipientForm.spec.tsx (3 hunks)
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/forms/RecipientForm/RecipientForm.tsx (1 hunks)
  • apps/meteor/client/views/omnichannel/contactInfo/ContactInfo/ContactInfo.tsx (2 hunks)
  • apps/meteor/client/views/omnichannel/contactInfo/tabs/ContactInfoChannels/ContactInfoChannels.tsx (2 hunks)
  • apps/meteor/client/views/omnichannel/contactInfo/tabs/ContactInfoChannels/ContactInfoChannelsItem.tsx (3 hunks)
  • apps/meteor/client/views/omnichannel/contactInfo/tabs/ContactInfoDetails/ContactInfoDetails.tsx (4 hunks)
  • apps/meteor/client/views/omnichannel/contactInfo/tabs/ContactInfoDetails/ContactInfoOutboundMessageButton.tsx (2 hunks)
  • apps/meteor/client/views/omnichannel/contactInfo/tabs/ContactInfoDetails/ContactInfoPhoneEntry.tsx (3 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/forms/RecipientForm.spec.tsx (1)
apps/meteor/tests/mocks/data.ts (1)
  • createFakeContactWithManagerData (352-366)
apps/meteor/client/views/omnichannel/contactInfo/tabs/ContactInfoDetails/ContactInfoOutboundMessageButton.tsx (1)
apps/meteor/client/components/Omnichannel/OutboundMessage/modals/OutboundMessageModal/OutboundMessageModal.tsx (1)
  • OutboundMessageModalProps (11-14)
apps/meteor/client/views/omnichannel/contactInfo/tabs/ContactInfoDetails/ContactInfoPhoneEntry.tsx (1)
packages/apps-engine/src/definition/livechat/index.ts (1)
  • ILivechatContact (29-29)
🔇 Additional comments (5)
apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/forms/RecipientForm.spec.tsx (1)

27-27: Mocks: explicit unknown: false is good

Being explicit aligns the test fixtures with the new runtime shape and avoids accidental truthy/undefined behavior.

Also applies to: 40-40

apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/forms/RecipientForm/RecipientForm.tsx (1)

81-90: Type-safety OK — unknown?: boolean is declared on ILivechatContact

Declaration found at packages/core-typings/src/ILivechatContact.ts (unknown?: boolean); the runtime guard is type-safe and can remain or be removed later when the endpoint handles unknown contacts.

apps/meteor/client/views/omnichannel/contactInfo/tabs/ContactInfoDetails/ContactInfoOutboundMessageButton.tsx (1)

22-24: Permission/license gating: good call

Early return on missing license/permission avoids dangling UI states. LGTM.

apps/meteor/client/views/omnichannel/contactInfo/tabs/ContactInfoDetails/ContactInfoDetails.tsx (2)

41-47: Contact handed down to phone entries: LGTM

Ensures unknown-contact awareness in per-phone actions.


56-59: A11y: good use of labelled-by

Label associations for created-at improve SR navigation. LGTM.

@aleksandernsilva aleksandernsilva added this to the 7.11.0 milestone Sep 18, 2025
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: 1

♻️ Duplicate comments (1)
apps/meteor/client/views/omnichannel/contactInfo/tabs/ContactInfoDetails/ContactInfoPhoneEntry.tsx (1)

1-1: Resolved: ILivechatContact import aligned to core-typings

Good fix; matches the rest of the feature and avoids type drift.

🧹 Nitpick comments (1)
apps/meteor/client/views/omnichannel/contactInfo/tabs/ContactInfoDetails/ContactInfoPhoneEntry.tsx (1)

14-15: Prop allows undefined contact; current gating only checks unknown

If contact is omitted, the Outbound button won’t be disabled (since contact?.unknown is falsy). Either ensure contact is always provided, or treat missing contact as unknown in consumers.

Would you confirm whether contact is guaranteed at all call sites after this refactor? If not, the change suggested below on Lines 30–35 will harden the gating without widening types.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 978cc7f and 517602d.

📒 Files selected for processing (1)
  • apps/meteor/client/views/omnichannel/contactInfo/tabs/ContactInfoDetails/ContactInfoPhoneEntry.tsx (3 hunks)
🔇 Additional comments (1)
apps/meteor/client/views/omnichannel/contactInfo/tabs/ContactInfoDetails/ContactInfoPhoneEntry.tsx (1)

17-21: LGTM on signature change and hooks usage

Destructuring contact and keeping value flow intact looks good.

tassoevan
tassoevan previously approved these changes Sep 19, 2025
@tassoevan tassoevan added the stat: QA assured Means it has been tested and approved by a company insider label Sep 19, 2025
@dionisio-bot dionisio-bot bot added the stat: ready to merge PR tested and approved waiting for merge label Sep 19, 2025
@aleksandernsilva aleksandernsilva removed the stat: QA assured Means it has been tested and approved by a company insider label Sep 19, 2025
@dionisio-bot dionisio-bot bot removed the stat: ready to merge PR tested and approved waiting for merge label Sep 19, 2025
@aleksandernsilva aleksandernsilva added the stat: QA assured Means it has been tested and approved by a company insider label Sep 19, 2025
@dionisio-bot dionisio-bot bot added the stat: ready to merge PR tested and approved waiting for merge label Sep 19, 2025
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: 0

🧹 Nitpick comments (2)
apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/forms/RecipientForm/RecipientForm.spec.tsx (2)

33-34: Mirror change on contactTwo — OK; consider centralizing default.

Optional: set unknown: false as a default in the test factory to avoid repeating in every mock.

For example, in createFakeContact (or createFakeContactWithManagerData) default the field when absent:

export function createFakeContactWithManagerData(overrides?: Partial<Serialized<ILivechatContactWithManagerData>>) {
  const { contactManager: contactManagerOverwrites, ...contactOverwrites } = overrides || {};
  const contact = createFakeContact({ unknown: false, ...contactOverwrites });
  return {
    ...contact,
    contactManager: {
      _id: faker.string.uuid(),
      name: faker.person.fullName(),
      username: faker.internet.userName(),
      ...contactManagerOverwrites,
    },
  };
}

168-177: Great coverage for the unknown‑contact path; add state assertions and retry recovery.

Strengthen by asserting dependent fields are disabled and that Retry clears the error once the contact becomes known.

Apply this diff within this test case:

 it('should show retry button when contact is unknown', async () => {
   getContactMock.mockImplementationOnce(() => ({ contact: createFakeContactWithManagerData({ _id: 'contact-1', unknown: true }) }));
 
   render(<RecipientForm defaultValues={{ contactId: 'contact-1' }} {...defaultProps} />, { wrapper: appRoot.build() });
 
   await waitFor(() => expect(screen.getByLabelText('Contact*')).toHaveAccessibleDescription('Error loading contact information'));
 
   const retryButton = screen.getByRole('button', { name: 'Retry' });
   expect(retryButton).toBeInTheDocument();
+
+  // Dependent fields should be disabled when contact is unknown
+  expect(screen.getByLabelText('To*')).toHaveClass('disabled');
+  expect(screen.getByLabelText('From*')).toHaveClass('disabled');
+
+  // On retry, if contact becomes known, error should clear
+  getContactMock.mockImplementationOnce(() => ({ contact: contactOneMock }));
+  await userEvent.click(retryButton);
+  await waitFor(() => expect(screen.queryByText('Error loading contact information')).not.toBeInTheDocument());
 });

Additionally, keep mock return shapes consistently async to reduce flakiness:

// Prefer this shape (apply similarly to other GET mocks):
const getContactMock = jest.fn().mockResolvedValue({ contact: contactOneMock });
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 517602d and 832fb28.

📒 Files selected for processing (8)
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/forms/RecipientForm/RecipientForm.spec.tsx (3 hunks)
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/forms/RecipientForm/RecipientForm.tsx (1 hunks)
  • apps/meteor/client/views/omnichannel/contactInfo/ContactInfo/ContactInfo.tsx (2 hunks)
  • apps/meteor/client/views/omnichannel/contactInfo/tabs/ContactInfoChannels/ContactInfoChannels.tsx (2 hunks)
  • apps/meteor/client/views/omnichannel/contactInfo/tabs/ContactInfoChannels/ContactInfoChannelsItem.tsx (3 hunks)
  • apps/meteor/client/views/omnichannel/contactInfo/tabs/ContactInfoDetails/ContactInfoDetails.tsx (4 hunks)
  • apps/meteor/client/views/omnichannel/contactInfo/tabs/ContactInfoDetails/ContactInfoOutboundMessageButton.tsx (2 hunks)
  • apps/meteor/client/views/omnichannel/contactInfo/tabs/ContactInfoDetails/ContactInfoPhoneEntry.tsx (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (7)
  • apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/forms/RecipientForm/RecipientForm.tsx
  • apps/meteor/client/views/omnichannel/contactInfo/tabs/ContactInfoDetails/ContactInfoPhoneEntry.tsx
  • apps/meteor/client/views/omnichannel/contactInfo/tabs/ContactInfoDetails/ContactInfoOutboundMessageButton.tsx
  • apps/meteor/client/views/omnichannel/contactInfo/tabs/ContactInfoDetails/ContactInfoDetails.tsx
  • apps/meteor/client/views/omnichannel/contactInfo/tabs/ContactInfoChannels/ContactInfoChannelsItem.tsx
  • apps/meteor/client/views/omnichannel/contactInfo/ContactInfo/ContactInfo.tsx
  • apps/meteor/client/views/omnichannel/contactInfo/tabs/ContactInfoChannels/ContactInfoChannels.tsx
🧰 Additional context used
🧬 Code graph analysis (1)
apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/forms/RecipientForm/RecipientForm.spec.tsx (1)
apps/meteor/tests/mocks/data.ts (1)
  • createFakeContactWithManagerData (352-366)
⏰ 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). (1)
  • GitHub Check: CodeQL-Build
🔇 Additional comments (1)
apps/meteor/client/components/Omnichannel/OutboundMessage/components/OutboundMessageWizard/forms/RecipientForm/RecipientForm.spec.tsx (1)

20-21: Explicit unknown: false on contactOne mock — LGTM; typings include unknown?: boolean.
Confirmed ILivechatContact / ILivechatContactWithManagerData declare unknown?: boolean.

@kodiakhq kodiakhq bot merged commit 05beabb into develop Sep 19, 2025
48 checks passed
@kodiakhq kodiakhq bot deleted the fix/outbound-unknown-contact branch September 19, 2025 19:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

stat: QA assured Means it has been tested and approved by a company insider stat: ready to merge PR tested and approved waiting for merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants