From 142c402e76c5ad3b18a41edb6f9edc89234eeab5 Mon Sep 17 00:00:00 2001 From: ShridharGoel <35566748+ShridharGoel@users.noreply.github.com> Date: Sun, 21 Apr 2024 14:07:31 +0530 Subject: [PATCH 01/12] Tests for group chat name --- src/pages/InviteReportParticipantsPage.tsx | 17 +- tests/ui/GroupChatNameTests.tsx | 479 +++++++++++++++++++++ tests/unit/ReportUtilsTest.ts | 107 +++++ tests/utils/LHNTestUtils.tsx | 7 + 4 files changed, 602 insertions(+), 8 deletions(-) create mode 100644 tests/ui/GroupChatNameTests.tsx diff --git a/src/pages/InviteReportParticipantsPage.tsx b/src/pages/InviteReportParticipantsPage.tsx index da97ef26414bb..7e92a917c67c4 100644 --- a/src/pages/InviteReportParticipantsPage.tsx +++ b/src/pages/InviteReportParticipantsPage.tsx @@ -12,6 +12,7 @@ import InviteMemberListItem from '@components/SelectionList/InviteMemberListItem import type {Section} from '@components/SelectionList/types'; import withNavigationTransitionEnd from '@components/withNavigationTransitionEnd'; import type {WithNavigationTransitionEndProps} from '@components/withNavigationTransitionEnd'; +import useDebouncedState from '@hooks/useDebouncedState'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import * as DeviceCapabilities from '@libs/DeviceCapabilities'; @@ -45,7 +46,7 @@ function InviteReportParticipantsPage({betas, personalDetails, report, didScreen const styles = useThemeStyles(); const {translate} = useLocalize(); - const [searchTerm, setSearchTerm] = useState(''); + const [searchTerm, debouncedSearchTerm, setSearchTerm] = useDebouncedState(''); const [selectedOptions, setSelectedOptions] = useState([]); const [invitePersonalDetails, setInvitePersonalDetails] = useState([]); const [recentReports, setRecentReports] = useState([]); @@ -55,7 +56,7 @@ function InviteReportParticipantsPage({betas, personalDetails, report, didScreen const excludedUsers = useMemo(() => [...PersonalDetailsUtils.getLoginsByAccountIDs(ReportUtils.getParticipantAccountIDs(report?.reportID ?? '')), ...CONST.EXPENSIFY_EMAILS], [report]); useEffect(() => { - const inviteOptions = OptionsListUtils.getMemberInviteOptions(options.personalDetails, betas ?? [], searchTerm, excludedUsers, false, options.reports, true); + const inviteOptions = OptionsListUtils.getMemberInviteOptions(options.personalDetails, betas ?? [], debouncedSearchTerm, excludedUsers, false, options.reports, true); // Update selectedOptions with the latest personalDetails information const detailsMap: Record = {}; @@ -75,7 +76,7 @@ function InviteReportParticipantsPage({betas, personalDetails, report, didScreen setRecentReports(inviteOptions.recentReports); setSelectedOptions(newSelectedOptions); // eslint-disable-next-line react-hooks/exhaustive-deps -- we don't want to recalculate when selectedOptions change - }, [personalDetails, betas, searchTerm, excludedUsers, options]); + }, [personalDetails, betas, debouncedSearchTerm, excludedUsers, options]); const sections = useMemo(() => { const sectionsArr: Sections = []; @@ -86,11 +87,11 @@ function InviteReportParticipantsPage({betas, personalDetails, report, didScreen // Filter all options that is a part of the search term or in the personal details let filterSelectedOptions = selectedOptions; - if (searchTerm !== '') { + if (debouncedSearchTerm !== '') { filterSelectedOptions = selectedOptions.filter((option) => { const accountID = option?.accountID; const isOptionInPersonalDetails = invitePersonalDetails.some((personalDetail) => accountID && personalDetail?.accountID === accountID); - const searchValue = OptionsListUtils.getSearchValueForPhoneOrEmail(searchTerm); + const searchValue = OptionsListUtils.getSearchValueForPhoneOrEmail(debouncedSearchTerm); const isPartOfSearchTerm = !!option.text?.toLowerCase().includes(searchValue) || !!option.login?.toLowerCase().includes(searchValue); return isPartOfSearchTerm || isOptionInPersonalDetails; }); @@ -128,7 +129,7 @@ function InviteReportParticipantsPage({betas, personalDetails, report, didScreen } return sectionsArr; - }, [invitePersonalDetails, searchTerm, selectedOptions, translate, userToInvite, areOptionsInitialized, recentReports]); + }, [invitePersonalDetails, debouncedSearchTerm, selectedOptions, translate, userToInvite, areOptionsInitialized, recentReports]); const toggleOption = useCallback( (option: OptionsListUtils.MemberForList) => { @@ -169,7 +170,7 @@ function InviteReportParticipantsPage({betas, personalDetails, report, didScreen }, [selectedOptions, backRoute, reportID, validate]); const headerMessage = useMemo(() => { - const searchValue = searchTerm.trim().toLowerCase(); + const searchValue = debouncedSearchTerm.trim().toLowerCase(); const expensifyEmails = CONST.EXPENSIFY_EMAILS as string[]; if (!userToInvite && expensifyEmails.includes(searchValue)) { return translate('messages.errorMessageInvalidEmail'); @@ -185,7 +186,7 @@ function InviteReportParticipantsPage({betas, personalDetails, report, didScreen return translate('messages.userIsAlreadyMember', {login: searchValue, name: reportName ?? ''}); } return OptionsListUtils.getHeaderMessage(invitePersonalDetails.length !== 0, Boolean(userToInvite), searchValue); - }, [searchTerm, userToInvite, excludedUsers, invitePersonalDetails, translate, reportName]); + }, [debouncedSearchTerm, userToInvite, excludedUsers, invitePersonalDetails, translate, reportName]); return ( ({ + __esModule: true, + default: { + ignoreLogs: jest.fn(), + ignoreAllLogs: jest.fn(), + }, +})); + +jest.mock('react-native-reanimated', () => ({ + ...jest.requireActual('react-native-reanimated/mock'), + createAnimatedPropAdapter: jest.fn, + useReducedMotion: jest.fn, +})); + +/** + * We need to keep track of the transitionEnd callback so we can trigger it in our tests + */ +let transitionEndCB: () => void; + +type ListenerMock = { + triggerTransitionEnd: () => void; + addListener: jest.Mock; +}; + +/** + * This is a helper function to create a mock for the addListener function of the react-navigation library. + * The reason we need this is because we need to trigger the transitionEnd event in our tests to simulate + * the transitionEnd event that is triggered when the screen transition animation is completed. + * + * P.S: This can't be moved to a utils file because Jest wants any external function to stay in the scope. + * + * @returns An object with two functions: triggerTransitionEnd and addListener + */ +const createAddListenerMock = (): ListenerMock => { + const transitionEndListeners: Array<() => void> = []; + const triggerTransitionEnd = () => { + transitionEndListeners.forEach((transitionEndListener) => transitionEndListener()); + }; + + const addListener: jest.Mock = jest.fn().mockImplementation((listener, callback) => { + if (listener === 'transitionEnd') { + transitionEndListeners.push(callback); + } + return () => { + // eslint-disable-next-line rulesdir/prefer-underscore-method + transitionEndListeners.filter((cb) => cb !== callback); + }; + }); + + return {triggerTransitionEnd, addListener}; +}; + +jest.mock('@react-navigation/native', () => { + const actualNav = jest.requireActual('@react-navigation/native'); + const {triggerTransitionEnd, addListener} = createAddListenerMock(); + transitionEndCB = triggerTransitionEnd; + + const useNavigation = () => + ({ + navigate: jest.fn(), + ...actualNav.useNavigation, + getState: () => ({ + routes: [], + }), + addListener, + } as typeof NativeNavigation.useNavigation); + + return { + ...actualNav, + useNavigation, + getState: () => ({ + routes: [], + }), + } as typeof NativeNavigation; +}); + +beforeAll(() => { + // In this test, we are generically mocking the responses of all API requests by mocking fetch() and having it + // return 200. In other tests, we might mock HttpUtils.xhr() with a more specific mock data response (which means + // fetch() never gets called so it does not need mocking) or we might have fetch throw an error to test error handling + // behavior. But here we just want to treat all API requests as a generic "success" and in the cases where we need to + // simulate data arriving we will just set it into Onyx directly with Onyx.merge() or Onyx.set() etc. + // @ts-expect-error -- TODO: Remove this once TestHelper (https://github.com/Expensify/App/issues/25318) is migrated + global.fetch = TestHelper.getGlobalFetchMock(); + + Linking.setInitialURL('https://new.expensify.com/'); + appSetup(); + + // Connect to Pusher + PusherConnectionManager.init(); + Pusher.init({ + appKey: CONFIG.PUSHER.APP_KEY, + cluster: CONFIG.PUSHER.CLUSTER, + authEndpoint: `${CONFIG.EXPENSIFY.DEFAULT_API_ROOT}api/AuthenticatePusher?`, + }); +}); + +async function navigateToSidebarOption(index: number): Promise { + const hintText = Localize.translateLocal('accessibilityHints.navigatesToChat'); + const optionRows = screen.queryAllByAccessibilityHint(hintText); + fireEvent(optionRows[index], 'press'); + await waitForBatchedUpdatesWithAct(); +} + +const REPORT_ID = '1'; +const USER_A_ACCOUNT_ID = 1; +const USER_A_EMAIL = 'user_a@test.com'; +const USER_B_ACCOUNT_ID = 2; +const USER_B_EMAIL = 'user_b@test.com'; +const USER_C_ACCOUNT_ID = 3; +const USER_C_EMAIL = 'user_c@test.com'; +const USER_D_ACCOUNT_ID = 4; +const USER_D_EMAIL = 'user_d@test.com'; +const USER_E_ACCOUNT_ID = 5; +const USER_E_EMAIL = 'user_e@test.com'; +const USER_F_ACCOUNT_ID = 6; +const USER_F_EMAIL = 'user_f@test.com'; +const USER_G_ACCOUNT_ID = 7; +const USER_G_EMAIL = 'user_g@test.com'; +const USER_H_ACCOUNT_ID = 8; +const USER_H_EMAIL = 'user_h@test.com'; +let reportActionCreatedDate: string; +let reportAction2CreatedDate: string; + +/** + * Sets up a test with a logged in user. Returns the test instance. + */ +function signInAndGetApp(reportName: string = "", participantAccountIDs?: number[], participants: Record = {}): Promise { + // Render the App and sign in as a test user. + render(); + return waitForBatchedUpdatesWithAct() + .then(async () => { + await waitForBatchedUpdatesWithAct(); + const hintText = Localize.translateLocal('loginForm.loginForm'); + const loginForm = screen.queryAllByLabelText(hintText); + expect(loginForm).toHaveLength(1); + + await act(async () => { + await TestHelper.signInWithTestUser(USER_A_ACCOUNT_ID, USER_A_EMAIL, undefined, undefined, 'A'); + }); + return waitForBatchedUpdatesWithAct(); + }) + .then(() => { + User.subscribeToUserEvents(); + return waitForBatchedUpdates(); + }) + .then(async () => { + const TEN_MINUTES_AGO = subMinutes(new Date(), 10); + reportActionCreatedDate = format(addSeconds(TEN_MINUTES_AGO, 30), CONST.DATE.FNS_DB_FORMAT_STRING); + reportAction2CreatedDate = format(addSeconds(TEN_MINUTES_AGO, 60), CONST.DATE.FNS_DB_FORMAT_STRING); + + // Simulate setting an unread report and personal details + await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${REPORT_ID}`, { + reportID: REPORT_ID, + reportName: reportName, + lastReadTime: reportActionCreatedDate, + lastVisibleActionCreated: reportAction2CreatedDate, + lastMessageText: 'Test', + groupChatAdminLogins: USER_A_EMAIL, + participantAccountIDs: participantAccountIDs, + participants: participants, + lastActorAccountID: USER_B_ACCOUNT_ID, + type: CONST.REPORT.TYPE.CHAT, + chatType: CONST.REPORT.CHAT_TYPE.GROUP, + }); + const createdReportActionID = NumberUtils.rand64().toString(); + await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${REPORT_ID}`, { + [createdReportActionID]: { + actionName: CONST.REPORT.ACTIONS.TYPE.CREATED, + automatic: false, + created: format(TEN_MINUTES_AGO, CONST.DATE.FNS_DB_FORMAT_STRING), + reportActionID: createdReportActionID, + message: [ + { + style: 'strong', + text: '__FAKE__', + type: 'TEXT', + }, + { + style: 'normal', + text: 'created this report', + type: 'TEXT', + }, + ], + }, + }); + + await Onyx.merge(ONYXKEYS.PERSONAL_DETAILS_LIST, { + [USER_A_ACCOUNT_ID]: TestHelper.buildPersonalDetails(USER_A_EMAIL, USER_A_ACCOUNT_ID, 'A'), + [USER_B_ACCOUNT_ID]: TestHelper.buildPersonalDetails(USER_B_EMAIL, USER_B_ACCOUNT_ID, 'B'), + [USER_C_ACCOUNT_ID]: TestHelper.buildPersonalDetails(USER_C_EMAIL, USER_C_ACCOUNT_ID, 'C'), + [USER_D_ACCOUNT_ID]: TestHelper.buildPersonalDetails(USER_D_EMAIL, USER_D_ACCOUNT_ID, 'D'), + [USER_E_ACCOUNT_ID]: TestHelper.buildPersonalDetails(USER_E_EMAIL, USER_E_ACCOUNT_ID, 'E'), + [USER_F_ACCOUNT_ID]: TestHelper.buildPersonalDetails(USER_F_EMAIL, USER_F_ACCOUNT_ID, 'F'), + [USER_G_ACCOUNT_ID]: TestHelper.buildPersonalDetails(USER_G_EMAIL, USER_G_ACCOUNT_ID, 'G'), + [USER_H_ACCOUNT_ID]: TestHelper.buildPersonalDetails(USER_H_EMAIL, USER_H_ACCOUNT_ID, 'H'), + }); + + // We manually setting the sidebar as loaded since the onLayout event does not fire in tests + AppActions.setSidebarLoaded(); + return waitForBatchedUpdatesWithAct(); + }); +} + +/** + * Tests for checking the group chat names at places like LHN, chat header, details page etc. + * Note that limit of 5 names is only for the header. + */ +describe('Tests for group chat name', () => { + afterEach(() => { + jest.clearAllMocks(); + Onyx.clear(); + + // Unsubscribe to pusher channels + PusherHelper.teardown(); + }); + + const participantAccountIDs4 = [USER_A_ACCOUNT_ID, USER_B_ACCOUNT_ID, USER_C_ACCOUNT_ID, USER_D_ACCOUNT_ID]; + const participants4 = { + [USER_A_ACCOUNT_ID]: {hidden: false, role: 'admin'}, + [USER_B_ACCOUNT_ID]: {hidden: false, role: 'member'}, + [USER_C_ACCOUNT_ID]: {hidden: false, role: 'member'}, + [USER_D_ACCOUNT_ID]: {hidden: false, role: 'member'}, + } + + const participantAccountIDs8 = [...participantAccountIDs4, USER_E_ACCOUNT_ID, USER_F_ACCOUNT_ID, USER_F_ACCOUNT_ID, USER_G_ACCOUNT_ID]; + const participants8 = { + ...participants4, + [USER_E_ACCOUNT_ID]: {hidden: false, role: 'member'}, + [USER_F_ACCOUNT_ID]: {hidden: false, role: 'member'}, + [USER_G_ACCOUNT_ID]: {hidden: false, role: 'member'}, + [USER_H_ACCOUNT_ID]: {hidden: false, role: 'member'}, + } + + it('Should show correctly in LHN', () => + signInAndGetApp("A, B, C, D", participantAccountIDs4, participants4) + .then(() => { + // Verify the sidebar links are rendered + const sidebarLinksHintText = Localize.translateLocal('sidebarScreen.listOfChats'); + const sidebarLinks = screen.queryAllByLabelText(sidebarLinksHintText); + expect(sidebarLinks).toHaveLength(1); + + // Verify there is only one option in the sidebar + const optionRowsHintText = Localize.translateLocal('accessibilityHints.navigatesToChat'); + const optionRows = screen.queryAllByAccessibilityHint(optionRowsHintText); + expect(optionRows).toHaveLength(1); + + const displayNameHintText = Localize.translateLocal('accessibilityHints.chatUserDisplayNames'); + const displayNameText = screen.queryByLabelText(displayNameHintText); + + return waitFor(() => expect(displayNameText?.props?.children?.[0]).toBe("A, B, C, D")); + })); + + it('Should show correctly in LHN when report name is not present', () => + signInAndGetApp("", participantAccountIDs4, participants4) + .then(() => { + // Verify the sidebar links are rendered + const sidebarLinksHintText = Localize.translateLocal('sidebarScreen.listOfChats'); + const sidebarLinks = screen.queryAllByLabelText(sidebarLinksHintText); + expect(sidebarLinks).toHaveLength(1); + + // Verify there is only one option in the sidebar + const optionRowsHintText = Localize.translateLocal('accessibilityHints.navigatesToChat'); + const optionRows = screen.queryAllByAccessibilityHint(optionRowsHintText); + expect(optionRows).toHaveLength(1); + + const displayNameHintText = Localize.translateLocal('accessibilityHints.chatUserDisplayNames'); + const displayNameText = screen.queryByLabelText(displayNameHintText); + + return waitFor(() => expect(displayNameText?.props?.children?.[0]).toBe("A, B, C, D")); + })); + + it('Should show all 8 names in LHN when 8 participants are present', () => + signInAndGetApp("", participantAccountIDs8, participants8) + .then(() => { + // Verify the sidebar links are rendered + const sidebarLinksHintText = Localize.translateLocal('sidebarScreen.listOfChats'); + const sidebarLinks = screen.queryAllByLabelText(sidebarLinksHintText); + expect(sidebarLinks).toHaveLength(1); + + // Verify there is only one option in the sidebar + const optionRowsHintText = Localize.translateLocal('accessibilityHints.navigatesToChat'); + const optionRows = screen.queryAllByAccessibilityHint(optionRowsHintText); + expect(optionRows).toHaveLength(1); + + const displayNameHintText = Localize.translateLocal('accessibilityHints.chatUserDisplayNames'); + const displayNameText = screen.queryByLabelText(displayNameHintText); + + return waitFor(() => expect(displayNameText?.props?.children?.[0]).toBe("A, B, C, D, E, F, G, H")); + })); + + it('Check if group name shows fine for report header', () => + signInAndGetApp("", participantAccountIDs4, participants4) + .then(() => { + // Verify the sidebar links are rendered + const sidebarLinksHintText = Localize.translateLocal('sidebarScreen.listOfChats'); + const sidebarLinks = screen.queryAllByLabelText(sidebarLinksHintText); + expect(sidebarLinks).toHaveLength(1); + + // Verify there is only one option in the sidebar + const optionRowsHintText = Localize.translateLocal('accessibilityHints.navigatesToChat'); + const optionRows = screen.queryAllByAccessibilityHint(optionRowsHintText); + expect(optionRows).toHaveLength(1); + + const displayNameHintText = Localize.translateLocal('accessibilityHints.chatUserDisplayNames'); + const displayNameText = screen.queryByLabelText(displayNameHintText); + + expect(displayNameText?.props?.children?.[0]).toBe("A, B, C, D"); + + return navigateToSidebarOption(0); + }) + .then(waitForBatchedUpdates) + .then(async () => { + await act(() => transitionEndCB?.()); + const name = "A, B, C, D"; + const displayNameTexts = screen.queryAllByLabelText(name); + return waitFor(() => expect(displayNameTexts).toHaveLength(1)); + })); + + it('Should show only 5 names when there are 8 participants in the report header', () => + signInAndGetApp("", participantAccountIDs8, participants8) + .then(() => { + // Verify the sidebar links are rendered + const sidebarLinksHintText = Localize.translateLocal('sidebarScreen.listOfChats'); + const sidebarLinks = screen.queryAllByLabelText(sidebarLinksHintText); + expect(sidebarLinks).toHaveLength(1); + + // Verify there is only one option in the sidebar + const optionRowsHintText = Localize.translateLocal('accessibilityHints.navigatesToChat'); + const optionRows = screen.queryAllByAccessibilityHint(optionRowsHintText); + expect(optionRows).toHaveLength(1); + + const displayNameHintText = Localize.translateLocal('accessibilityHints.chatUserDisplayNames'); + const displayNameText = screen.queryByLabelText(displayNameHintText); + + expect(displayNameText?.props?.children?.[0]).toBe("A, B, C, D, E, F, G, H"); + + return navigateToSidebarOption(0); + }) + .then(waitForBatchedUpdates) + .then(async () => { + await act(() => transitionEndCB?.()); + const name = "A, B, C, D, E"; + const displayNameTexts = screen.queryAllByLabelText(name); + return waitFor(() => expect(displayNameTexts).toHaveLength(1)); + })); + + it('Should show exact name in header when report name is available with 4 participants', () => + signInAndGetApp("Test chat", participantAccountIDs4, participants4) + .then(() => { + // Verify the sidebar links are rendered + const sidebarLinksHintText = Localize.translateLocal('sidebarScreen.listOfChats'); + const sidebarLinks = screen.queryAllByLabelText(sidebarLinksHintText); + expect(sidebarLinks).toHaveLength(1); + + // Verify there is only one option in the sidebar + const optionRowsHintText = Localize.translateLocal('accessibilityHints.navigatesToChat'); + const optionRows = screen.queryAllByAccessibilityHint(optionRowsHintText); + expect(optionRows).toHaveLength(1); + + const displayNameHintText = Localize.translateLocal('accessibilityHints.chatUserDisplayNames'); + const displayNameText = screen.queryByLabelText(displayNameHintText); + + expect(displayNameText?.props?.children?.[0]).toBe("Test chat"); + + return navigateToSidebarOption(0); + }) + .then(waitForBatchedUpdates) + .then(async () => { + await act(() => transitionEndCB?.()); + const name = "Test chat"; + const displayNameTexts = screen.queryAllByLabelText(name); + return waitFor(() => expect(displayNameTexts).toHaveLength(1)); + })); + + it('Should show exact name in header when report name is available with 8 participants', () => + signInAndGetApp("Let's talk", participantAccountIDs8, participants8) + .then(() => { + // Verify the sidebar links are rendered + const sidebarLinksHintText = Localize.translateLocal('sidebarScreen.listOfChats'); + const sidebarLinks = screen.queryAllByLabelText(sidebarLinksHintText); + expect(sidebarLinks).toHaveLength(1); + + // Verify there is only one option in the sidebar + const optionRowsHintText = Localize.translateLocal('accessibilityHints.navigatesToChat'); + const optionRows = screen.queryAllByAccessibilityHint(optionRowsHintText); + expect(optionRows).toHaveLength(1); + + const displayNameHintText = Localize.translateLocal('accessibilityHints.chatUserDisplayNames'); + const displayNameText = screen.queryByLabelText(displayNameHintText); + + expect(displayNameText?.props?.children?.[0]).toBe("Let's talk"); + + return navigateToSidebarOption(0); + }) + .then(waitForBatchedUpdates) + .then(async () => { + await act(() => transitionEndCB?.()); + const name = "Let's talk"; + const displayNameTexts = screen.queryAllByLabelText(name); + return waitFor(() => expect(displayNameTexts).toHaveLength(1)); + })); + + it('Should show last message preview in LHN', () => + signInAndGetApp("A, B, C, D", participantAccountIDs4, participants4) + .then(() => { + // Verify the sidebar links are rendered + const sidebarLinksHintText = Localize.translateLocal('sidebarScreen.listOfChats'); + const sidebarLinks = screen.queryAllByLabelText(sidebarLinksHintText); + expect(sidebarLinks).toHaveLength(1); + + // Verify there is only one option in the sidebar + const optionRowsHintText = Localize.translateLocal('accessibilityHints.navigatesToChat'); + const optionRows = screen.queryAllByAccessibilityHint(optionRowsHintText); + expect(optionRows).toHaveLength(1); + + const lastChatHintText = Localize.translateLocal('accessibilityHints.lastChatMessagePreview'); + const lastChatText = screen.queryByLabelText(lastChatHintText); + + return waitFor(() => expect(lastChatText?.props?.children).toBe("B: Test")); + })); + + it('Should sort the names before displaying', () => + signInAndGetApp("", [USER_E_ACCOUNT_ID, ...participantAccountIDs4], { + [USER_E_ACCOUNT_ID]: { + hidden: false, + role: 'member' + }, ...participants4, + }) + .then(() => { + // Verify the sidebar links are rendered + const sidebarLinksHintText = Localize.translateLocal('sidebarScreen.listOfChats'); + const sidebarLinks = screen.queryAllByLabelText(sidebarLinksHintText); + expect(sidebarLinks).toHaveLength(1); + + // Verify there is only one option in the sidebar + const optionRowsHintText = Localize.translateLocal('accessibilityHints.navigatesToChat'); + const optionRows = screen.queryAllByAccessibilityHint(optionRowsHintText); + expect(optionRows).toHaveLength(1); + + const displayNameHintText = Localize.translateLocal('accessibilityHints.chatUserDisplayNames'); + const displayNameText = screen.queryByLabelText(displayNameHintText); + + return waitFor(() => expect(displayNameText?.props?.children?.[0]).toBe("A, B, C, D, E")); + })); +}); diff --git a/tests/unit/ReportUtilsTest.ts b/tests/unit/ReportUtilsTest.ts index 0ed28ea84fcb9..40cb0b15850f9 100644 --- a/tests/unit/ReportUtilsTest.ts +++ b/tests/unit/ReportUtilsTest.ts @@ -9,6 +9,7 @@ import {toCollectionDataSet} from '@src/types/utils/CollectionDataSet'; import * as NumberUtils from '../../src/libs/NumberUtils'; import * as LHNTestUtils from '../utils/LHNTestUtils'; import waitForBatchedUpdates from '../utils/waitForBatchedUpdates'; +import {fakePersonalDetails} from "../utils/LHNTestUtils"; // Be sure to include the mocked permissions library or else the beta tests won't work jest.mock('@libs/Permissions'); @@ -825,4 +826,110 @@ describe('ReportUtils', () => { expect(ReportUtils.getAllAncestorReportActions(reports[4])).toEqual(resultAncestors); }); }); + + describe('getGroupChatName tests', () => { + afterEach(() => Onyx.clear()); + + describe('When participantAccountIDs is passed to getGroupChatName', () => { + it('Should show all participants name if count <= 5 and shouldApplyLimit is false', async function () { + const report = { + ...LHNTestUtils.getFakeReport([1, 2, 3, 4]), + chatType: CONST.REPORT.CHAT_TYPE.GROUP, + }; + + await Onyx.merge(ONYXKEYS.PERSONAL_DETAILS_LIST, fakePersonalDetails); + expect(ReportUtils.getGroupChatName(report?.participantAccountIDs ?? [])).toEqual("Four, One, Three, Two"); + }); + + it('Should show all participants name if count <= 5 and shouldApplyLimit is true', async function () { + const report = { + ...LHNTestUtils.getFakeReport([1, 2, 3, 4]), + chatType: CONST.REPORT.CHAT_TYPE.GROUP, + }; + + await Onyx.merge(ONYXKEYS.PERSONAL_DETAILS_LIST, fakePersonalDetails); + expect(ReportUtils.getGroupChatName(report?.participantAccountIDs ?? [], true)).toEqual("Four, One, Three, Two"); + }); + + it('Should show 5 participants name if count > 5 and shouldApplyLimit is true', async function () { + const report = { + ...LHNTestUtils.getFakeReport([1, 2, 3, 4, 5, 6, 7, 8]), + chatType: CONST.REPORT.CHAT_TYPE.GROUP, + }; + + await Onyx.merge(ONYXKEYS.PERSONAL_DETAILS_LIST, fakePersonalDetails); + expect(ReportUtils.getGroupChatName(report?.participantAccountIDs ?? [], true)).toEqual("Five, Four, One, Three, Two"); + }); + + it('Should show all participants name if count > 5 and shouldApplyLimit is false', async function () { + const report = { + ...LHNTestUtils.getFakeReport([1, 2, 3, 4, 5, 6, 7, 8]), + chatType: CONST.REPORT.CHAT_TYPE.GROUP, + }; + + await Onyx.merge(ONYXKEYS.PERSONAL_DETAILS_LIST, fakePersonalDetails); + expect(ReportUtils.getGroupChatName(report?.participantAccountIDs ?? [], false)).toEqual("Eight, Five, Four, One, Seven, Six, Three, Two"); + }); + + it('Should use correct display name for participants', async function () { + const report = { + ...LHNTestUtils.getFakeReport([1, 2, 3, 4]), + chatType: CONST.REPORT.CHAT_TYPE.GROUP, + }; + + await Onyx.merge(ONYXKEYS.PERSONAL_DETAILS_LIST, participantsPersonalDetails); + expect(ReportUtils.getGroupChatName(report?.participantAccountIDs ?? [], true)).toEqual("(833) 240-3627, floki@vikings.net, Lagertha, Ragnar"); + }); + }); + + describe('When participantAccountIDs is not passed to getGroupChatName and report ID is passed', () => { + it('Should show report name if count <= 5 and shouldApplyLimit is false', async function () { + const report = { + ...LHNTestUtils.getFakeReport([1, 2, 3, 4]), + chatType: CONST.REPORT.CHAT_TYPE.GROUP, + reportID: `1`, + reportName: "Let's talk", + }; + await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}1`, report); + await Onyx.merge(ONYXKEYS.PERSONAL_DETAILS_LIST, fakePersonalDetails); + expect(ReportUtils.getGroupChatName(undefined, false, '1')).toEqual("Let's talk"); + }); + + it('Should show report name if count <= 5 and shouldApplyLimit is true', async function () { + const report = { + ...LHNTestUtils.getFakeReport([1, 2, 3, 4]), + chatType: CONST.REPORT.CHAT_TYPE.GROUP, + reportID: `1`, + reportName: "Let's talk", + }; + await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}1`, report); + await Onyx.merge(ONYXKEYS.PERSONAL_DETAILS_LIST, fakePersonalDetails); + expect(ReportUtils.getGroupChatName(undefined, true, '1')).toEqual("Let's talk"); + }); + + it('Should show report name if count > 5 and shouldApplyLimit is true', async function () { + const report = { + ...LHNTestUtils.getFakeReport([1, 2, 3, 4, 5, 6, 7, 8]), + chatType: CONST.REPORT.CHAT_TYPE.GROUP, + reportID: `1`, + reportName: "Let's talk", + }; + await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}1`, report); + await Onyx.merge(ONYXKEYS.PERSONAL_DETAILS_LIST, fakePersonalDetails); + expect(ReportUtils.getGroupChatName(undefined, true, '1')).toEqual("Let's talk"); + }); + + it('Should show report name if count > 5 and shouldApplyLimit is false', async function () { + const report = { + ...LHNTestUtils.getFakeReport([1, 2, 3, 4, 5, 6, 7, 8]), + chatType: CONST.REPORT.CHAT_TYPE.GROUP, + reportID: `1`, + reportName: "Let's talk", + }; + await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}1`, report); + await Onyx.merge(ONYXKEYS.PERSONAL_DETAILS_LIST, fakePersonalDetails); + expect(ReportUtils.getGroupChatName(undefined, false, '1')).toEqual("Let's talk"); + }); + }); + }); }); diff --git a/tests/utils/LHNTestUtils.tsx b/tests/utils/LHNTestUtils.tsx index 248b0f946edc1..d92e3f1665c19 100644 --- a/tests/utils/LHNTestUtils.tsx +++ b/tests/utils/LHNTestUtils.tsx @@ -110,6 +110,13 @@ const fakePersonalDetails: PersonalDetailsList = { avatar: 'none', firstName: 'Nine', }, + 10: { + accountID: 10, + login: 'email10@test.com', + displayName: 'Email Ten', + avatar: 'none', + firstName: 'Ten', + }, }; let lastFakeReportID = 0; From 46c5110893297eba8dc2ff16cdd528631b0a616d Mon Sep 17 00:00:00 2001 From: ShridharGoel <35566748+ShridharGoel@users.noreply.github.com> Date: Sun, 21 Apr 2024 23:08:49 +0530 Subject: [PATCH 02/12] Update --- tests/ui/GroupChatNameTests.tsx | 182 ++++++++++++++++---------------- tests/unit/ReportUtilsTest.ts | 30 +++--- 2 files changed, 104 insertions(+), 108 deletions(-) diff --git a/tests/ui/GroupChatNameTests.tsx b/tests/ui/GroupChatNameTests.tsx index 7d40abd4c3f24..e589fa6c005e5 100644 --- a/tests/ui/GroupChatNameTests.tsx +++ b/tests/ui/GroupChatNameTests.tsx @@ -17,11 +17,11 @@ import CONFIG from '@src/CONFIG'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import appSetup from '@src/setup'; +import type Participant from '@src/types/onyx/Report'; import PusherHelper from '../utils/PusherHelper'; import * as TestHelper from '../utils/TestHelper'; import waitForBatchedUpdates from '../utils/waitForBatchedUpdates'; import waitForBatchedUpdatesWithAct from '../utils/waitForBatchedUpdatesWithAct'; -import {Participant} from "@src/types/onyx/Report"; // We need a large timeout here as we are lazy loading React Navigation screens and this test is running against the entire mounted App jest.setTimeout(50000); @@ -158,9 +158,9 @@ let reportAction2CreatedDate: string; /** * Sets up a test with a logged in user. Returns the test instance. */ -function signInAndGetApp(reportName: string = "", participantAccountIDs?: number[], participants: Record = {}): Promise { +function signInAndGetApp(reportName = '', participantAccountIDs?: number[], participants: Record = {}): Promise { // Render the App and sign in as a test user. - render(); + render(); return waitForBatchedUpdatesWithAct() .then(async () => { await waitForBatchedUpdatesWithAct(); @@ -185,13 +185,13 @@ function signInAndGetApp(reportName: string = "", participantAccountIDs?: number // Simulate setting an unread report and personal details await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${REPORT_ID}`, { reportID: REPORT_ID, - reportName: reportName, + reportName, lastReadTime: reportActionCreatedDate, lastVisibleActionCreated: reportAction2CreatedDate, lastMessageText: 'Test', groupChatAdminLogins: USER_A_EMAIL, - participantAccountIDs: participantAccountIDs, - participants: participants, + participantAccountIDs, + participants, lastActorAccountID: USER_B_ACCOUNT_ID, type: CONST.REPORT.TYPE.CHAT, chatType: CONST.REPORT.CHAT_TYPE.GROUP, @@ -254,7 +254,7 @@ describe('Tests for group chat name', () => { [USER_B_ACCOUNT_ID]: {hidden: false, role: 'member'}, [USER_C_ACCOUNT_ID]: {hidden: false, role: 'member'}, [USER_D_ACCOUNT_ID]: {hidden: false, role: 'member'}, - } + }; const participantAccountIDs8 = [...participantAccountIDs4, USER_E_ACCOUNT_ID, USER_F_ACCOUNT_ID, USER_F_ACCOUNT_ID, USER_G_ACCOUNT_ID]; const participants8 = { @@ -263,67 +263,64 @@ describe('Tests for group chat name', () => { [USER_F_ACCOUNT_ID]: {hidden: false, role: 'member'}, [USER_G_ACCOUNT_ID]: {hidden: false, role: 'member'}, [USER_H_ACCOUNT_ID]: {hidden: false, role: 'member'}, - } + }; it('Should show correctly in LHN', () => - signInAndGetApp("A, B, C, D", participantAccountIDs4, participants4) - .then(() => { - // Verify the sidebar links are rendered - const sidebarLinksHintText = Localize.translateLocal('sidebarScreen.listOfChats'); - const sidebarLinks = screen.queryAllByLabelText(sidebarLinksHintText); - expect(sidebarLinks).toHaveLength(1); + signInAndGetApp('A, B, C, D', participantAccountIDs4, participants4).then(() => { + // Verify the sidebar links are rendered + const sidebarLinksHintText = Localize.translateLocal('sidebarScreen.listOfChats'); + const sidebarLinks = screen.queryAllByLabelText(sidebarLinksHintText); + expect(sidebarLinks).toHaveLength(1); - // Verify there is only one option in the sidebar - const optionRowsHintText = Localize.translateLocal('accessibilityHints.navigatesToChat'); - const optionRows = screen.queryAllByAccessibilityHint(optionRowsHintText); - expect(optionRows).toHaveLength(1); + // Verify there is only one option in the sidebar + const optionRowsHintText = Localize.translateLocal('accessibilityHints.navigatesToChat'); + const optionRows = screen.queryAllByAccessibilityHint(optionRowsHintText); + expect(optionRows).toHaveLength(1); - const displayNameHintText = Localize.translateLocal('accessibilityHints.chatUserDisplayNames'); - const displayNameText = screen.queryByLabelText(displayNameHintText); + const displayNameHintText = Localize.translateLocal('accessibilityHints.chatUserDisplayNames'); + const displayNameText = screen.queryByLabelText(displayNameHintText); - return waitFor(() => expect(displayNameText?.props?.children?.[0]).toBe("A, B, C, D")); - })); + return waitFor(() => expect(displayNameText?.props?.children?.[0]).toBe('A, B, C, D')); + })); it('Should show correctly in LHN when report name is not present', () => - signInAndGetApp("", participantAccountIDs4, participants4) - .then(() => { - // Verify the sidebar links are rendered - const sidebarLinksHintText = Localize.translateLocal('sidebarScreen.listOfChats'); - const sidebarLinks = screen.queryAllByLabelText(sidebarLinksHintText); - expect(sidebarLinks).toHaveLength(1); + signInAndGetApp('', participantAccountIDs4, participants4).then(() => { + // Verify the sidebar links are rendered + const sidebarLinksHintText = Localize.translateLocal('sidebarScreen.listOfChats'); + const sidebarLinks = screen.queryAllByLabelText(sidebarLinksHintText); + expect(sidebarLinks).toHaveLength(1); - // Verify there is only one option in the sidebar - const optionRowsHintText = Localize.translateLocal('accessibilityHints.navigatesToChat'); - const optionRows = screen.queryAllByAccessibilityHint(optionRowsHintText); - expect(optionRows).toHaveLength(1); + // Verify there is only one option in the sidebar + const optionRowsHintText = Localize.translateLocal('accessibilityHints.navigatesToChat'); + const optionRows = screen.queryAllByAccessibilityHint(optionRowsHintText); + expect(optionRows).toHaveLength(1); - const displayNameHintText = Localize.translateLocal('accessibilityHints.chatUserDisplayNames'); - const displayNameText = screen.queryByLabelText(displayNameHintText); + const displayNameHintText = Localize.translateLocal('accessibilityHints.chatUserDisplayNames'); + const displayNameText = screen.queryByLabelText(displayNameHintText); - return waitFor(() => expect(displayNameText?.props?.children?.[0]).toBe("A, B, C, D")); - })); + return waitFor(() => expect(displayNameText?.props?.children?.[0]).toBe('A, B, C, D')); + })); it('Should show all 8 names in LHN when 8 participants are present', () => - signInAndGetApp("", participantAccountIDs8, participants8) - .then(() => { - // Verify the sidebar links are rendered - const sidebarLinksHintText = Localize.translateLocal('sidebarScreen.listOfChats'); - const sidebarLinks = screen.queryAllByLabelText(sidebarLinksHintText); - expect(sidebarLinks).toHaveLength(1); + signInAndGetApp('', participantAccountIDs8, participants8).then(() => { + // Verify the sidebar links are rendered + const sidebarLinksHintText = Localize.translateLocal('sidebarScreen.listOfChats'); + const sidebarLinks = screen.queryAllByLabelText(sidebarLinksHintText); + expect(sidebarLinks).toHaveLength(1); - // Verify there is only one option in the sidebar - const optionRowsHintText = Localize.translateLocal('accessibilityHints.navigatesToChat'); - const optionRows = screen.queryAllByAccessibilityHint(optionRowsHintText); - expect(optionRows).toHaveLength(1); + // Verify there is only one option in the sidebar + const optionRowsHintText = Localize.translateLocal('accessibilityHints.navigatesToChat'); + const optionRows = screen.queryAllByAccessibilityHint(optionRowsHintText); + expect(optionRows).toHaveLength(1); - const displayNameHintText = Localize.translateLocal('accessibilityHints.chatUserDisplayNames'); - const displayNameText = screen.queryByLabelText(displayNameHintText); + const displayNameHintText = Localize.translateLocal('accessibilityHints.chatUserDisplayNames'); + const displayNameText = screen.queryByLabelText(displayNameHintText); - return waitFor(() => expect(displayNameText?.props?.children?.[0]).toBe("A, B, C, D, E, F, G, H")); - })); + return waitFor(() => expect(displayNameText?.props?.children?.[0]).toBe('A, B, C, D, E, F, G, H')); + })); it('Check if group name shows fine for report header', () => - signInAndGetApp("", participantAccountIDs4, participants4) + signInAndGetApp('', participantAccountIDs4, participants4) .then(() => { // Verify the sidebar links are rendered const sidebarLinksHintText = Localize.translateLocal('sidebarScreen.listOfChats'); @@ -338,20 +335,20 @@ describe('Tests for group chat name', () => { const displayNameHintText = Localize.translateLocal('accessibilityHints.chatUserDisplayNames'); const displayNameText = screen.queryByLabelText(displayNameHintText); - expect(displayNameText?.props?.children?.[0]).toBe("A, B, C, D"); + expect(displayNameText?.props?.children?.[0]).toBe('A, B, C, D'); return navigateToSidebarOption(0); }) .then(waitForBatchedUpdates) .then(async () => { await act(() => transitionEndCB?.()); - const name = "A, B, C, D"; + const name = 'A, B, C, D'; const displayNameTexts = screen.queryAllByLabelText(name); return waitFor(() => expect(displayNameTexts).toHaveLength(1)); })); it('Should show only 5 names when there are 8 participants in the report header', () => - signInAndGetApp("", participantAccountIDs8, participants8) + signInAndGetApp('', participantAccountIDs8, participants8) .then(() => { // Verify the sidebar links are rendered const sidebarLinksHintText = Localize.translateLocal('sidebarScreen.listOfChats'); @@ -366,20 +363,20 @@ describe('Tests for group chat name', () => { const displayNameHintText = Localize.translateLocal('accessibilityHints.chatUserDisplayNames'); const displayNameText = screen.queryByLabelText(displayNameHintText); - expect(displayNameText?.props?.children?.[0]).toBe("A, B, C, D, E, F, G, H"); + expect(displayNameText?.props?.children?.[0]).toBe('A, B, C, D, E, F, G, H'); return navigateToSidebarOption(0); }) .then(waitForBatchedUpdates) .then(async () => { await act(() => transitionEndCB?.()); - const name = "A, B, C, D, E"; + const name = 'A, B, C, D, E'; const displayNameTexts = screen.queryAllByLabelText(name); return waitFor(() => expect(displayNameTexts).toHaveLength(1)); })); it('Should show exact name in header when report name is available with 4 participants', () => - signInAndGetApp("Test chat", participantAccountIDs4, participants4) + signInAndGetApp('Test chat', participantAccountIDs4, participants4) .then(() => { // Verify the sidebar links are rendered const sidebarLinksHintText = Localize.translateLocal('sidebarScreen.listOfChats'); @@ -394,14 +391,14 @@ describe('Tests for group chat name', () => { const displayNameHintText = Localize.translateLocal('accessibilityHints.chatUserDisplayNames'); const displayNameText = screen.queryByLabelText(displayNameHintText); - expect(displayNameText?.props?.children?.[0]).toBe("Test chat"); + expect(displayNameText?.props?.children?.[0]).toBe('Test chat'); return navigateToSidebarOption(0); }) .then(waitForBatchedUpdates) .then(async () => { await act(() => transitionEndCB?.()); - const name = "Test chat"; + const name = 'Test chat'; const displayNameTexts = screen.queryAllByLabelText(name); return waitFor(() => expect(displayNameTexts).toHaveLength(1)); })); @@ -435,45 +432,44 @@ describe('Tests for group chat name', () => { })); it('Should show last message preview in LHN', () => - signInAndGetApp("A, B, C, D", participantAccountIDs4, participants4) - .then(() => { - // Verify the sidebar links are rendered - const sidebarLinksHintText = Localize.translateLocal('sidebarScreen.listOfChats'); - const sidebarLinks = screen.queryAllByLabelText(sidebarLinksHintText); - expect(sidebarLinks).toHaveLength(1); + signInAndGetApp('A, B, C, D', participantAccountIDs4, participants4).then(() => { + // Verify the sidebar links are rendered + const sidebarLinksHintText = Localize.translateLocal('sidebarScreen.listOfChats'); + const sidebarLinks = screen.queryAllByLabelText(sidebarLinksHintText); + expect(sidebarLinks).toHaveLength(1); - // Verify there is only one option in the sidebar - const optionRowsHintText = Localize.translateLocal('accessibilityHints.navigatesToChat'); - const optionRows = screen.queryAllByAccessibilityHint(optionRowsHintText); - expect(optionRows).toHaveLength(1); + // Verify there is only one option in the sidebar + const optionRowsHintText = Localize.translateLocal('accessibilityHints.navigatesToChat'); + const optionRows = screen.queryAllByAccessibilityHint(optionRowsHintText); + expect(optionRows).toHaveLength(1); - const lastChatHintText = Localize.translateLocal('accessibilityHints.lastChatMessagePreview'); - const lastChatText = screen.queryByLabelText(lastChatHintText); + const lastChatHintText = Localize.translateLocal('accessibilityHints.lastChatMessagePreview'); + const lastChatText = screen.queryByLabelText(lastChatHintText); - return waitFor(() => expect(lastChatText?.props?.children).toBe("B: Test")); - })); + return waitFor(() => expect(lastChatText?.props?.children).toBe('B: Test')); + })); it('Should sort the names before displaying', () => - signInAndGetApp("", [USER_E_ACCOUNT_ID, ...participantAccountIDs4], { + signInAndGetApp('', [USER_E_ACCOUNT_ID, ...participantAccountIDs4], { [USER_E_ACCOUNT_ID]: { hidden: false, - role: 'member' - }, ...participants4, - }) - .then(() => { - // Verify the sidebar links are rendered - const sidebarLinksHintText = Localize.translateLocal('sidebarScreen.listOfChats'); - const sidebarLinks = screen.queryAllByLabelText(sidebarLinksHintText); - expect(sidebarLinks).toHaveLength(1); - - // Verify there is only one option in the sidebar - const optionRowsHintText = Localize.translateLocal('accessibilityHints.navigatesToChat'); - const optionRows = screen.queryAllByAccessibilityHint(optionRowsHintText); - expect(optionRows).toHaveLength(1); - - const displayNameHintText = Localize.translateLocal('accessibilityHints.chatUserDisplayNames'); - const displayNameText = screen.queryByLabelText(displayNameHintText); - - return waitFor(() => expect(displayNameText?.props?.children?.[0]).toBe("A, B, C, D, E")); - })); + role: 'member', + }, + ...participants4, + }).then(() => { + // Verify the sidebar links are rendered + const sidebarLinksHintText = Localize.translateLocal('sidebarScreen.listOfChats'); + const sidebarLinks = screen.queryAllByLabelText(sidebarLinksHintText); + expect(sidebarLinks).toHaveLength(1); + + // Verify there is only one option in the sidebar + const optionRowsHintText = Localize.translateLocal('accessibilityHints.navigatesToChat'); + const optionRows = screen.queryAllByAccessibilityHint(optionRowsHintText); + expect(optionRows).toHaveLength(1); + + const displayNameHintText = Localize.translateLocal('accessibilityHints.chatUserDisplayNames'); + const displayNameText = screen.queryByLabelText(displayNameHintText); + + return waitFor(() => expect(displayNameText?.props?.children?.[0]).toBe('A, B, C, D, E')); + })); }); diff --git a/tests/unit/ReportUtilsTest.ts b/tests/unit/ReportUtilsTest.ts index 40cb0b15850f9..e87d1843d88fd 100644 --- a/tests/unit/ReportUtilsTest.ts +++ b/tests/unit/ReportUtilsTest.ts @@ -8,8 +8,8 @@ import type {PersonalDetailsList, Policy, Report, ReportAction} from '@src/types import {toCollectionDataSet} from '@src/types/utils/CollectionDataSet'; import * as NumberUtils from '../../src/libs/NumberUtils'; import * as LHNTestUtils from '../utils/LHNTestUtils'; +import {fakePersonalDetails} from '../utils/LHNTestUtils'; import waitForBatchedUpdates from '../utils/waitForBatchedUpdates'; -import {fakePersonalDetails} from "../utils/LHNTestUtils"; // Be sure to include the mocked permissions library or else the beta tests won't work jest.mock('@libs/Permissions'); @@ -831,59 +831,59 @@ describe('ReportUtils', () => { afterEach(() => Onyx.clear()); describe('When participantAccountIDs is passed to getGroupChatName', () => { - it('Should show all participants name if count <= 5 and shouldApplyLimit is false', async function () { + it('Should show all participants name if count <= 5 and shouldApplyLimit is false', async () => { const report = { ...LHNTestUtils.getFakeReport([1, 2, 3, 4]), chatType: CONST.REPORT.CHAT_TYPE.GROUP, }; await Onyx.merge(ONYXKEYS.PERSONAL_DETAILS_LIST, fakePersonalDetails); - expect(ReportUtils.getGroupChatName(report?.participantAccountIDs ?? [])).toEqual("Four, One, Three, Two"); + expect(ReportUtils.getGroupChatName(report?.participantAccountIDs ?? [])).toEqual('Four, One, Three, Two'); }); - it('Should show all participants name if count <= 5 and shouldApplyLimit is true', async function () { + it('Should show all participants name if count <= 5 and shouldApplyLimit is true', async () => { const report = { ...LHNTestUtils.getFakeReport([1, 2, 3, 4]), chatType: CONST.REPORT.CHAT_TYPE.GROUP, }; await Onyx.merge(ONYXKEYS.PERSONAL_DETAILS_LIST, fakePersonalDetails); - expect(ReportUtils.getGroupChatName(report?.participantAccountIDs ?? [], true)).toEqual("Four, One, Three, Two"); + expect(ReportUtils.getGroupChatName(report?.participantAccountIDs ?? [], true)).toEqual('Four, One, Three, Two'); }); - it('Should show 5 participants name if count > 5 and shouldApplyLimit is true', async function () { + it('Should show 5 participants name if count > 5 and shouldApplyLimit is true', async () => { const report = { ...LHNTestUtils.getFakeReport([1, 2, 3, 4, 5, 6, 7, 8]), chatType: CONST.REPORT.CHAT_TYPE.GROUP, }; await Onyx.merge(ONYXKEYS.PERSONAL_DETAILS_LIST, fakePersonalDetails); - expect(ReportUtils.getGroupChatName(report?.participantAccountIDs ?? [], true)).toEqual("Five, Four, One, Three, Two"); + expect(ReportUtils.getGroupChatName(report?.participantAccountIDs ?? [], true)).toEqual('Five, Four, One, Three, Two'); }); - it('Should show all participants name if count > 5 and shouldApplyLimit is false', async function () { + it('Should show all participants name if count > 5 and shouldApplyLimit is false', async () => { const report = { ...LHNTestUtils.getFakeReport([1, 2, 3, 4, 5, 6, 7, 8]), chatType: CONST.REPORT.CHAT_TYPE.GROUP, }; await Onyx.merge(ONYXKEYS.PERSONAL_DETAILS_LIST, fakePersonalDetails); - expect(ReportUtils.getGroupChatName(report?.participantAccountIDs ?? [], false)).toEqual("Eight, Five, Four, One, Seven, Six, Three, Two"); + expect(ReportUtils.getGroupChatName(report?.participantAccountIDs ?? [], false)).toEqual('Eight, Five, Four, One, Seven, Six, Three, Two'); }); - it('Should use correct display name for participants', async function () { + it('Should use correct display name for participants', async () => { const report = { ...LHNTestUtils.getFakeReport([1, 2, 3, 4]), chatType: CONST.REPORT.CHAT_TYPE.GROUP, }; await Onyx.merge(ONYXKEYS.PERSONAL_DETAILS_LIST, participantsPersonalDetails); - expect(ReportUtils.getGroupChatName(report?.participantAccountIDs ?? [], true)).toEqual("(833) 240-3627, floki@vikings.net, Lagertha, Ragnar"); + expect(ReportUtils.getGroupChatName(report?.participantAccountIDs ?? [], true)).toEqual('(833) 240-3627, floki@vikings.net, Lagertha, Ragnar'); }); }); describe('When participantAccountIDs is not passed to getGroupChatName and report ID is passed', () => { - it('Should show report name if count <= 5 and shouldApplyLimit is false', async function () { + it('Should show report name if count <= 5 and shouldApplyLimit is false', async () => { const report = { ...LHNTestUtils.getFakeReport([1, 2, 3, 4]), chatType: CONST.REPORT.CHAT_TYPE.GROUP, @@ -895,7 +895,7 @@ describe('ReportUtils', () => { expect(ReportUtils.getGroupChatName(undefined, false, '1')).toEqual("Let's talk"); }); - it('Should show report name if count <= 5 and shouldApplyLimit is true', async function () { + it('Should show report name if count <= 5 and shouldApplyLimit is true', async () => { const report = { ...LHNTestUtils.getFakeReport([1, 2, 3, 4]), chatType: CONST.REPORT.CHAT_TYPE.GROUP, @@ -907,7 +907,7 @@ describe('ReportUtils', () => { expect(ReportUtils.getGroupChatName(undefined, true, '1')).toEqual("Let's talk"); }); - it('Should show report name if count > 5 and shouldApplyLimit is true', async function () { + it('Should show report name if count > 5 and shouldApplyLimit is true', async () => { const report = { ...LHNTestUtils.getFakeReport([1, 2, 3, 4, 5, 6, 7, 8]), chatType: CONST.REPORT.CHAT_TYPE.GROUP, @@ -919,7 +919,7 @@ describe('ReportUtils', () => { expect(ReportUtils.getGroupChatName(undefined, true, '1')).toEqual("Let's talk"); }); - it('Should show report name if count > 5 and shouldApplyLimit is false', async function () { + it('Should show report name if count > 5 and shouldApplyLimit is false', async () => { const report = { ...LHNTestUtils.getFakeReport([1, 2, 3, 4, 5, 6, 7, 8]), chatType: CONST.REPORT.CHAT_TYPE.GROUP, From 70da623fba3c4dea7b129a940817c5d56bff1ddf Mon Sep 17 00:00:00 2001 From: ShridharGoel <35566748+ShridharGoel@users.noreply.github.com> Date: Mon, 6 May 2024 19:08:01 +0530 Subject: [PATCH 03/12] Update --- tests/ui/GroupChatNameTests.tsx | 101 ++++++++------------------------ tests/unit/ReportUtilsTest.ts | 12 ++++ tests/utils/LHNTestUtils.tsx | 11 ++++ 3 files changed, 46 insertions(+), 78 deletions(-) diff --git a/tests/ui/GroupChatNameTests.tsx b/tests/ui/GroupChatNameTests.tsx index e589fa6c005e5..dcfcf4383b9dd 100644 --- a/tests/ui/GroupChatNameTests.tsx +++ b/tests/ui/GroupChatNameTests.tsx @@ -1,23 +1,18 @@ -/* eslint-disable @typescript-eslint/naming-convention */ +/* eslint-disable testing-library/no-node-access */ import type * as NativeNavigation from '@react-navigation/native'; import {act, fireEvent, render, screen, waitFor} from '@testing-library/react-native'; -import {addSeconds, format, subMinutes} from 'date-fns'; import React from 'react'; import {Linking} from 'react-native'; import Onyx from 'react-native-onyx'; import type Animated from 'react-native-reanimated'; import * as Localize from '@libs/Localize'; -import * as NumberUtils from '@libs/NumberUtils'; -import * as Pusher from '@libs/Pusher/pusher'; -import PusherConnectionManager from '@libs/PusherConnectionManager'; import * as AppActions from '@userActions/App'; import * as User from '@userActions/User'; import App from '@src/App'; -import CONFIG from '@src/CONFIG'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import appSetup from '@src/setup'; -import type Participant from '@src/types/onyx/Report'; +import type {Participant} from '@src/types/onyx/Report'; import PusherHelper from '../utils/PusherHelper'; import * as TestHelper from '../utils/TestHelper'; import waitForBatchedUpdates from '../utils/waitForBatchedUpdates'; @@ -26,12 +21,11 @@ import waitForBatchedUpdatesWithAct from '../utils/waitForBatchedUpdatesWithAct' // We need a large timeout here as we are lazy loading React Navigation screens and this test is running against the entire mounted App jest.setTimeout(50000); -jest.mock('../../src/libs/Notification/LocalNotification'); -jest.mock('../../src/components/Icon/Expensicons'); jest.mock('../../src/components/ConfirmedRoute.tsx'); // Needed for: https://stackoverflow.com/questions/76903168/mocking-libraries-in-jest jest.mock('react-native/Libraries/LogBox/LogBox', () => ({ + /* eslint-disable-next-line @typescript-eslint/naming-convention */ __esModule: true, default: { ignoreLogs: jest.fn(), @@ -118,14 +112,6 @@ beforeAll(() => { Linking.setInitialURL('https://new.expensify.com/'); appSetup(); - - // Connect to Pusher - PusherConnectionManager.init(); - Pusher.init({ - appKey: CONFIG.PUSHER.APP_KEY, - cluster: CONFIG.PUSHER.CLUSTER, - authEndpoint: `${CONFIG.EXPENSIFY.DEFAULT_API_ROOT}api/AuthenticatePusher?`, - }); }); async function navigateToSidebarOption(index: number): Promise { @@ -152,15 +138,22 @@ const USER_G_ACCOUNT_ID = 7; const USER_G_EMAIL = 'user_g@test.com'; const USER_H_ACCOUNT_ID = 8; const USER_H_EMAIL = 'user_h@test.com'; -let reportActionCreatedDate: string; -let reportAction2CreatedDate: string; /** * Sets up a test with a logged in user. Returns the test instance. */ -function signInAndGetApp(reportName = '', participantAccountIDs?: number[], participants: Record = {}): Promise { +function signInAndGetApp(reportName = '', participantAccountIDs?: number[]): Promise { // Render the App and sign in as a test user. render(); + + const participants: Record = {}; + participantAccountIDs?.forEach((id) => { + participants[id] = { + hidden: false, + role: id === 1 ? 'admin' : 'member', + } as Participant; + }); + return waitForBatchedUpdatesWithAct() .then(async () => { await waitForBatchedUpdatesWithAct(); @@ -178,45 +171,17 @@ function signInAndGetApp(reportName = '', participantAccountIDs?: number[], part return waitForBatchedUpdates(); }) .then(async () => { - const TEN_MINUTES_AGO = subMinutes(new Date(), 10); - reportActionCreatedDate = format(addSeconds(TEN_MINUTES_AGO, 30), CONST.DATE.FNS_DB_FORMAT_STRING); - reportAction2CreatedDate = format(addSeconds(TEN_MINUTES_AGO, 60), CONST.DATE.FNS_DB_FORMAT_STRING); - // Simulate setting an unread report and personal details await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${REPORT_ID}`, { reportID: REPORT_ID, reportName, - lastReadTime: reportActionCreatedDate, - lastVisibleActionCreated: reportAction2CreatedDate, lastMessageText: 'Test', - groupChatAdminLogins: USER_A_EMAIL, participantAccountIDs, participants, lastActorAccountID: USER_B_ACCOUNT_ID, type: CONST.REPORT.TYPE.CHAT, chatType: CONST.REPORT.CHAT_TYPE.GROUP, }); - const createdReportActionID = NumberUtils.rand64().toString(); - await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${REPORT_ID}`, { - [createdReportActionID]: { - actionName: CONST.REPORT.ACTIONS.TYPE.CREATED, - automatic: false, - created: format(TEN_MINUTES_AGO, CONST.DATE.FNS_DB_FORMAT_STRING), - reportActionID: createdReportActionID, - message: [ - { - style: 'strong', - text: '__FAKE__', - type: 'TEXT', - }, - { - style: 'normal', - text: 'created this report', - type: 'TEXT', - }, - ], - }, - }); await Onyx.merge(ONYXKEYS.PERSONAL_DETAILS_LIST, { [USER_A_ACCOUNT_ID]: TestHelper.buildPersonalDetails(USER_A_EMAIL, USER_A_ACCOUNT_ID, 'A'), @@ -249,24 +214,10 @@ describe('Tests for group chat name', () => { }); const participantAccountIDs4 = [USER_A_ACCOUNT_ID, USER_B_ACCOUNT_ID, USER_C_ACCOUNT_ID, USER_D_ACCOUNT_ID]; - const participants4 = { - [USER_A_ACCOUNT_ID]: {hidden: false, role: 'admin'}, - [USER_B_ACCOUNT_ID]: {hidden: false, role: 'member'}, - [USER_C_ACCOUNT_ID]: {hidden: false, role: 'member'}, - [USER_D_ACCOUNT_ID]: {hidden: false, role: 'member'}, - }; - - const participantAccountIDs8 = [...participantAccountIDs4, USER_E_ACCOUNT_ID, USER_F_ACCOUNT_ID, USER_F_ACCOUNT_ID, USER_G_ACCOUNT_ID]; - const participants8 = { - ...participants4, - [USER_E_ACCOUNT_ID]: {hidden: false, role: 'member'}, - [USER_F_ACCOUNT_ID]: {hidden: false, role: 'member'}, - [USER_G_ACCOUNT_ID]: {hidden: false, role: 'member'}, - [USER_H_ACCOUNT_ID]: {hidden: false, role: 'member'}, - }; + const participantAccountIDs8 = [...participantAccountIDs4, USER_E_ACCOUNT_ID, USER_F_ACCOUNT_ID, USER_G_ACCOUNT_ID, USER_H_ACCOUNT_ID]; it('Should show correctly in LHN', () => - signInAndGetApp('A, B, C, D', participantAccountIDs4, participants4).then(() => { + signInAndGetApp('A, B, C, D', participantAccountIDs4).then(() => { // Verify the sidebar links are rendered const sidebarLinksHintText = Localize.translateLocal('sidebarScreen.listOfChats'); const sidebarLinks = screen.queryAllByLabelText(sidebarLinksHintText); @@ -284,7 +235,7 @@ describe('Tests for group chat name', () => { })); it('Should show correctly in LHN when report name is not present', () => - signInAndGetApp('', participantAccountIDs4, participants4).then(() => { + signInAndGetApp('', participantAccountIDs4).then(() => { // Verify the sidebar links are rendered const sidebarLinksHintText = Localize.translateLocal('sidebarScreen.listOfChats'); const sidebarLinks = screen.queryAllByLabelText(sidebarLinksHintText); @@ -302,7 +253,7 @@ describe('Tests for group chat name', () => { })); it('Should show all 8 names in LHN when 8 participants are present', () => - signInAndGetApp('', participantAccountIDs8, participants8).then(() => { + signInAndGetApp('', participantAccountIDs8).then(() => { // Verify the sidebar links are rendered const sidebarLinksHintText = Localize.translateLocal('sidebarScreen.listOfChats'); const sidebarLinks = screen.queryAllByLabelText(sidebarLinksHintText); @@ -320,7 +271,7 @@ describe('Tests for group chat name', () => { })); it('Check if group name shows fine for report header', () => - signInAndGetApp('', participantAccountIDs4, participants4) + signInAndGetApp('', participantAccountIDs4) .then(() => { // Verify the sidebar links are rendered const sidebarLinksHintText = Localize.translateLocal('sidebarScreen.listOfChats'); @@ -348,7 +299,7 @@ describe('Tests for group chat name', () => { })); it('Should show only 5 names when there are 8 participants in the report header', () => - signInAndGetApp('', participantAccountIDs8, participants8) + signInAndGetApp('', participantAccountIDs8) .then(() => { // Verify the sidebar links are rendered const sidebarLinksHintText = Localize.translateLocal('sidebarScreen.listOfChats'); @@ -376,7 +327,7 @@ describe('Tests for group chat name', () => { })); it('Should show exact name in header when report name is available with 4 participants', () => - signInAndGetApp('Test chat', participantAccountIDs4, participants4) + signInAndGetApp('Test chat', participantAccountIDs4) .then(() => { // Verify the sidebar links are rendered const sidebarLinksHintText = Localize.translateLocal('sidebarScreen.listOfChats'); @@ -404,7 +355,7 @@ describe('Tests for group chat name', () => { })); it('Should show exact name in header when report name is available with 8 participants', () => - signInAndGetApp("Let's talk", participantAccountIDs8, participants8) + signInAndGetApp("Let's talk", participantAccountIDs8) .then(() => { // Verify the sidebar links are rendered const sidebarLinksHintText = Localize.translateLocal('sidebarScreen.listOfChats'); @@ -432,7 +383,7 @@ describe('Tests for group chat name', () => { })); it('Should show last message preview in LHN', () => - signInAndGetApp('A, B, C, D', participantAccountIDs4, participants4).then(() => { + signInAndGetApp('A, B, C, D', participantAccountIDs4).then(() => { // Verify the sidebar links are rendered const sidebarLinksHintText = Localize.translateLocal('sidebarScreen.listOfChats'); const sidebarLinks = screen.queryAllByLabelText(sidebarLinksHintText); @@ -450,13 +401,7 @@ describe('Tests for group chat name', () => { })); it('Should sort the names before displaying', () => - signInAndGetApp('', [USER_E_ACCOUNT_ID, ...participantAccountIDs4], { - [USER_E_ACCOUNT_ID]: { - hidden: false, - role: 'member', - }, - ...participants4, - }).then(() => { + signInAndGetApp('', [USER_E_ACCOUNT_ID, ...participantAccountIDs4]).then(() => { // Verify the sidebar links are rendered const sidebarLinksHintText = Localize.translateLocal('sidebarScreen.listOfChats'); const sidebarLinks = screen.queryAllByLabelText(sidebarLinksHintText); diff --git a/tests/unit/ReportUtilsTest.ts b/tests/unit/ReportUtilsTest.ts index 88394d1fba15b..0c05961f4f07f 100644 --- a/tests/unit/ReportUtilsTest.ts +++ b/tests/unit/ReportUtilsTest.ts @@ -930,6 +930,18 @@ describe('ReportUtils', () => { await Onyx.merge(ONYXKEYS.PERSONAL_DETAILS_LIST, fakePersonalDetails); expect(ReportUtils.getGroupChatName(undefined, false, '1')).toEqual("Let's talk"); }); + + it('Should show participant names if report name is not available', async () => { + const report = { + ...LHNTestUtils.getFakeReport([1, 2, 3, 4, 5, 6, 7, 8]), + chatType: CONST.REPORT.CHAT_TYPE.GROUP, + reportID: `1`, + reportName: '', + }; + await Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}1`, report); + await Onyx.merge(ONYXKEYS.PERSONAL_DETAILS_LIST, fakePersonalDetails); + expect(ReportUtils.getGroupChatName(undefined, false, '1')).toEqual('Eight, Five, Four, One, Seven, Six, Three, Two'); + }); }); }); }); diff --git a/tests/utils/LHNTestUtils.tsx b/tests/utils/LHNTestUtils.tsx index 13d50c5626849..d8d695c3fdd69 100644 --- a/tests/utils/LHNTestUtils.tsx +++ b/tests/utils/LHNTestUtils.tsx @@ -15,6 +15,7 @@ import SidebarLinksData from '@pages/home/sidebar/SidebarLinksData'; import CONST from '@src/CONST'; import type {PersonalDetailsList, Policy, Report, ReportAction} from '@src/types/onyx'; import type {ActionName} from '@src/types/onyx/OriginalMessage'; +import type {Participant} from '@src/types/onyx/Report'; type MockedReportActionItemSingleProps = { /** Determines if the avatar is displayed as a subscript (positioned lower than normal) */ @@ -129,6 +130,15 @@ let lastFakeReportActionID = 0; function getFakeReport(participantAccountIDs = [1, 2], millisecondsInThePast = 0, isUnread = false): Report { const lastVisibleActionCreated = DateUtils.getDBTime(Date.now() - millisecondsInThePast); + const participants: Record = {}; + + participantAccountIDs.forEach((id) => { + participants[id] = { + hidden: false, + role: id === 1 ? 'admin' : 'member', + } as Participant; + }); + return { type: CONST.REPORT.TYPE.CHAT, reportID: `${++lastFakeReportID}`, @@ -136,6 +146,7 @@ function getFakeReport(participantAccountIDs = [1, 2], millisecondsInThePast = 0 lastVisibleActionCreated, lastReadTime: isUnread ? DateUtils.subtractMillisecondsFromDateTime(lastVisibleActionCreated, 1) : lastVisibleActionCreated, participantAccountIDs, + participants, }; } From bfe39100f044634ba6dea5c2b914c770af0fdf4a Mon Sep 17 00:00:00 2001 From: ShridharGoel <35566748+ShridharGoel@users.noreply.github.com> Date: Wed, 8 May 2024 18:07:07 +0530 Subject: [PATCH 04/12] Add admin and member only for group tests --- tests/unit/ReportUtilsTest.ts | 20 ++++++++++---------- tests/utils/LHNTestUtils.tsx | 4 ++-- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/tests/unit/ReportUtilsTest.ts b/tests/unit/ReportUtilsTest.ts index 0c05961f4f07f..88d789e4e546c 100644 --- a/tests/unit/ReportUtilsTest.ts +++ b/tests/unit/ReportUtilsTest.ts @@ -833,7 +833,7 @@ describe('ReportUtils', () => { describe('When participantAccountIDs is passed to getGroupChatName', () => { it('Should show all participants name if count <= 5 and shouldApplyLimit is false', async () => { const report = { - ...LHNTestUtils.getFakeReport([1, 2, 3, 4]), + ...LHNTestUtils.getFakeReport([1, 2, 3, 4], 0, false, true), chatType: CONST.REPORT.CHAT_TYPE.GROUP, }; @@ -843,7 +843,7 @@ describe('ReportUtils', () => { it('Should show all participants name if count <= 5 and shouldApplyLimit is true', async () => { const report = { - ...LHNTestUtils.getFakeReport([1, 2, 3, 4]), + ...LHNTestUtils.getFakeReport([1, 2, 3, 4], 0, false, true), chatType: CONST.REPORT.CHAT_TYPE.GROUP, }; @@ -853,7 +853,7 @@ describe('ReportUtils', () => { it('Should show 5 participants name if count > 5 and shouldApplyLimit is true', async () => { const report = { - ...LHNTestUtils.getFakeReport([1, 2, 3, 4, 5, 6, 7, 8]), + ...LHNTestUtils.getFakeReport([1, 2, 3, 4, 5, 6, 7, 8], 0, false, true), chatType: CONST.REPORT.CHAT_TYPE.GROUP, }; @@ -863,7 +863,7 @@ describe('ReportUtils', () => { it('Should show all participants name if count > 5 and shouldApplyLimit is false', async () => { const report = { - ...LHNTestUtils.getFakeReport([1, 2, 3, 4, 5, 6, 7, 8]), + ...LHNTestUtils.getFakeReport([1, 2, 3, 4, 5, 6, 7, 8], 0, false, true), chatType: CONST.REPORT.CHAT_TYPE.GROUP, }; @@ -873,7 +873,7 @@ describe('ReportUtils', () => { it('Should use correct display name for participants', async () => { const report = { - ...LHNTestUtils.getFakeReport([1, 2, 3, 4]), + ...LHNTestUtils.getFakeReport([1, 2, 3, 4], 0, false, true), chatType: CONST.REPORT.CHAT_TYPE.GROUP, }; @@ -885,7 +885,7 @@ describe('ReportUtils', () => { describe('When participantAccountIDs is not passed to getGroupChatName and report ID is passed', () => { it('Should show report name if count <= 5 and shouldApplyLimit is false', async () => { const report = { - ...LHNTestUtils.getFakeReport([1, 2, 3, 4]), + ...LHNTestUtils.getFakeReport([1, 2, 3, 4], 0, false, true), chatType: CONST.REPORT.CHAT_TYPE.GROUP, reportID: `1`, reportName: "Let's talk", @@ -897,7 +897,7 @@ describe('ReportUtils', () => { it('Should show report name if count <= 5 and shouldApplyLimit is true', async () => { const report = { - ...LHNTestUtils.getFakeReport([1, 2, 3, 4]), + ...LHNTestUtils.getFakeReport([1, 2, 3, 4], 0, false, true), chatType: CONST.REPORT.CHAT_TYPE.GROUP, reportID: `1`, reportName: "Let's talk", @@ -909,7 +909,7 @@ describe('ReportUtils', () => { it('Should show report name if count > 5 and shouldApplyLimit is true', async () => { const report = { - ...LHNTestUtils.getFakeReport([1, 2, 3, 4, 5, 6, 7, 8]), + ...LHNTestUtils.getFakeReport([1, 2, 3, 4, 5, 6, 7, 8], 0, false, true), chatType: CONST.REPORT.CHAT_TYPE.GROUP, reportID: `1`, reportName: "Let's talk", @@ -921,7 +921,7 @@ describe('ReportUtils', () => { it('Should show report name if count > 5 and shouldApplyLimit is false', async () => { const report = { - ...LHNTestUtils.getFakeReport([1, 2, 3, 4, 5, 6, 7, 8]), + ...LHNTestUtils.getFakeReport([1, 2, 3, 4, 5, 6, 7, 8], 0, false, true), chatType: CONST.REPORT.CHAT_TYPE.GROUP, reportID: `1`, reportName: "Let's talk", @@ -933,7 +933,7 @@ describe('ReportUtils', () => { it('Should show participant names if report name is not available', async () => { const report = { - ...LHNTestUtils.getFakeReport([1, 2, 3, 4, 5, 6, 7, 8]), + ...LHNTestUtils.getFakeReport([1, 2, 3, 4, 5, 6, 7, 8], 0, false, true), chatType: CONST.REPORT.CHAT_TYPE.GROUP, reportID: `1`, reportName: '', diff --git a/tests/utils/LHNTestUtils.tsx b/tests/utils/LHNTestUtils.tsx index d8d695c3fdd69..72cadfa81ec7d 100644 --- a/tests/utils/LHNTestUtils.tsx +++ b/tests/utils/LHNTestUtils.tsx @@ -127,7 +127,7 @@ let lastFakeReportActionID = 0; /** * @param millisecondsInThePast the number of milliseconds in the past for the last message timestamp (to order reports by most recent messages) */ -function getFakeReport(participantAccountIDs = [1, 2], millisecondsInThePast = 0, isUnread = false): Report { +function getFakeReport(participantAccountIDs = [1, 2], millisecondsInThePast = 0, isUnread = false, shouldAddParticipantRole: boolean = false): Report { const lastVisibleActionCreated = DateUtils.getDBTime(Date.now() - millisecondsInThePast); const participants: Record = {}; @@ -135,7 +135,7 @@ function getFakeReport(participantAccountIDs = [1, 2], millisecondsInThePast = 0 participantAccountIDs.forEach((id) => { participants[id] = { hidden: false, - role: id === 1 ? 'admin' : 'member', + role: shouldAddParticipantRole ? (id === 1 ? 'admin' : 'member') : null, } as Participant; }); From b49d5011a74a65dc97d55c8d20b8100697affacd Mon Sep 17 00:00:00 2001 From: ShridharGoel <35566748+ShridharGoel@users.noreply.github.com> Date: Fri, 10 May 2024 01:48:34 +0530 Subject: [PATCH 05/12] Update --- tests/unit/ReportUtilsTest.ts | 20 ++++++++++---------- tests/utils/LHNTestUtils.tsx | 8 ++++---- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/tests/unit/ReportUtilsTest.ts b/tests/unit/ReportUtilsTest.ts index 88d789e4e546c..65af15d09d110 100644 --- a/tests/unit/ReportUtilsTest.ts +++ b/tests/unit/ReportUtilsTest.ts @@ -833,7 +833,7 @@ describe('ReportUtils', () => { describe('When participantAccountIDs is passed to getGroupChatName', () => { it('Should show all participants name if count <= 5 and shouldApplyLimit is false', async () => { const report = { - ...LHNTestUtils.getFakeReport([1, 2, 3, 4], 0, false, true), + ...LHNTestUtils.getFakeReport([1, 2, 3, 4], 0, false, [1]), chatType: CONST.REPORT.CHAT_TYPE.GROUP, }; @@ -843,7 +843,7 @@ describe('ReportUtils', () => { it('Should show all participants name if count <= 5 and shouldApplyLimit is true', async () => { const report = { - ...LHNTestUtils.getFakeReport([1, 2, 3, 4], 0, false, true), + ...LHNTestUtils.getFakeReport([1, 2, 3, 4], 0, false, [1]), chatType: CONST.REPORT.CHAT_TYPE.GROUP, }; @@ -853,7 +853,7 @@ describe('ReportUtils', () => { it('Should show 5 participants name if count > 5 and shouldApplyLimit is true', async () => { const report = { - ...LHNTestUtils.getFakeReport([1, 2, 3, 4, 5, 6, 7, 8], 0, false, true), + ...LHNTestUtils.getFakeReport([1, 2, 3, 4, 5, 6, 7, 8], 0, false, [1, 2]), chatType: CONST.REPORT.CHAT_TYPE.GROUP, }; @@ -863,7 +863,7 @@ describe('ReportUtils', () => { it('Should show all participants name if count > 5 and shouldApplyLimit is false', async () => { const report = { - ...LHNTestUtils.getFakeReport([1, 2, 3, 4, 5, 6, 7, 8], 0, false, true), + ...LHNTestUtils.getFakeReport([1, 2, 3, 4, 5, 6, 7, 8], 0, false, [1, 2]), chatType: CONST.REPORT.CHAT_TYPE.GROUP, }; @@ -873,7 +873,7 @@ describe('ReportUtils', () => { it('Should use correct display name for participants', async () => { const report = { - ...LHNTestUtils.getFakeReport([1, 2, 3, 4], 0, false, true), + ...LHNTestUtils.getFakeReport([1, 2, 3, 4], 0, false, [1]), chatType: CONST.REPORT.CHAT_TYPE.GROUP, }; @@ -885,7 +885,7 @@ describe('ReportUtils', () => { describe('When participantAccountIDs is not passed to getGroupChatName and report ID is passed', () => { it('Should show report name if count <= 5 and shouldApplyLimit is false', async () => { const report = { - ...LHNTestUtils.getFakeReport([1, 2, 3, 4], 0, false, true), + ...LHNTestUtils.getFakeReport([1, 2, 3, 4], 0, false, [1]), chatType: CONST.REPORT.CHAT_TYPE.GROUP, reportID: `1`, reportName: "Let's talk", @@ -897,7 +897,7 @@ describe('ReportUtils', () => { it('Should show report name if count <= 5 and shouldApplyLimit is true', async () => { const report = { - ...LHNTestUtils.getFakeReport([1, 2, 3, 4], 0, false, true), + ...LHNTestUtils.getFakeReport([1, 2, 3, 4], 0, false, [1]), chatType: CONST.REPORT.CHAT_TYPE.GROUP, reportID: `1`, reportName: "Let's talk", @@ -909,7 +909,7 @@ describe('ReportUtils', () => { it('Should show report name if count > 5 and shouldApplyLimit is true', async () => { const report = { - ...LHNTestUtils.getFakeReport([1, 2, 3, 4, 5, 6, 7, 8], 0, false, true), + ...LHNTestUtils.getFakeReport([1, 2, 3, 4, 5, 6, 7, 8], 0, false, [1, 2]), chatType: CONST.REPORT.CHAT_TYPE.GROUP, reportID: `1`, reportName: "Let's talk", @@ -921,7 +921,7 @@ describe('ReportUtils', () => { it('Should show report name if count > 5 and shouldApplyLimit is false', async () => { const report = { - ...LHNTestUtils.getFakeReport([1, 2, 3, 4, 5, 6, 7, 8], 0, false, true), + ...LHNTestUtils.getFakeReport([1, 2, 3, 4, 5, 6, 7, 8], 0, false, [1, 2]), chatType: CONST.REPORT.CHAT_TYPE.GROUP, reportID: `1`, reportName: "Let's talk", @@ -933,7 +933,7 @@ describe('ReportUtils', () => { it('Should show participant names if report name is not available', async () => { const report = { - ...LHNTestUtils.getFakeReport([1, 2, 3, 4, 5, 6, 7, 8], 0, false, true), + ...LHNTestUtils.getFakeReport([1, 2, 3, 4, 5, 6, 7, 8], 0, false, [1, 2]), chatType: CONST.REPORT.CHAT_TYPE.GROUP, reportID: `1`, reportName: '', diff --git a/tests/utils/LHNTestUtils.tsx b/tests/utils/LHNTestUtils.tsx index 72cadfa81ec7d..7fb294275db12 100644 --- a/tests/utils/LHNTestUtils.tsx +++ b/tests/utils/LHNTestUtils.tsx @@ -15,7 +15,7 @@ import SidebarLinksData from '@pages/home/sidebar/SidebarLinksData'; import CONST from '@src/CONST'; import type {PersonalDetailsList, Policy, Report, ReportAction} from '@src/types/onyx'; import type {ActionName} from '@src/types/onyx/OriginalMessage'; -import type {Participant} from '@src/types/onyx/Report'; +import type {Participant, Participants} from '@src/types/onyx/Report'; type MockedReportActionItemSingleProps = { /** Determines if the avatar is displayed as a subscript (positioned lower than normal) */ @@ -127,15 +127,15 @@ let lastFakeReportActionID = 0; /** * @param millisecondsInThePast the number of milliseconds in the past for the last message timestamp (to order reports by most recent messages) */ -function getFakeReport(participantAccountIDs = [1, 2], millisecondsInThePast = 0, isUnread = false, shouldAddParticipantRole: boolean = false): Report { +function getFakeReport(participantAccountIDs = [1, 2], millisecondsInThePast = 0, isUnread = false, adminIDs: number[] = []): Report { const lastVisibleActionCreated = DateUtils.getDBTime(Date.now() - millisecondsInThePast); - const participants: Record = {}; + const participants: Participants = {}; participantAccountIDs.forEach((id) => { participants[id] = { hidden: false, - role: shouldAddParticipantRole ? (id === 1 ? 'admin' : 'member') : null, + role: adminIDs.includes(id) ? 'admin' : 'member', } as Participant; }); From dd83c641e3da74022fdb05a4e10f845cab0e895a Mon Sep 17 00:00:00 2001 From: ShridharGoel <35566748+ShridharGoel@users.noreply.github.com> Date: Fri, 17 May 2024 01:26:56 +0530 Subject: [PATCH 06/12] Updates --- tests/ui/GroupChatNameTests.tsx | 31 +++++------------------- tests/ui/UnreadIndicatorsTest.tsx | 31 ++---------------------- tests/utils/TestHelper.ts | 40 ++++++++++++++++++++++++++++++- 3 files changed, 47 insertions(+), 55 deletions(-) diff --git a/tests/ui/GroupChatNameTests.tsx b/tests/ui/GroupChatNameTests.tsx index dcfcf4383b9dd..704a35303050f 100644 --- a/tests/ui/GroupChatNameTests.tsx +++ b/tests/ui/GroupChatNameTests.tsx @@ -1,20 +1,18 @@ /* eslint-disable testing-library/no-node-access */ import type * as NativeNavigation from '@react-navigation/native'; -import {act, fireEvent, render, screen, waitFor} from '@testing-library/react-native'; +import {act, render, screen, waitFor} from '@testing-library/react-native'; import React from 'react'; -import {Linking} from 'react-native'; import Onyx from 'react-native-onyx'; -import type Animated from 'react-native-reanimated'; import * as Localize from '@libs/Localize'; import * as AppActions from '@userActions/App'; import * as User from '@userActions/User'; import App from '@src/App'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; -import appSetup from '@src/setup'; import type {Participant} from '@src/types/onyx/Report'; import PusherHelper from '../utils/PusherHelper'; import * as TestHelper from '../utils/TestHelper'; +import {navigateToSidebarOption} from '../utils/TestHelper'; import waitForBatchedUpdates from '../utils/waitForBatchedUpdates'; import waitForBatchedUpdatesWithAct from '../utils/waitForBatchedUpdatesWithAct'; @@ -54,9 +52,8 @@ type ListenerMock = { * The reason we need this is because we need to trigger the transitionEnd event in our tests to simulate * the transitionEnd event that is triggered when the screen transition animation is completed. * - * P.S: This can't be moved to a utils file because Jest wants any external function to stay in the scope. - * - * @returns An object with two functions: triggerTransitionEnd and addListener + * This can't be moved to a utils file because Jest wants any external function to stay in the scope. + * Details: https://github.com/jestjs/jest/issues/2567 */ const createAddListenerMock = (): ListenerMock => { const transitionEndListeners: Array<() => void> = []; @@ -102,25 +99,9 @@ jest.mock('@react-navigation/native', () => { }); beforeAll(() => { - // In this test, we are generically mocking the responses of all API requests by mocking fetch() and having it - // return 200. In other tests, we might mock HttpUtils.xhr() with a more specific mock data response (which means - // fetch() never gets called so it does not need mocking) or we might have fetch throw an error to test error handling - // behavior. But here we just want to treat all API requests as a generic "success" and in the cases where we need to - // simulate data arriving we will just set it into Onyx directly with Onyx.merge() or Onyx.set() etc. - // @ts-expect-error -- TODO: Remove this once TestHelper (https://github.com/Expensify/App/issues/25318) is migrated - global.fetch = TestHelper.getGlobalFetchMock(); - - Linking.setInitialURL('https://new.expensify.com/'); - appSetup(); + TestHelper.beforeAllSetupUITests() }); -async function navigateToSidebarOption(index: number): Promise { - const hintText = Localize.translateLocal('accessibilityHints.navigatesToChat'); - const optionRows = screen.queryAllByAccessibilityHint(hintText); - fireEvent(optionRows[index], 'press'); - await waitForBatchedUpdatesWithAct(); -} - const REPORT_ID = '1'; const USER_A_ACCOUNT_ID = 1; const USER_A_EMAIL = 'user_a@test.com'; @@ -144,7 +125,7 @@ const USER_H_EMAIL = 'user_h@test.com'; */ function signInAndGetApp(reportName = '', participantAccountIDs?: number[]): Promise { // Render the App and sign in as a test user. - render(); + render(); const participants: Record = {}; participantAccountIDs?.forEach((id) => { diff --git a/tests/ui/UnreadIndicatorsTest.tsx b/tests/ui/UnreadIndicatorsTest.tsx index 5218c1e696c95..568f38995c066 100644 --- a/tests/ui/UnreadIndicatorsTest.tsx +++ b/tests/ui/UnreadIndicatorsTest.tsx @@ -13,22 +13,19 @@ import DateUtils from '@libs/DateUtils'; import * as Localize from '@libs/Localize'; import LocalNotification from '@libs/Notification/LocalNotification'; import * as NumberUtils from '@libs/NumberUtils'; -import * as Pusher from '@libs/Pusher/pusher'; -import PusherConnectionManager from '@libs/PusherConnectionManager'; import FontUtils from '@styles/utils/FontUtils'; import * as AppActions from '@userActions/App'; import * as Report from '@userActions/Report'; import * as User from '@userActions/User'; import App from '@src/App'; -import CONFIG from '@src/CONFIG'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; -import appSetup from '@src/setup'; import type {ReportAction, ReportActions} from '@src/types/onyx'; import PusherHelper from '../utils/PusherHelper'; import * as TestHelper from '../utils/TestHelper'; import waitForBatchedUpdates from '../utils/waitForBatchedUpdates'; import waitForBatchedUpdatesWithAct from '../utils/waitForBatchedUpdatesWithAct'; +import {navigateToSidebarOption} from "../utils/TestHelper"; // We need a large timeout here as we are lazy loading React Navigation screens and this test is running against the entire mounted App jest.setTimeout(30000); @@ -114,24 +111,7 @@ jest.mock('@react-navigation/native', () => { }); beforeAll(() => { - // In this test, we are generically mocking the responses of all API requests by mocking fetch() and having it - // return 200. In other tests, we might mock HttpUtils.xhr() with a more specific mock data response (which means - // fetch() never gets called so it does not need mocking) or we might have fetch throw an error to test error handling - // behavior. But here we just want to treat all API requests as a generic "success" and in the cases where we need to - // simulate data arriving we will just set it into Onyx directly with Onyx.merge() or Onyx.set() etc. - // @ts-expect-error -- TODO: Remove this once TestHelper (https://github.com/Expensify/App/issues/25318) is migrated - global.fetch = TestHelper.getGlobalFetchMock(); - - Linking.setInitialURL('https://new.expensify.com/'); - appSetup(); - - // Connect to Pusher - PusherConnectionManager.init(); - Pusher.init({ - appKey: CONFIG.PUSHER.APP_KEY, - cluster: CONFIG.PUSHER.CLUSTER, - authEndpoint: `${CONFIG.EXPENSIFY.DEFAULT_API_ROOT}api/AuthenticatePusher?`, - }); + TestHelper.beforeAllSetupUITests(true) }); function scrollUpToRevealNewMessagesBadge() { @@ -170,13 +150,6 @@ function navigateToSidebar(): Promise { return waitForBatchedUpdates(); } -async function navigateToSidebarOption(index: number): Promise { - const hintText = Localize.translateLocal('accessibilityHints.navigatesToChat'); - const optionRows = screen.queryAllByAccessibilityHint(hintText); - fireEvent(optionRows[index], 'press'); - await waitForBatchedUpdatesWithAct(); -} - function areYouOnChatListScreen(): boolean { const hintText = Localize.translateLocal('sidebarScreen.listOfChats'); const sidebarLinks = screen.queryAllByLabelText(hintText); diff --git a/tests/utils/TestHelper.ts b/tests/utils/TestHelper.ts index 5621762885659..f88edcef7734e 100644 --- a/tests/utils/TestHelper.ts +++ b/tests/utils/TestHelper.ts @@ -7,6 +7,16 @@ import * as NumberUtils from '@src/libs/NumberUtils'; import ONYXKEYS from '@src/ONYXKEYS'; import type {Response as OnyxResponse, PersonalDetails, Report} from '@src/types/onyx'; import waitForBatchedUpdates from './waitForBatchedUpdates'; +import * as Localize from "@libs/Localize"; +import {fireEvent, screen} from "@testing-library/react-native"; +import waitForBatchedUpdatesWithAct from "./waitForBatchedUpdatesWithAct"; +import {Linking} from "react-native"; +import appSetup from "@src/setup"; +import PusherConnectionManager from "@libs/PusherConnectionManager"; +import CONFIG from "@src/CONFIG"; +import * as Pusher from '@libs/Pusher/pusher'; +import {func} from "prop-types"; +import * as NativeNavigation from "@react-navigation/native"; type MockFetch = ReturnType & { pause?: () => void; @@ -242,4 +252,32 @@ const createAddListenerMock = () => { return {triggerTransitionEnd, addListener}; }; -export {assertFormDataMatchesObject, buildPersonalDetails, buildTestReportComment, createAddListenerMock, getGlobalFetchMock, setPersonalDetails, signInWithTestUser, signOutTestUser}; +async function navigateToSidebarOption(index: number): Promise { + const hintText = Localize.translateLocal('accessibilityHints.navigatesToChat'); + const optionRows = screen.queryAllByAccessibilityHint(hintText); + fireEvent(optionRows[index], 'press'); + await waitForBatchedUpdatesWithAct(); +} + +function beforeAllSetupUITests(shouldConnectToPusher: boolean = false) { + // In this test, we are generically mocking the responses of all API requests by mocking fetch() and having it + // return 200. In other tests, we might mock HttpUtils.xhr() with a more specific mock data response (which means + // fetch() never gets called so it does not need mocking) or we might have fetch throw an error to test error handling + // behavior. But here we just want to treat all API requests as a generic "success" and in the cases where we need to + // simulate data arriving we will just set it into Onyx directly with Onyx.merge() or Onyx.set() etc. + global.fetch = getGlobalFetchMock(); + + Linking.setInitialURL('https://new.expensify.com/'); + appSetup(); + + if (shouldConnectToPusher) { + PusherConnectionManager.init(); + Pusher.init({ + appKey: CONFIG.PUSHER.APP_KEY, + cluster: CONFIG.PUSHER.CLUSTER, + authEndpoint: `${CONFIG.EXPENSIFY.DEFAULT_API_ROOT}api/AuthenticatePusher?`, + }); + } +} + +export {assertFormDataMatchesObject, buildPersonalDetails, buildTestReportComment, createAddListenerMock, getGlobalFetchMock, setPersonalDetails, signInWithTestUser, signOutTestUser, navigateToSidebarOption, beforeAllSetupUITests}; From d22bce2953cce964eb372bce3f64848f56e7280d Mon Sep 17 00:00:00 2001 From: ShridharGoel <35566748+ShridharGoel@users.noreply.github.com> Date: Fri, 17 May 2024 01:52:22 +0530 Subject: [PATCH 07/12] Fixes --- tests/ui/GroupChatNameTests.tsx | 4 ++-- tests/ui/UnreadIndicatorsTest.tsx | 4 ++-- tests/unit/ReportUtilsTest.ts | 35 +++++-------------------------- tests/utils/LHNTestUtils.tsx | 11 +++++----- tests/utils/TestHelper.ts | 33 +++++++++++++++++++---------- 5 files changed, 36 insertions(+), 51 deletions(-) diff --git a/tests/ui/GroupChatNameTests.tsx b/tests/ui/GroupChatNameTests.tsx index 3feed89ee9aa9..3818e46270baf 100644 --- a/tests/ui/GroupChatNameTests.tsx +++ b/tests/ui/GroupChatNameTests.tsx @@ -99,7 +99,7 @@ jest.mock('@react-navigation/native', () => { }); beforeAll(() => { - TestHelper.beforeAllSetupUITests() + TestHelper.beforeAllSetupUITests(); }); const REPORT_ID = '1'; @@ -125,7 +125,7 @@ const USER_H_EMAIL = 'user_h@test.com'; */ function signInAndGetApp(reportName = '', participantAccountIDs?: number[]): Promise { // Render the App and sign in as a test user. - render(); + render(); const participants: Record = {}; participantAccountIDs?.forEach((id) => { diff --git a/tests/ui/UnreadIndicatorsTest.tsx b/tests/ui/UnreadIndicatorsTest.tsx index 8bbe913da9e9c..9f5374a957e7d 100644 --- a/tests/ui/UnreadIndicatorsTest.tsx +++ b/tests/ui/UnreadIndicatorsTest.tsx @@ -23,9 +23,9 @@ import ONYXKEYS from '@src/ONYXKEYS'; import type {ReportAction, ReportActions} from '@src/types/onyx'; import PusherHelper from '../utils/PusherHelper'; import * as TestHelper from '../utils/TestHelper'; +import {navigateToSidebarOption} from '../utils/TestHelper'; import waitForBatchedUpdates from '../utils/waitForBatchedUpdates'; import waitForBatchedUpdatesWithAct from '../utils/waitForBatchedUpdatesWithAct'; -import {navigateToSidebarOption} from "../utils/TestHelper"; // We need a large timeout here as we are lazy loading React Navigation screens and this test is running against the entire mounted App jest.setTimeout(30000); @@ -111,7 +111,7 @@ jest.mock('@react-navigation/native', () => { }); beforeAll(() => { - TestHelper.beforeAllSetupUITests(true) + TestHelper.beforeAllSetupUITests(true); }); function scrollUpToRevealNewMessagesBadge() { diff --git a/tests/unit/ReportUtilsTest.ts b/tests/unit/ReportUtilsTest.ts index df7cffbe45f18..fbf05cf44cddf 100644 --- a/tests/unit/ReportUtilsTest.ts +++ b/tests/unit/ReportUtilsTest.ts @@ -835,53 +835,28 @@ describe('ReportUtils', () => { describe('When participantAccountIDs is passed to getGroupChatName', () => { it('Should show all participants name if count <= 5 and shouldApplyLimit is false', async () => { - const report = { - ...LHNTestUtils.getFakeReport([1, 2, 3, 4], 0, false, [1]), - chatType: CONST.REPORT.CHAT_TYPE.GROUP, - }; - await Onyx.merge(ONYXKEYS.PERSONAL_DETAILS_LIST, fakePersonalDetails); - expect(ReportUtils.getGroupChatName(report?.participantAccountIDs ?? [])).toEqual('Four, One, Three, Two'); + expect(ReportUtils.getGroupChatName([1, 2, 3, 4])).toEqual('Four, One, Three, Two'); }); it('Should show all participants name if count <= 5 and shouldApplyLimit is true', async () => { - const report = { - ...LHNTestUtils.getFakeReport([1, 2, 3, 4], 0, false, [1]), - chatType: CONST.REPORT.CHAT_TYPE.GROUP, - }; - await Onyx.merge(ONYXKEYS.PERSONAL_DETAILS_LIST, fakePersonalDetails); - expect(ReportUtils.getGroupChatName(report?.participantAccountIDs ?? [], true)).toEqual('Four, One, Three, Two'); + expect(ReportUtils.getGroupChatName([1, 2, 3, 4], true)).toEqual('Four, One, Three, Two'); }); it('Should show 5 participants name if count > 5 and shouldApplyLimit is true', async () => { - const report = { - ...LHNTestUtils.getFakeReport([1, 2, 3, 4, 5, 6, 7, 8], 0, false, [1, 2]), - chatType: CONST.REPORT.CHAT_TYPE.GROUP, - }; - await Onyx.merge(ONYXKEYS.PERSONAL_DETAILS_LIST, fakePersonalDetails); - expect(ReportUtils.getGroupChatName(report?.participantAccountIDs ?? [], true)).toEqual('Five, Four, One, Three, Two'); + expect(ReportUtils.getGroupChatName([1, 2, 3, 4, 5, 6, 7, 8], true)).toEqual('Five, Four, One, Three, Two'); }); it('Should show all participants name if count > 5 and shouldApplyLimit is false', async () => { - const report = { - ...LHNTestUtils.getFakeReport([1, 2, 3, 4, 5, 6, 7, 8], 0, false, [1, 2]), - chatType: CONST.REPORT.CHAT_TYPE.GROUP, - }; - await Onyx.merge(ONYXKEYS.PERSONAL_DETAILS_LIST, fakePersonalDetails); - expect(ReportUtils.getGroupChatName(report?.participantAccountIDs ?? [], false)).toEqual('Eight, Five, Four, One, Seven, Six, Three, Two'); + expect(ReportUtils.getGroupChatName([1, 2, 3, 4, 5, 6, 7, 8], false)).toEqual('Eight, Five, Four, One, Seven, Six, Three, Two'); }); it('Should use correct display name for participants', async () => { - const report = { - ...LHNTestUtils.getFakeReport([1, 2, 3, 4], 0, false, [1]), - chatType: CONST.REPORT.CHAT_TYPE.GROUP, - }; - await Onyx.merge(ONYXKEYS.PERSONAL_DETAILS_LIST, participantsPersonalDetails); - expect(ReportUtils.getGroupChatName(report?.participantAccountIDs ?? [], true)).toEqual('(833) 240-3627, floki@vikings.net, Lagertha, Ragnar'); + expect(ReportUtils.getGroupChatName([1, 2, 3, 4], true)).toEqual('(833) 240-3627, floki@vikings.net, Lagertha, Ragnar'); }); }); diff --git a/tests/utils/LHNTestUtils.tsx b/tests/utils/LHNTestUtils.tsx index 7e6f00604afdc..6e464855f4041 100644 --- a/tests/utils/LHNTestUtils.tsx +++ b/tests/utils/LHNTestUtils.tsx @@ -131,14 +131,14 @@ let lastFakeReportActionID = 0; function getFakeReport(participantAccountIDs = [1, 2], millisecondsInThePast = 0, isUnread = false, adminIDs: number[] = []): Report { const lastVisibleActionCreated = DateUtils.getDBTime(Date.now() - millisecondsInThePast); - const participants: Participants = {}; + const participants = ReportUtils.buildParticipantsFromAccountIDs(participantAccountIDs); - participantAccountIDs.forEach((id) => { + adminIDs.forEach((id) => { participants[id] = { hidden: false, - role: adminIDs.includes(id) ? 'admin' : 'member', - } as Participant; - }); + role: CONST.REPORT.ROLE.ADMIN, + } + }) return { type: CONST.REPORT.TYPE.CHAT, @@ -146,7 +146,6 @@ function getFakeReport(participantAccountIDs = [1, 2], millisecondsInThePast = 0 reportName: 'Report', lastVisibleActionCreated, lastReadTime: isUnread ? DateUtils.subtractMillisecondsFromDateTime(lastVisibleActionCreated, 1) : lastVisibleActionCreated, - participants: ReportUtils.buildParticipantsFromAccountIDs(participantAccountIDs), participants, }; } diff --git a/tests/utils/TestHelper.ts b/tests/utils/TestHelper.ts index 94ffded1832a7..160d6468d3bc1 100644 --- a/tests/utils/TestHelper.ts +++ b/tests/utils/TestHelper.ts @@ -1,22 +1,22 @@ +import * as NativeNavigation from '@react-navigation/native'; +import {fireEvent, screen} from '@testing-library/react-native'; import Str from 'expensify-common/lib/str'; +import {func} from 'prop-types'; +import {Linking} from 'react-native'; import Onyx from 'react-native-onyx'; +import * as Localize from '@libs/Localize'; +import * as Pusher from '@libs/Pusher/pusher'; +import PusherConnectionManager from '@libs/PusherConnectionManager'; +import CONFIG from '@src/CONFIG'; import CONST from '@src/CONST'; import * as Session from '@src/libs/actions/Session'; import HttpUtils from '@src/libs/HttpUtils'; import * as NumberUtils from '@src/libs/NumberUtils'; import ONYXKEYS from '@src/ONYXKEYS'; +import appSetup from '@src/setup'; import type {Response as OnyxResponse, PersonalDetails, Report} from '@src/types/onyx'; import waitForBatchedUpdates from './waitForBatchedUpdates'; -import * as Localize from "@libs/Localize"; -import {fireEvent, screen} from "@testing-library/react-native"; -import waitForBatchedUpdatesWithAct from "./waitForBatchedUpdatesWithAct"; -import {Linking} from "react-native"; -import appSetup from "@src/setup"; -import PusherConnectionManager from "@libs/PusherConnectionManager"; -import CONFIG from "@src/CONFIG"; -import * as Pusher from '@libs/Pusher/pusher'; -import {func} from "prop-types"; -import * as NativeNavigation from "@react-navigation/native"; +import waitForBatchedUpdatesWithAct from './waitForBatchedUpdatesWithAct'; type MockFetch = ReturnType & { pause?: () => void; @@ -281,4 +281,15 @@ function beforeAllSetupUITests(shouldConnectToPusher: boolean = false) { } export type {MockFetch}; -export {assertFormDataMatchesObject, buildPersonalDetails, buildTestReportComment, createAddListenerMock, getGlobalFetchMock, setPersonalDetails, signInWithTestUser, signOutTestUser, navigateToSidebarOption, beforeAllSetupUITests}; +export { + assertFormDataMatchesObject, + buildPersonalDetails, + buildTestReportComment, + createAddListenerMock, + getGlobalFetchMock, + setPersonalDetails, + signInWithTestUser, + signOutTestUser, + navigateToSidebarOption, + beforeAllSetupUITests, +}; From f954655eda58ae6f03229cfe0093ef68de27a45a Mon Sep 17 00:00:00 2001 From: ShridharGoel <35566748+ShridharGoel@users.noreply.github.com> Date: Fri, 17 May 2024 02:10:24 +0530 Subject: [PATCH 08/12] Fixes --- tests/ui/GroupChatNameTests.tsx | 2 +- tests/ui/UnreadIndicatorsTest.tsx | 2 +- tests/utils/LHNTestUtils.tsx | 1 - tests/utils/TestHelper.ts | 4 +--- 4 files changed, 3 insertions(+), 6 deletions(-) diff --git a/tests/ui/GroupChatNameTests.tsx b/tests/ui/GroupChatNameTests.tsx index 3818e46270baf..5bbeb66395338 100644 --- a/tests/ui/GroupChatNameTests.tsx +++ b/tests/ui/GroupChatNameTests.tsx @@ -15,6 +15,7 @@ import * as TestHelper from '../utils/TestHelper'; import {navigateToSidebarOption} from '../utils/TestHelper'; import waitForBatchedUpdates from '../utils/waitForBatchedUpdates'; import waitForBatchedUpdatesWithAct from '../utils/waitForBatchedUpdatesWithAct'; +import Animated from "react-native-reanimated"; // We need a large timeout here as we are lazy loading React Navigation screens and this test is running against the entire mounted App jest.setTimeout(50000); @@ -157,7 +158,6 @@ function signInAndGetApp(reportName = '', participantAccountIDs?: number[]): Pro reportID: REPORT_ID, reportName, lastMessageText: 'Test', - participantAccountIDs, participants, lastActorAccountID: USER_B_ACCOUNT_ID, type: CONST.REPORT.TYPE.CHAT, diff --git a/tests/ui/UnreadIndicatorsTest.tsx b/tests/ui/UnreadIndicatorsTest.tsx index 9f5374a957e7d..753d2aa159e12 100644 --- a/tests/ui/UnreadIndicatorsTest.tsx +++ b/tests/ui/UnreadIndicatorsTest.tsx @@ -4,7 +4,7 @@ import {act, fireEvent, render, screen, waitFor} from '@testing-library/react-na import {addSeconds, format, subMinutes, subSeconds} from 'date-fns'; import {utcToZonedTime} from 'date-fns-tz'; import React from 'react'; -import {AppState, DeviceEventEmitter, Linking} from 'react-native'; +import {AppState, DeviceEventEmitter} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; import Onyx from 'react-native-onyx'; import type Animated from 'react-native-reanimated'; diff --git a/tests/utils/LHNTestUtils.tsx b/tests/utils/LHNTestUtils.tsx index 6e464855f4041..6139e429fde8a 100644 --- a/tests/utils/LHNTestUtils.tsx +++ b/tests/utils/LHNTestUtils.tsx @@ -16,7 +16,6 @@ import SidebarLinksData from '@pages/home/sidebar/SidebarLinksData'; import CONST from '@src/CONST'; import type {PersonalDetailsList, Policy, Report, ReportAction} from '@src/types/onyx'; import type {ActionName} from '@src/types/onyx/OriginalMessage'; -import type {Participant, Participants} from '@src/types/onyx/Report'; type MockedReportActionItemSingleProps = { /** Determines if the avatar is displayed as a subscript (positioned lower than normal) */ diff --git a/tests/utils/TestHelper.ts b/tests/utils/TestHelper.ts index 160d6468d3bc1..a4f3ca5c667ff 100644 --- a/tests/utils/TestHelper.ts +++ b/tests/utils/TestHelper.ts @@ -1,7 +1,5 @@ -import * as NativeNavigation from '@react-navigation/native'; import {fireEvent, screen} from '@testing-library/react-native'; import Str from 'expensify-common/lib/str'; -import {func} from 'prop-types'; import {Linking} from 'react-native'; import Onyx from 'react-native-onyx'; import * as Localize from '@libs/Localize'; @@ -259,7 +257,7 @@ async function navigateToSidebarOption(index: number): Promise { await waitForBatchedUpdatesWithAct(); } -function beforeAllSetupUITests(shouldConnectToPusher: boolean = false) { +function beforeAllSetupUITests(shouldConnectToPusher = false) { // In this test, we are generically mocking the responses of all API requests by mocking fetch() and having it // return 200. In other tests, we might mock HttpUtils.xhr() with a more specific mock data response (which means // fetch() never gets called so it does not need mocking) or we might have fetch throw an error to test error handling From 333eed7ac6f35953dc0bf4fe44d16be1574fa2c6 Mon Sep 17 00:00:00 2001 From: ShridharGoel <35566748+ShridharGoel@users.noreply.github.com> Date: Sun, 2 Jun 2024 00:26:25 +0530 Subject: [PATCH 09/12] Use __mocks__ --- __mocks__/@react-native-reanimated/index.ts | 10 ++++++++++ tests/ui/GroupChatNameTests.tsx | 7 ------- tests/ui/UnreadIndicatorsTest.tsx | 6 ------ 3 files changed, 10 insertions(+), 13 deletions(-) create mode 100644 __mocks__/@react-native-reanimated/index.ts diff --git a/__mocks__/@react-native-reanimated/index.ts b/__mocks__/@react-native-reanimated/index.ts new file mode 100644 index 0000000000000..28efba1dde69a --- /dev/null +++ b/__mocks__/@react-native-reanimated/index.ts @@ -0,0 +1,10 @@ +// __mocks__/react-native-reanimated/index.js +const actualAnimated = jest.requireActual('react-native-reanimated/mock'); + +const mock = { + ...actualAnimated, + createAnimatedPropAdapter: jest.fn(), + useReducedMotion: jest.fn(), +}; + +export default mock; diff --git a/tests/ui/GroupChatNameTests.tsx b/tests/ui/GroupChatNameTests.tsx index 5bbeb66395338..7cdcdd4974c91 100644 --- a/tests/ui/GroupChatNameTests.tsx +++ b/tests/ui/GroupChatNameTests.tsx @@ -15,7 +15,6 @@ import * as TestHelper from '../utils/TestHelper'; import {navigateToSidebarOption} from '../utils/TestHelper'; import waitForBatchedUpdates from '../utils/waitForBatchedUpdates'; import waitForBatchedUpdatesWithAct from '../utils/waitForBatchedUpdatesWithAct'; -import Animated from "react-native-reanimated"; // We need a large timeout here as we are lazy loading React Navigation screens and this test is running against the entire mounted App jest.setTimeout(50000); @@ -32,12 +31,6 @@ jest.mock('react-native/Libraries/LogBox/LogBox', () => ({ }, })); -jest.mock('react-native-reanimated', () => ({ - ...jest.requireActual('react-native-reanimated/mock'), - createAnimatedPropAdapter: jest.fn, - useReducedMotion: jest.fn, -})); - /** * We need to keep track of the transitionEnd callback so we can trigger it in our tests */ diff --git a/tests/ui/UnreadIndicatorsTest.tsx b/tests/ui/UnreadIndicatorsTest.tsx index 1d883f069b0b9..2747ae512d5f7 100644 --- a/tests/ui/UnreadIndicatorsTest.tsx +++ b/tests/ui/UnreadIndicatorsTest.tsx @@ -44,12 +44,6 @@ jest.mock('react-native/Libraries/LogBox/LogBox', () => ({ }, })); -jest.mock('react-native-reanimated', () => ({ - ...jest.requireActual('react-native-reanimated/mock'), - createAnimatedPropAdapter: jest.fn, - useReducedMotion: jest.fn, -})); - /** * We need to keep track of the transitionEnd callback so we can trigger it in our tests */ From cdc24cd6bff39b47a8481c4dc67d13e38d077b5d Mon Sep 17 00:00:00 2001 From: ShridharGoel <35566748+ShridharGoel@users.noreply.github.com> Date: Tue, 4 Jun 2024 23:22:25 +0530 Subject: [PATCH 10/12] Update --- tests/ui/GroupChatNameTests.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ui/GroupChatNameTests.tsx b/tests/ui/GroupChatNameTests.tsx index 7cdcdd4974c91..5ac141e2d2a1d 100644 --- a/tests/ui/GroupChatNameTests.tsx +++ b/tests/ui/GroupChatNameTests.tsx @@ -179,7 +179,7 @@ function signInAndGetApp(reportName = '', participantAccountIDs?: number[]): Pro * Note that limit of 5 names is only for the header. */ describe('Tests for group chat name', () => { - afterEach(() => { + beforeEach(() => { jest.clearAllMocks(); Onyx.clear(); From 77592478af52791785ad577f18028e101ba5c458 Mon Sep 17 00:00:00 2001 From: ShridharGoel <35566748+ShridharGoel@users.noreply.github.com> Date: Wed, 5 Jun 2024 17:09:51 +0530 Subject: [PATCH 11/12] Update --- tests/ui/GroupChatNameTests.tsx | 3 +-- tests/ui/UnreadIndicatorsTest.tsx | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/ui/GroupChatNameTests.tsx b/tests/ui/GroupChatNameTests.tsx index 5ac141e2d2a1d..e0ac71120768f 100644 --- a/tests/ui/GroupChatNameTests.tsx +++ b/tests/ui/GroupChatNameTests.tsx @@ -55,12 +55,11 @@ const createAddListenerMock = (): ListenerMock => { transitionEndListeners.forEach((transitionEndListener) => transitionEndListener()); }; - const addListener: jest.Mock = jest.fn().mockImplementation((listener, callback) => { + const addListener: jest.Mock = jest.fn().mockImplementation((listener, callback: () => void) => { if (listener === 'transitionEnd') { transitionEndListeners.push(callback); } return () => { - // eslint-disable-next-line rulesdir/prefer-underscore-method transitionEndListeners.filter((cb) => cb !== callback); }; }); diff --git a/tests/ui/UnreadIndicatorsTest.tsx b/tests/ui/UnreadIndicatorsTest.tsx index 2747ae512d5f7..13eefa00d619b 100644 --- a/tests/ui/UnreadIndicatorsTest.tsx +++ b/tests/ui/UnreadIndicatorsTest.tsx @@ -8,7 +8,6 @@ import {AppState, DeviceEventEmitter} from 'react-native'; import type {ViewStyle} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; import Onyx from 'react-native-onyx'; -import type Animated from 'react-native-reanimated'; import * as CollectionUtils from '@libs/CollectionUtils'; import DateUtils from '@libs/DateUtils'; import * as Localize from '@libs/Localize'; From 5660b25707f3640a25eb8bf7cb97b44d5c1cc2bd Mon Sep 17 00:00:00 2001 From: ShridharGoel <35566748+ShridharGoel@users.noreply.github.com> Date: Sat, 8 Jun 2024 01:11:02 +0530 Subject: [PATCH 12/12] Update --- tests/utils/LHNTestUtils.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/utils/LHNTestUtils.tsx b/tests/utils/LHNTestUtils.tsx index 6139e429fde8a..c9064e1e7a8ce 100644 --- a/tests/utils/LHNTestUtils.tsx +++ b/tests/utils/LHNTestUtils.tsx @@ -136,8 +136,8 @@ function getFakeReport(participantAccountIDs = [1, 2], millisecondsInThePast = 0 participants[id] = { hidden: false, role: CONST.REPORT.ROLE.ADMIN, - } - }) + }; + }); return { type: CONST.REPORT.TYPE.CHAT,