From 9bf8099eec0ff2e0456c27626b7c021ecddf246e Mon Sep 17 00:00:00 2001 From: VickyStash <vikstash@gmail.com> Date: Fri, 23 Feb 2024 17:01:38 +0100 Subject: [PATCH 1/5] [TS migration] Migrate 'EmojiTest.js' test --- src/libs/EmojiUtils.ts | 2 +- tests/unit/{EmojiTest.js => EmojiTest.ts} | 73 ++++++++++++----------- 2 files changed, 38 insertions(+), 37 deletions(-) rename tests/unit/{EmojiTest.js => EmojiTest.ts} (88%) diff --git a/src/libs/EmojiUtils.ts b/src/libs/EmojiUtils.ts index 730f2a5d3295..2b9e4c6fcd8a 100644 --- a/src/libs/EmojiUtils.ts +++ b/src/libs/EmojiUtils.ts @@ -384,7 +384,7 @@ function replaceAndExtractEmojis(text: string, preferredSkinTone: number = CONST * Suggest emojis when typing emojis prefix after colon * @param [limit] - matching emojis limit */ -function suggestEmojis(text: string, lang: keyof SupportedLanguage, limit = CONST.AUTO_COMPLETE_SUGGESTER.MAX_AMOUNT_OF_SUGGESTIONS): Emoji[] | undefined { +function suggestEmojis(text: string, lang: SupportedLanguage, limit: number = CONST.AUTO_COMPLETE_SUGGESTER.MAX_AMOUNT_OF_SUGGESTIONS): Emoji[] | undefined { // emojisTrie is importing the emoji JSON file on the app starting and we want to avoid it const emojisTrie = require('./EmojiTrie').default; diff --git a/tests/unit/EmojiTest.js b/tests/unit/EmojiTest.ts similarity index 88% rename from tests/unit/EmojiTest.js rename to tests/unit/EmojiTest.ts index 40474d0331fe..954d561598e8 100644 --- a/tests/unit/EmojiTest.js +++ b/tests/unit/EmojiTest.ts @@ -1,20 +1,20 @@ import {getUnixTime} from 'date-fns'; -import lodashGet from 'lodash/get'; import Onyx from 'react-native-onyx'; -import _ from 'underscore'; -import Emoji from '../../assets/emojis'; -import CONST from '../../src/CONST'; -import * as User from '../../src/libs/actions/User'; -import * as EmojiUtils from '../../src/libs/EmojiUtils'; -import ONYXKEYS from '../../src/ONYXKEYS'; +import Emojis from '@assets/emojis'; +import type {Emoji} from '@assets/emojis/types'; +import * as User from '@libs/actions/User'; +import * as EmojiUtils from '@libs/EmojiUtils'; +import CONST from '@src/CONST'; +import ONYXKEYS from '@src/ONYXKEYS'; +import type {FrequentlyUsedEmoji} from '@src/types/onyx'; import * as TestHelper from '../utils/TestHelper'; import waitForBatchedUpdates from '../utils/waitForBatchedUpdates'; describe('EmojiTest', () => { it('matches all the emojis in the list', () => { // Given the set of Emojis available in the application - const emojiMatched = _.every(Emoji, (emoji) => { - if (emoji.header === true || emoji.spacer) { + const emojiMatched = Emojis.every((emoji) => { + if (('header' in emoji && emoji.header) || ('spacer' in emoji && emoji.spacer)) { return true; } @@ -22,9 +22,9 @@ describe('EmojiTest', () => { const isEmojiMatched = EmojiUtils.containsOnlyEmojis(emoji.code); let skinToneMatched = true; - if (emoji.types) { + if ('types' in emoji && emoji.types) { // and every skin tone variant of the Emoji code - skinToneMatched = _.every(emoji.types, (emojiWithSkinTone) => EmojiUtils.containsOnlyEmojis(emojiWithSkinTone)); + skinToneMatched = emoji.types.every((emojiWithSkinTone) => EmojiUtils.containsOnlyEmojis(emojiWithSkinTone)); } return skinToneMatched && isEmojiMatched; }); @@ -103,42 +103,42 @@ describe('EmojiTest', () => { it('replaces an emoji code with an emoji and a space', () => { const text = 'Hi :smile:'; - expect(lodashGet(EmojiUtils.replaceEmojis(text), 'text')).toBe('Hi 😄 '); + expect(EmojiUtils.replaceEmojis(text).text).toBe('Hi 😄 '); }); it('will add a space after the last emoji', () => { const text = 'Hi :smile::wave:'; - expect(lodashGet(EmojiUtils.replaceEmojis(text), 'text')).toBe('Hi 😄👋 '); + expect(EmojiUtils.replaceEmojis(text).text).toBe('Hi 😄👋 '); }); it('will add a space after the last emoji if there is text after it', () => { const text = 'Hi :smile::wave:space after last emoji'; - expect(lodashGet(EmojiUtils.replaceEmojis(text), 'text')).toBe('Hi 😄👋 space after last emoji'); + expect(EmojiUtils.replaceEmojis(text).text).toBe('Hi 😄👋 space after last emoji'); }); it('will add a space after the last emoji if there is invalid emoji after it', () => { const text = 'Hi :smile::wave:space when :invalidemoji: present'; - expect(lodashGet(EmojiUtils.replaceEmojis(text), 'text')).toBe('Hi 😄👋 space when :invalidemoji: present'); + expect(EmojiUtils.replaceEmojis(text).text).toBe('Hi 😄👋 space when :invalidemoji: present'); }); it('will not add a space after the last emoji if there if last emoji is immediately followed by a space', () => { const text = 'Hi :smile::wave: space after last emoji'; - expect(lodashGet(EmojiUtils.replaceEmojis(text), 'text')).toBe('Hi 😄👋 space after last emoji'); + expect(EmojiUtils.replaceEmojis(text).text).toBe('Hi 😄👋 space after last emoji'); }); it('will return correct cursor position', () => { const text = 'Hi :smile: there :wave:!'; - expect(lodashGet(EmojiUtils.replaceEmojis(text), 'cursorPosition')).toBe(15); + expect(EmojiUtils.replaceEmojis(text).cursorPosition).toBe(15); }); it('will return correct cursor position when space is not added by space follows last emoji', () => { const text = 'Hi :smile: there!'; - expect(lodashGet(EmojiUtils.replaceEmojis(text), 'cursorPosition')).toBe(6); + expect(EmojiUtils.replaceEmojis(text).cursorPosition).toBe(6); }); it('will return undefined cursor position when no emoji is replaced', () => { const text = 'Hi there!'; - expect(lodashGet(EmojiUtils.replaceEmojis(text), 'cursorPosition')).toBe(undefined); + expect(EmojiUtils.replaceEmojis(text).cursorPosition).toBe(undefined); }); it('suggests emojis when typing emojis prefix after colon', () => { @@ -149,11 +149,11 @@ describe('EmojiTest', () => { it('suggests a limited number of matching emojis', () => { const text = 'Hi :face'; const limit = 3; - expect(EmojiUtils.suggestEmojis(text, 'en', limit).length).toBe(limit); + expect(EmojiUtils.suggestEmojis(text, 'en', limit)?.length).toBe(limit); }); it('correct suggests emojis accounting for keywords', () => { - const thumbEmojis = [ + const thumbEmojis: Emoji[] = [ { code: '👍', name: '+1', @@ -190,10 +190,11 @@ describe('EmojiTest', () => { }); describe('update frequently used emojis', () => { - let spy; + let spy: jest.SpyInstance; beforeAll(() => { Onyx.init({keys: ONYXKEYS}); + // @ts-expect-error TODO: Remove this once TestHelper (https://github.com/Expensify/App/issues/25318) is migrated to TypeScript. global.fetch = TestHelper.getGlobalFetchMock(); spy = jest.spyOn(User, 'updateFrequentlyUsedEmojis'); }); @@ -205,7 +206,7 @@ describe('EmojiTest', () => { it('should put a less frequent and recent used emoji behind', () => { // Given an existing frequently used emojis list with count > 1 - const frequentlyEmojisList = [ + const frequentlyEmojisList: FrequentlyUsedEmoji[] = [ { code: '👋', name: 'wave', @@ -237,12 +238,12 @@ describe('EmojiTest', () => { return waitForBatchedUpdates().then(() => { // When add a new emoji const currentTime = getUnixTime(new Date()); - const smileEmoji = {code: '😄', name: 'smile'}; + const smileEmoji: Emoji = {code: '😄', name: 'smile'}; const newEmoji = [smileEmoji]; User.updateFrequentlyUsedEmojis(EmojiUtils.getFrequentlyUsedEmojis(newEmoji)); // Then the new emoji should be at the last item of the list - const expectedSmileEmoji = {...smileEmoji, count: 1, lastUpdatedAt: currentTime}; + const expectedSmileEmoji: FrequentlyUsedEmoji = {...smileEmoji, count: 1, lastUpdatedAt: currentTime}; const expectedFrequentlyEmojisList = [...frequentlyEmojisList, expectedSmileEmoji]; expect(spy).toBeCalledWith(expectedFrequentlyEmojisList); @@ -251,8 +252,8 @@ describe('EmojiTest', () => { it('should put more frequent and recent used emoji to the front', () => { // Given an existing frequently used emojis list - const smileEmoji = {code: '😄', name: 'smile'}; - const frequentlyEmojisList = [ + const smileEmoji: Emoji = {code: '😄', name: 'smile'}; + const frequentlyEmojisList: FrequentlyUsedEmoji[] = [ { code: '😠', name: 'angry', @@ -296,10 +297,10 @@ describe('EmojiTest', () => { it('should sorted descending by count and lastUpdatedAt for multiple emoji added', () => { // Given an existing frequently used emojis list - const smileEmoji = {code: '😄', name: 'smile'}; - const zzzEmoji = {code: '💤', name: 'zzz'}; - const impEmoji = {code: '👿', name: 'imp'}; - const frequentlyEmojisList = [ + const smileEmoji: Emoji = {code: '😄', name: 'smile'}; + const zzzEmoji: Emoji = {code: '💤', name: 'zzz'}; + const impEmoji: Emoji = {code: '👿', name: 'imp'}; + const frequentlyEmojisList: FrequentlyUsedEmoji[] = [ { code: '😠', name: 'angry', @@ -345,11 +346,11 @@ describe('EmojiTest', () => { it('make sure the most recent new emoji is added to the list even it is full with count > 1', () => { // Given an existing full (24 items) frequently used emojis list - const smileEmoji = {code: '😄', name: 'smile'}; - const zzzEmoji = {code: '💤', name: 'zzz'}; - const impEmoji = {code: '👿', name: 'imp'}; - const bookEmoji = {code: '📚', name: 'books'}; - const frequentlyEmojisList = [ + const smileEmoji: Emoji = {code: '😄', name: 'smile'}; + const zzzEmoji: Emoji = {code: '💤', name: 'zzz'}; + const impEmoji: Emoji = {code: '👿', name: 'imp'}; + const bookEmoji: Emoji = {code: '📚', name: 'books'}; + const frequentlyEmojisList: FrequentlyUsedEmoji[] = [ { code: '😠', name: 'angry', From 84592abe6d5991cd81464b8a2e175b90fa7cf446 Mon Sep 17 00:00:00 2001 From: VickyStash <vikstash@gmail.com> Date: Mon, 26 Feb 2024 15:27:40 +0100 Subject: [PATCH 2/5] Migrate to TS SidebarOrderTest, LHNTestUtils test files --- .../home/report/ReportActionItemSingle.tsx | 2 +- src/types/onyx/ReportAction.ts | 3 + ...idebarOrderTest.js => SidebarOrderTest.ts} | 429 +++++++++++------- .../{LHNTestUtils.js => LHNTestUtils.tsx} | 222 ++++----- 4 files changed, 347 insertions(+), 309 deletions(-) rename tests/unit/{SidebarOrderTest.js => SidebarOrderTest.ts} (73%) rename tests/utils/{LHNTestUtils.js => LHNTestUtils.tsx} (68%) diff --git a/src/pages/home/report/ReportActionItemSingle.tsx b/src/pages/home/report/ReportActionItemSingle.tsx index 18f261024fd6..741422cc7e82 100644 --- a/src/pages/home/report/ReportActionItemSingle.tsx +++ b/src/pages/home/report/ReportActionItemSingle.tsx @@ -27,7 +27,7 @@ import type ChildrenProps from '@src/types/utils/ChildrenProps'; import ReportActionItemDate from './ReportActionItemDate'; import ReportActionItemFragment from './ReportActionItemFragment'; -type ReportActionItemSingleProps = ChildrenProps & { +type ReportActionItemSingleProps = Partial<ChildrenProps> & { /** All the data of the action */ action: ReportAction; diff --git a/src/types/onyx/ReportAction.ts b/src/types/onyx/ReportAction.ts index ed3173381b32..dffbbab6c011 100644 --- a/src/types/onyx/ReportAction.ts +++ b/src/types/onyx/ReportAction.ts @@ -123,6 +123,9 @@ type ReportActionBase = { actorAccountID?: number; + /** The account of the last message's actor */ + actor?: string; + /** Person who created the action */ person?: Person[]; diff --git a/tests/unit/SidebarOrderTest.js b/tests/unit/SidebarOrderTest.ts similarity index 73% rename from tests/unit/SidebarOrderTest.js rename to tests/unit/SidebarOrderTest.ts index 7ae8c4e1e9b3..9e70347764df 100644 --- a/tests/unit/SidebarOrderTest.js +++ b/tests/unit/SidebarOrderTest.ts @@ -1,14 +1,16 @@ import {cleanup, screen} from '@testing-library/react-native'; -import lodashGet from 'lodash/get'; import Onyx from 'react-native-onyx'; -import CONST from '../../src/CONST'; -import * as Report from '../../src/libs/actions/Report'; -import DateUtils from '../../src/libs/DateUtils'; -import * as Localize from '../../src/libs/Localize'; +import * as Report from '@libs/actions/Report'; +import DateUtils from '@libs/DateUtils'; +import * as Localize from '@libs/Localize'; +import CONST from '@src/CONST'; +import type * as OnyxTypes from '@src/types/onyx'; import * as LHNTestUtils from '../utils/LHNTestUtils'; import waitForBatchedUpdates from '../utils/waitForBatchedUpdates'; import wrapOnyxWithWaitForBatchedUpdates from '../utils/wrapOnyxWithWaitForBatchedUpdates'; +type ReportCollectionDataSet = Record<`${typeof ONYXKEYS.COLLECTION.REPORT}${string}`, OnyxTypes.Report>; + // Be sure to include the mocked Permissions and Expensicons libraries as well as the usePermissions hook or else the beta tests won't work jest.mock('../../src/libs/Permissions'); jest.mock('../../src/hooks/usePermissions.ts'); @@ -23,15 +25,16 @@ const ONYXKEYS = { COLLECTION: { REPORT: 'report_', REPORT_ACTIONS: 'reportActions_', + POLICY: 'policy_', }, NETWORK: 'network', -}; + IS_LOADING_REPORT_DATA: 'isLoadingReportData', +} as const; describe('Sidebar', () => { beforeAll(() => Onyx.init({ keys: ONYXKEYS, - registerStorageEventListener: () => {}, safeEvictionKeys: [ONYXKEYS.COLLECTION.REPORT_ACTIONS], }), ); @@ -88,6 +91,10 @@ describe('Sidebar', () => { const report = LHNTestUtils.getFakeReport([1, 2]); LHNTestUtils.getDefaultRenderedSidebarLinks(report.reportID); + const reportCollectionDataSet: ReportCollectionDataSet = { + [`${ONYXKEYS.COLLECTION.REPORT}${report.reportID}`]: report, + }; + return ( waitForBatchedUpdates() // When Onyx is updated with the data and the sidebar re-renders @@ -96,7 +103,7 @@ describe('Sidebar', () => { [ONYXKEYS.NVP_PRIORITY_MODE]: CONST.PRIORITY_MODE.DEFAULT, [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, [ONYXKEYS.IS_LOADING_APP]: false, - [`${ONYXKEYS.COLLECTION.REPORT}${report.reportID}`]: report, + ...reportCollectionDataSet, }), ) @@ -120,6 +127,12 @@ describe('Sidebar', () => { Report.addComment(report2.reportID, 'Hi, this is a comment'); Report.addComment(report3.reportID, 'Hi, this is a comment'); + const reportCollectionDataSet: ReportCollectionDataSet = { + [`${ONYXKEYS.COLLECTION.REPORT}${report1.reportID}`]: report1, + [`${ONYXKEYS.COLLECTION.REPORT}${report2.reportID}`]: report2, + [`${ONYXKEYS.COLLECTION.REPORT}${report3.reportID}`]: report3, + }; + return ( waitForBatchedUpdates() // When Onyx is updated with the data and the sidebar re-renders @@ -128,9 +141,7 @@ describe('Sidebar', () => { [ONYXKEYS.NVP_PRIORITY_MODE]: CONST.PRIORITY_MODE.DEFAULT, [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, [ONYXKEYS.IS_LOADING_APP]: false, - [`${ONYXKEYS.COLLECTION.REPORT}${report1.reportID}`]: report1, - [`${ONYXKEYS.COLLECTION.REPORT}${report2.reportID}`]: report2, - [`${ONYXKEYS.COLLECTION.REPORT}${report3.reportID}`]: report3, + ...reportCollectionDataSet, }), ) @@ -140,9 +151,9 @@ describe('Sidebar', () => { const displayNames = screen.queryAllByLabelText(hintText); expect(displayNames).toHaveLength(3); - expect(lodashGet(displayNames, [0, 'props', 'children', 0])).toBe('Five, Six'); - expect(lodashGet(displayNames, [1, 'props', 'children', 0])).toBe('Three, Four'); - expect(lodashGet(displayNames, [2, 'props', 'children', 0])).toBe('One, Two'); + expect(displayNames[0].props.children[0]).toBe('Five, Six'); + expect(displayNames[1].props.children[0]).toBe('Three, Four'); + expect(displayNames[2].props.children[0]).toBe('One, Two'); }) ); }); @@ -166,6 +177,12 @@ describe('Sidebar', () => { const currentReportId = report1.reportID; LHNTestUtils.getDefaultRenderedSidebarLinks(currentReportId); + const reportCollectionDataSet: ReportCollectionDataSet = { + [`${ONYXKEYS.COLLECTION.REPORT}${report1.reportID}`]: report1, + [`${ONYXKEYS.COLLECTION.REPORT}${report2.reportID}`]: report2, + [`${ONYXKEYS.COLLECTION.REPORT}${report3.reportID}`]: report3, + }; + return ( waitForBatchedUpdates() // When Onyx is updated with the data and the sidebar re-renders @@ -174,9 +191,7 @@ describe('Sidebar', () => { [ONYXKEYS.NVP_PRIORITY_MODE]: CONST.PRIORITY_MODE.DEFAULT, [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, [ONYXKEYS.IS_LOADING_APP]: false, - [`${ONYXKEYS.COLLECTION.REPORT}${report1.reportID}`]: report1, - [`${ONYXKEYS.COLLECTION.REPORT}${report2.reportID}`]: report2, - [`${ONYXKEYS.COLLECTION.REPORT}${report3.reportID}`]: report3, + ...reportCollectionDataSet, }), ) @@ -189,9 +204,9 @@ describe('Sidebar', () => { const hintText = Localize.translateLocal('accessibilityHints.chatUserDisplayNames'); const displayNames = screen.queryAllByLabelText(hintText); expect(displayNames).toHaveLength(3); - expect(lodashGet(displayNames, [0, 'props', 'children', 0])).toBe('One, Two'); // this has `hasDraft` flag enabled so it will be on top - expect(lodashGet(displayNames, [1, 'props', 'children', 0])).toBe('Five, Six'); - expect(lodashGet(displayNames, [2, 'props', 'children', 0])).toBe('Three, Four'); + expect(displayNames[0].props.children[0]).toBe('One, Two'); // this has `hasDraft` flag enabled so it will be on top + expect(displayNames[1].props.children[0]).toBe('Five, Six'); + expect(displayNames[2].props.children[0]).toBe('Three, Four'); }) ); }); @@ -209,6 +224,12 @@ describe('Sidebar', () => { Report.addComment(report2.reportID, 'Hi, this is a comment'); Report.addComment(report3.reportID, 'Hi, this is a comment'); + const reportCollectionDataSet: ReportCollectionDataSet = { + [`${ONYXKEYS.COLLECTION.REPORT}${report1.reportID}`]: report1, + [`${ONYXKEYS.COLLECTION.REPORT}${report2.reportID}`]: report2, + [`${ONYXKEYS.COLLECTION.REPORT}${report3.reportID}`]: report3, + }; + return ( waitForBatchedUpdates() // When Onyx is updated with the data and the sidebar re-renders @@ -217,9 +238,7 @@ describe('Sidebar', () => { [ONYXKEYS.NVP_PRIORITY_MODE]: CONST.PRIORITY_MODE.DEFAULT, [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, [ONYXKEYS.IS_LOADING_APP]: false, - [`${ONYXKEYS.COLLECTION.REPORT}${report1.reportID}`]: report1, - [`${ONYXKEYS.COLLECTION.REPORT}${report2.reportID}`]: report2, - [`${ONYXKEYS.COLLECTION.REPORT}${report3.reportID}`]: report3, + ...reportCollectionDataSet, }), ) @@ -236,9 +255,9 @@ describe('Sidebar', () => { const hintText = Localize.translateLocal('accessibilityHints.chatUserDisplayNames'); const displayNames = screen.queryAllByLabelText(hintText); expect(displayNames).toHaveLength(3); - expect(lodashGet(displayNames, [0, 'props', 'children', 0])).toBe('One, Two'); - expect(lodashGet(displayNames, [1, 'props', 'children', 0])).toBe('Five, Six'); - expect(lodashGet(displayNames, [2, 'props', 'children', 0])).toBe('Three, Four'); + expect(displayNames[0].props.children[0]).toBe('One, Two'); + expect(displayNames[1].props.children[0]).toBe('Five, Six'); + expect(displayNames[2].props.children[0]).toBe('Three, Four'); }) ); }); @@ -250,7 +269,7 @@ describe('Sidebar', () => { const report3 = LHNTestUtils.getFakeReport([5, 6], 2); const taskReportName = 'Buy Grocery'; - const taskReport = { + const taskReport: OnyxTypes.Report = { ...LHNTestUtils.getFakeReport([7, 8], 1), type: CONST.REPORT.TYPE.TASK, reportName: taskReportName, @@ -266,6 +285,13 @@ describe('Sidebar', () => { LHNTestUtils.getDefaultRenderedSidebarLinks(taskReport.reportID); + const reportCollectionDataSet: ReportCollectionDataSet = { + [`${ONYXKEYS.COLLECTION.REPORT}${report1.reportID}`]: report1, + [`${ONYXKEYS.COLLECTION.REPORT}${report2.reportID}`]: report2, + [`${ONYXKEYS.COLLECTION.REPORT}${report3.reportID}`]: report3, + [`${ONYXKEYS.COLLECTION.REPORT}${taskReport.reportID}`]: taskReport, + }; + return ( waitForBatchedUpdates() // When Onyx is updated with the data and the sidebar re-renders @@ -274,10 +300,7 @@ describe('Sidebar', () => { [ONYXKEYS.NVP_PRIORITY_MODE]: CONST.PRIORITY_MODE.DEFAULT, [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, [ONYXKEYS.IS_LOADING_REPORT_DATA]: false, - [`${ONYXKEYS.COLLECTION.REPORT}${report1.reportID}`]: report1, - [`${ONYXKEYS.COLLECTION.REPORT}${report2.reportID}`]: report2, - [`${ONYXKEYS.COLLECTION.REPORT}${report3.reportID}`]: report3, - [`${ONYXKEYS.COLLECTION.REPORT}${taskReport.reportID}`]: taskReport, + ...reportCollectionDataSet, }), ) @@ -286,10 +309,10 @@ describe('Sidebar', () => { const hintText = Localize.translateLocal('accessibilityHints.chatUserDisplayNames'); const displayNames = screen.queryAllByLabelText(hintText); expect(displayNames).toHaveLength(4); - expect(lodashGet(displayNames, [0, 'props', 'children', 0])).toBe(taskReportName); - expect(lodashGet(displayNames, [1, 'props', 'children', 0])).toBe('Five, Six'); - expect(lodashGet(displayNames, [2, 'props', 'children', 0])).toBe('Three, Four'); - expect(lodashGet(displayNames, [3, 'props', 'children', 0])).toBe('One, Two'); + expect(displayNames[0].props.children[0]).toBe(taskReportName); + expect(displayNames[1].props.children[0]).toBe('Five, Six'); + expect(displayNames[2].props.children[0]).toBe('Three, Four'); + expect(displayNames[3].props.children[0]).toBe('One, Two'); }) ); }); @@ -298,14 +321,14 @@ describe('Sidebar', () => { // Given three reports in the recently updated order of 3, 2, 1 const report1 = LHNTestUtils.getFakeReport([1, 2], 4); const report2 = LHNTestUtils.getFakeReport([3, 4], 3); - const report3 = { + const report3: OnyxTypes.Report = { ...LHNTestUtils.getFakeReport([5, 6], 2), hasOutstandingChildRequest: false, // This has to be added after the IOU report is generated - iouReportID: null, + iouReportID: undefined, }; - const iouReport = { + const iouReport: OnyxTypes.Report = { ...LHNTestUtils.getFakeReport([7, 8], 1), type: CONST.REPORT.TYPE.IOU, ownerAccountID: 2, @@ -326,6 +349,13 @@ describe('Sidebar', () => { LHNTestUtils.getDefaultRenderedSidebarLinks(report3.reportID); + const reportCollectionDataSet: ReportCollectionDataSet = { + [`${ONYXKEYS.COLLECTION.REPORT}${report1.reportID}`]: report1, + [`${ONYXKEYS.COLLECTION.REPORT}${report2.reportID}`]: report2, + [`${ONYXKEYS.COLLECTION.REPORT}${report3.reportID}`]: report3, + [`${ONYXKEYS.COLLECTION.REPORT}${iouReport.reportID}`]: iouReport, + }; + return ( waitForBatchedUpdates() // When Onyx is updated with the data and the sidebar re-renders @@ -334,10 +364,7 @@ describe('Sidebar', () => { [ONYXKEYS.NVP_PRIORITY_MODE]: CONST.PRIORITY_MODE.DEFAULT, [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, [ONYXKEYS.IS_LOADING_REPORT_DATA]: false, - [`${ONYXKEYS.COLLECTION.REPORT}${report1.reportID}`]: report1, - [`${ONYXKEYS.COLLECTION.REPORT}${report2.reportID}`]: report2, - [`${ONYXKEYS.COLLECTION.REPORT}${report3.reportID}`]: report3, - [`${ONYXKEYS.COLLECTION.REPORT}${iouReport.reportID}`]: iouReport, + ...reportCollectionDataSet, }), ) @@ -346,10 +373,10 @@ describe('Sidebar', () => { const hintText = Localize.translateLocal('accessibilityHints.chatUserDisplayNames'); const displayNames = screen.queryAllByLabelText(hintText); expect(displayNames).toHaveLength(4); - expect(lodashGet(displayNames, [0, 'props', 'children', 0])).toBe('Email Two owes $100.00'); - expect(lodashGet(displayNames, [1, 'props', 'children', 0])).toBe('Five, Six'); - expect(lodashGet(displayNames, [2, 'props', 'children', 0])).toBe('Three, Four'); - expect(lodashGet(displayNames, [3, 'props', 'children', 0])).toBe('One, Two'); + expect(displayNames[0].props.children[0]).toBe('Email Two owes $100.00'); + expect(displayNames[1].props.children[0]).toBe('Five, Six'); + expect(displayNames[2].props.children[0]).toBe('Three, Four'); + expect(displayNames[3].props.children[0]).toBe('One, Two'); }) ); }); @@ -360,14 +387,14 @@ describe('Sidebar', () => { const report2 = LHNTestUtils.getFakeReport([3, 4], 3); const fakeReport = LHNTestUtils.getFakeReportWithPolicy([5, 6], 2); const fakePolicy = LHNTestUtils.getFakePolicy(fakeReport.policyID); - const report3 = { + const report3: OnyxTypes.Report = { ...fakeReport, hasOutstandingChildRequest: false, // This has to be added after the IOU report is generated - iouReportID: null, + iouReportID: undefined, }; - const expenseReport = { + const expenseReport: OnyxTypes.Report = { ...LHNTestUtils.getFakeReport([7, 8], 1), type: CONST.REPORT.TYPE.EXPENSE, ownerAccountID: 7, @@ -389,6 +416,13 @@ describe('Sidebar', () => { LHNTestUtils.getDefaultRenderedSidebarLinks(report3.reportID); + const reportCollectionDataSet: ReportCollectionDataSet = { + [`${ONYXKEYS.COLLECTION.REPORT}${report1.reportID}`]: report1, + [`${ONYXKEYS.COLLECTION.REPORT}${report2.reportID}`]: report2, + [`${ONYXKEYS.COLLECTION.REPORT}${report3.reportID}`]: report3, + [`${ONYXKEYS.COLLECTION.REPORT}${expenseReport.reportID}`]: expenseReport, + }; + return ( waitForBatchedUpdates() // When Onyx is updated with the data and the sidebar re-renders @@ -398,10 +432,7 @@ describe('Sidebar', () => { [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, [ONYXKEYS.IS_LOADING_REPORT_DATA]: false, [`${ONYXKEYS.COLLECTION.POLICY}${fakeReport.policyID}`]: fakePolicy, - [`${ONYXKEYS.COLLECTION.REPORT}${report1.reportID}`]: report1, - [`${ONYXKEYS.COLLECTION.REPORT}${report2.reportID}`]: report2, - [`${ONYXKEYS.COLLECTION.REPORT}${report3.reportID}`]: report3, - [`${ONYXKEYS.COLLECTION.REPORT}${expenseReport.reportID}`]: expenseReport, + ...reportCollectionDataSet, }), ) @@ -410,10 +441,10 @@ describe('Sidebar', () => { const hintText = Localize.translateLocal('accessibilityHints.chatUserDisplayNames'); const displayNames = screen.queryAllByLabelText(hintText); expect(displayNames).toHaveLength(4); - expect(lodashGet(displayNames, [0, 'props', 'children', 0])).toBe('Workspace owes $100.00'); - expect(lodashGet(displayNames, [1, 'props', 'children', 0])).toBe('Email Five'); - expect(lodashGet(displayNames, [2, 'props', 'children', 0])).toBe('Three, Four'); - expect(lodashGet(displayNames, [3, 'props', 'children', 0])).toBe('One, Two'); + expect(displayNames[0].props.children[0]).toBe('Workspace owes $100.00'); + expect(displayNames[1].props.children[0]).toBe('Email Five'); + expect(displayNames[2].props.children[0]).toBe('Three, Four'); + expect(displayNames[3].props.children[0]).toBe('One, Two'); }) ); }); @@ -423,7 +454,7 @@ describe('Sidebar', () => { // And the second report has a draft // And the currently viewed report is the second report const report1 = LHNTestUtils.getFakeReport([1, 2], 3); - const report2 = { + const report2: OnyxTypes.Report = { ...LHNTestUtils.getFakeReport([3, 4], 2), hasDraft: true, }; @@ -437,6 +468,12 @@ describe('Sidebar', () => { const currentReportId = report2.reportID; LHNTestUtils.getDefaultRenderedSidebarLinks(currentReportId); + const reportCollectionDataSet: ReportCollectionDataSet = { + [`${ONYXKEYS.COLLECTION.REPORT}${report1.reportID}`]: report1, + [`${ONYXKEYS.COLLECTION.REPORT}${report2.reportID}`]: report2, + [`${ONYXKEYS.COLLECTION.REPORT}${report3.reportID}`]: report3, + }; + return ( waitForBatchedUpdates() // When Onyx is updated with the data and the sidebar re-renders @@ -445,9 +482,7 @@ describe('Sidebar', () => { [ONYXKEYS.NVP_PRIORITY_MODE]: CONST.PRIORITY_MODE.DEFAULT, [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, [ONYXKEYS.IS_LOADING_APP]: false, - [`${ONYXKEYS.COLLECTION.REPORT}${report1.reportID}`]: report1, - [`${ONYXKEYS.COLLECTION.REPORT}${report2.reportID}`]: report2, - [`${ONYXKEYS.COLLECTION.REPORT}${report3.reportID}`]: report3, + ...reportCollectionDataSet, }), ) @@ -465,9 +500,9 @@ describe('Sidebar', () => { const hintText = Localize.translateLocal('accessibilityHints.chatUserDisplayNames'); const displayNames = screen.queryAllByLabelText(hintText); expect(displayNames).toHaveLength(3); - expect(lodashGet(displayNames, [0, 'props', 'children', 0])).toBe('Three, Four'); - expect(lodashGet(displayNames, [1, 'props', 'children', 0])).toBe('Five, Six'); - expect(lodashGet(displayNames, [2, 'props', 'children', 0])).toBe('One, Two'); + expect(displayNames[0].props.children[0]).toBe('Three, Four'); + expect(displayNames[1].props.children[0]).toBe('Five, Six'); + expect(displayNames[2].props.children[0]).toBe('One, Two'); }) ); }); @@ -477,11 +512,15 @@ describe('Sidebar', () => { // Given a single report // And the report has a draft - const report = { + const report: OnyxTypes.Report = { ...LHNTestUtils.getFakeReport([1, 2]), hasDraft: true, }; + const reportCollectionDataSet: ReportCollectionDataSet = { + [`${ONYXKEYS.COLLECTION.REPORT}${report.reportID}`]: report, + }; + return ( waitForBatchedUpdates() // When Onyx is updated with the data and the sidebar re-renders @@ -490,7 +529,7 @@ describe('Sidebar', () => { [ONYXKEYS.NVP_PRIORITY_MODE]: CONST.PRIORITY_MODE.DEFAULT, [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, [ONYXKEYS.IS_LOADING_APP]: false, - [`${ONYXKEYS.COLLECTION.REPORT}${report.reportID}`]: report, + ...reportCollectionDataSet, }), ) @@ -514,11 +553,15 @@ describe('Sidebar', () => { // Given a single report // And the report is pinned - const report = { + const report: OnyxTypes.Report = { ...LHNTestUtils.getFakeReport([1, 2]), isPinned: true, }; + const reportCollectionDataSet: ReportCollectionDataSet = { + [`${ONYXKEYS.COLLECTION.REPORT}${report.reportID}`]: report, + }; + return ( waitForBatchedUpdates() // When Onyx is updated with the data and the sidebar re-renders @@ -527,7 +570,7 @@ describe('Sidebar', () => { [ONYXKEYS.NVP_PRIORITY_MODE]: CONST.PRIORITY_MODE.DEFAULT, [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, [ONYXKEYS.IS_LOADING_APP]: false, - [`${ONYXKEYS.COLLECTION.REPORT}${report.reportID}`]: report, + ...reportCollectionDataSet, }), ) @@ -551,22 +594,22 @@ describe('Sidebar', () => { // with the current user set to email9@ (someone not participating in any of the chats) // with a report that has a draft, a report that is pinned, and // an outstanding IOU report that doesn't belong to the current user - const report1 = { + const report1: OnyxTypes.Report = { ...LHNTestUtils.getFakeReport([1, 2], 3), isPinned: true, }; - const report2 = { + const report2: OnyxTypes.Report = { ...LHNTestUtils.getFakeReport([3, 4], 2), hasDraft: true, }; - const report3 = { + const report3: OnyxTypes.Report = { ...LHNTestUtils.getFakeReport([5, 6], 1), hasOutstandingChildRequest: false, // This has to be added after the IOU report is generated - iouReportID: null, + iouReportID: undefined, }; - const iouReport = { + const iouReport: OnyxTypes.Report = { ...LHNTestUtils.getFakeReport([7, 8]), type: CONST.REPORT.TYPE.IOU, ownerAccountID: 2, @@ -579,9 +622,19 @@ describe('Sidebar', () => { statusNum: CONST.REPORT.STATUS_NUM.SUBMITTED, }; report3.iouReportID = iouReport.reportID; + const currentReportId = report2.reportID; const currentlyLoggedInUserAccountID = 9; + LHNTestUtils.getDefaultRenderedSidebarLinks(currentReportId); + + const reportCollectionDataSet: ReportCollectionDataSet = { + [`${ONYXKEYS.COLLECTION.REPORT}${report1.reportID}`]: report1, + [`${ONYXKEYS.COLLECTION.REPORT}${report2.reportID}`]: report2, + [`${ONYXKEYS.COLLECTION.REPORT}${report3.reportID}`]: report3, + [`${ONYXKEYS.COLLECTION.REPORT}${iouReport.reportID}`]: iouReport, + }; + return ( waitForBatchedUpdates() // When Onyx is updated with the data and the sidebar re-renders @@ -591,10 +644,7 @@ describe('Sidebar', () => { [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, [ONYXKEYS.IS_LOADING_APP]: false, [ONYXKEYS.SESSION]: {accountID: currentlyLoggedInUserAccountID}, - [`${ONYXKEYS.COLLECTION.REPORT}${report1.reportID}`]: report1, - [`${ONYXKEYS.COLLECTION.REPORT}${report2.reportID}`]: report2, - [`${ONYXKEYS.COLLECTION.REPORT}${report3.reportID}`]: report3, - [`${ONYXKEYS.COLLECTION.REPORT}${iouReport.reportID}`]: iouReport, + ...reportCollectionDataSet, }), ) @@ -607,9 +657,9 @@ describe('Sidebar', () => { expect(displayNames).toHaveLength(3); expect(screen.queryAllByTestId('Pin Icon')).toHaveLength(1); expect(screen.queryAllByTestId('Pencil Icon')).toHaveLength(1); - expect(lodashGet(displayNames, [0, 'props', 'children', 0])).toBe('Email Two owes $100.00'); - expect(lodashGet(displayNames, [1, 'props', 'children', 0])).toBe('One, Two'); - expect(lodashGet(displayNames, [2, 'props', 'children', 0])).toBe('Three, Four'); + expect(displayNames[0].props.children[0]).toBe('Email Two owes $100.00'); + expect(displayNames[1].props.children[0]).toBe('One, Two'); + expect(displayNames[2].props.children[0]).toBe('Three, Four'); }) ); }); @@ -617,23 +667,31 @@ describe('Sidebar', () => { it('alphabetizes all the chats that are pinned', () => { // Given three reports in the recently updated order of 3, 2, 1 // and they are all pinned - const report1 = { + const report1: OnyxTypes.Report = { ...LHNTestUtils.getFakeReport([1, 2], 3), isPinned: true, }; - const report2 = { + const report2: OnyxTypes.Report = { ...LHNTestUtils.getFakeReport([3, 4], 2), isPinned: true, }; - const report3 = { + const report3: OnyxTypes.Report = { ...LHNTestUtils.getFakeReport([5, 6], 1), isPinned: true, }; - const report4 = { + const report4: OnyxTypes.Report = { ...LHNTestUtils.getFakeReport([7, 8], 0), isPinned: true, }; + LHNTestUtils.getDefaultRenderedSidebarLinks('0'); + + const reportCollectionDataSet: ReportCollectionDataSet = { + [`${ONYXKEYS.COLLECTION.REPORT}${report1.reportID}`]: report1, + [`${ONYXKEYS.COLLECTION.REPORT}${report2.reportID}`]: report2, + [`${ONYXKEYS.COLLECTION.REPORT}${report3.reportID}`]: report3, + }; + return ( waitForBatchedUpdates() // When Onyx is updated with the data and the sidebar re-renders @@ -642,9 +700,7 @@ describe('Sidebar', () => { [ONYXKEYS.NVP_PRIORITY_MODE]: CONST.PRIORITY_MODE.DEFAULT, [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, [ONYXKEYS.IS_LOADING_APP]: false, - [`${ONYXKEYS.COLLECTION.REPORT}${report1.reportID}`]: report1, - [`${ONYXKEYS.COLLECTION.REPORT}${report2.reportID}`]: report2, - [`${ONYXKEYS.COLLECTION.REPORT}${report3.reportID}`]: report3, + ...reportCollectionDataSet, }), ) @@ -653,9 +709,9 @@ describe('Sidebar', () => { const hintText = Localize.translateLocal('accessibilityHints.chatUserDisplayNames'); const displayNames = screen.queryAllByLabelText(hintText); expect(displayNames).toHaveLength(3); - expect(lodashGet(displayNames, [0, 'props', 'children', 0])).toBe('Five, Six'); - expect(lodashGet(displayNames, [1, 'props', 'children', 0])).toBe('One, Two'); - expect(lodashGet(displayNames, [2, 'props', 'children', 0])).toBe('Three, Four'); + expect(displayNames[0].props.children[0]).toBe('Five, Six'); + expect(displayNames[1].props.children[0]).toBe('One, Two'); + expect(displayNames[2].props.children[0]).toBe('Three, Four'); }) // When a new report is added @@ -666,10 +722,10 @@ describe('Sidebar', () => { const hintText = Localize.translateLocal('accessibilityHints.chatUserDisplayNames'); const displayNames = screen.queryAllByLabelText(hintText); expect(displayNames).toHaveLength(4); - expect(lodashGet(displayNames, [0, 'props', 'children', 0])).toBe('Five, Six'); - expect(lodashGet(displayNames, [1, 'props', 'children', 0])).toBe('One, Two'); - expect(lodashGet(displayNames, [2, 'props', 'children', 0])).toBe('Seven, Eight'); - expect(lodashGet(displayNames, [3, 'props', 'children', 0])).toBe('Three, Four'); + expect(displayNames[0].props.children[0]).toBe('Five, Six'); + expect(displayNames[1].props.children[0]).toBe('One, Two'); + expect(displayNames[2].props.children[0]).toBe('Seven, Eight'); + expect(displayNames[3].props.children[0]).toBe('Three, Four'); }) ); }); @@ -677,23 +733,31 @@ describe('Sidebar', () => { it('alphabetizes all the chats that have drafts', () => { // Given three reports in the recently updated order of 3, 2, 1 // and they all have drafts - const report1 = { + const report1: OnyxTypes.Report = { ...LHNTestUtils.getFakeReport([1, 2], 3), hasDraft: true, }; - const report2 = { + const report2: OnyxTypes.Report = { ...LHNTestUtils.getFakeReport([3, 4], 2), hasDraft: true, }; - const report3 = { + const report3: OnyxTypes.Report = { ...LHNTestUtils.getFakeReport([5, 6], 1), hasDraft: true, }; - const report4 = { + const report4: OnyxTypes.Report = { ...LHNTestUtils.getFakeReport([7, 8], 0), hasDraft: true, }; + LHNTestUtils.getDefaultRenderedSidebarLinks('0'); + + const reportCollectionDataSet: ReportCollectionDataSet = { + [`${ONYXKEYS.COLLECTION.REPORT}${report1.reportID}`]: report1, + [`${ONYXKEYS.COLLECTION.REPORT}${report2.reportID}`]: report2, + [`${ONYXKEYS.COLLECTION.REPORT}${report3.reportID}`]: report3, + }; + return ( waitForBatchedUpdates() // When Onyx is updated with the data and the sidebar re-renders @@ -702,9 +766,7 @@ describe('Sidebar', () => { [ONYXKEYS.NVP_PRIORITY_MODE]: CONST.PRIORITY_MODE.DEFAULT, [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, [ONYXKEYS.IS_LOADING_APP]: false, - [`${ONYXKEYS.COLLECTION.REPORT}${report1.reportID}`]: report1, - [`${ONYXKEYS.COLLECTION.REPORT}${report2.reportID}`]: report2, - [`${ONYXKEYS.COLLECTION.REPORT}${report3.reportID}`]: report3, + ...reportCollectionDataSet, }), ) @@ -713,9 +775,9 @@ describe('Sidebar', () => { const hintText = Localize.translateLocal('accessibilityHints.chatUserDisplayNames'); const displayNames = screen.queryAllByLabelText(hintText); expect(displayNames).toHaveLength(3); - expect(lodashGet(displayNames, [0, 'props', 'children', 0])).toBe('Five, Six'); - expect(lodashGet(displayNames, [1, 'props', 'children', 0])).toBe('One, Two'); - expect(lodashGet(displayNames, [2, 'props', 'children', 0])).toBe('Three, Four'); + expect(displayNames[0].props.children[0]).toBe('Five, Six'); + expect(displayNames[1].props.children[0]).toBe('One, Two'); + expect(displayNames[2].props.children[0]).toBe('Three, Four'); }) // When a new report is added @@ -726,17 +788,17 @@ describe('Sidebar', () => { const hintText = Localize.translateLocal('accessibilityHints.chatUserDisplayNames'); const displayNames = screen.queryAllByLabelText(hintText); expect(displayNames).toHaveLength(4); - expect(lodashGet(displayNames, [0, 'props', 'children', 0])).toBe('Five, Six'); - expect(lodashGet(displayNames, [1, 'props', 'children', 0])).toBe('One, Two'); - expect(lodashGet(displayNames, [2, 'props', 'children', 0])).toBe('Seven, Eight'); - expect(lodashGet(displayNames, [3, 'props', 'children', 0])).toBe('Three, Four'); + expect(displayNames[0].props.children[0]).toBe('Five, Six'); + expect(displayNames[1].props.children[0]).toBe('One, Two'); + expect(displayNames[2].props.children[0]).toBe('Seven, Eight'); + expect(displayNames[3].props.children[0]).toBe('Three, Four'); }) ); }); it('puts archived chats last', () => { // Given three reports, with the first report being archived - const report1 = { + const report1: OnyxTypes.Report = { ...LHNTestUtils.getFakeReport([1, 2]), chatType: CONST.REPORT.CHAT_TYPE.POLICY_ROOM, statusNum: CONST.REPORT.STATUS_NUM.CLOSED, @@ -752,7 +814,15 @@ describe('Sidebar', () => { // Given the user is in all betas const betas = [CONST.BETAS.DEFAULT_ROOMS]; + LHNTestUtils.getDefaultRenderedSidebarLinks('0'); + + const reportCollectionDataSet: ReportCollectionDataSet = { + [`${ONYXKEYS.COLLECTION.REPORT}${report1.reportID}`]: report1, + [`${ONYXKEYS.COLLECTION.REPORT}${report2.reportID}`]: report2, + [`${ONYXKEYS.COLLECTION.REPORT}${report3.reportID}`]: report3, + }; + return ( waitForBatchedUpdates() // When Onyx is updated with the data and the sidebar re-renders @@ -762,9 +832,7 @@ describe('Sidebar', () => { [ONYXKEYS.NVP_PRIORITY_MODE]: CONST.PRIORITY_MODE.DEFAULT, [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, [ONYXKEYS.IS_LOADING_APP]: false, - [`${ONYXKEYS.COLLECTION.REPORT}${report1.reportID}`]: report1, - [`${ONYXKEYS.COLLECTION.REPORT}${report2.reportID}`]: report2, - [`${ONYXKEYS.COLLECTION.REPORT}${report3.reportID}`]: report3, + ...reportCollectionDataSet, }), ) @@ -773,9 +841,9 @@ describe('Sidebar', () => { const hintText = Localize.translateLocal('accessibilityHints.chatUserDisplayNames'); const displayNames = screen.queryAllByLabelText(hintText); expect(displayNames).toHaveLength(3); - expect(lodashGet(displayNames, [0, 'props', 'children', 0])).toBe('Five, Six'); - expect(lodashGet(displayNames, [1, 'props', 'children', 0])).toBe('Three, Four'); - expect(lodashGet(displayNames, [2, 'props', 'children', 0])).toBe('Report (archived)'); + expect(displayNames[0].props.children[0]).toBe('Five, Six'); + expect(displayNames[1].props.children[0]).toBe('Three, Four'); + expect(displayNames[2].props.children[0]).toBe('Report (archived)'); }) ); }); @@ -790,6 +858,12 @@ describe('Sidebar', () => { const report3 = LHNTestUtils.getFakeReport([5, 6], 1, true); const report4 = LHNTestUtils.getFakeReport([7, 8], 0, true); + const reportCollectionDataSet: ReportCollectionDataSet = { + [`${ONYXKEYS.COLLECTION.REPORT}${report1.reportID}`]: report1, + [`${ONYXKEYS.COLLECTION.REPORT}${report2.reportID}`]: report2, + [`${ONYXKEYS.COLLECTION.REPORT}${report3.reportID}`]: report3, + }; + return ( waitForBatchedUpdates() // Given the sidebar is rendered in #focus mode (hides read chats) @@ -799,9 +873,7 @@ describe('Sidebar', () => { [ONYXKEYS.NVP_PRIORITY_MODE]: CONST.PRIORITY_MODE.GSD, [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, [ONYXKEYS.IS_LOADING_APP]: false, - [`${ONYXKEYS.COLLECTION.REPORT}${report1.reportID}`]: report1, - [`${ONYXKEYS.COLLECTION.REPORT}${report2.reportID}`]: report2, - [`${ONYXKEYS.COLLECTION.REPORT}${report3.reportID}`]: report3, + ...reportCollectionDataSet, }), ) @@ -810,9 +882,9 @@ describe('Sidebar', () => { const hintText = Localize.translateLocal('accessibilityHints.chatUserDisplayNames'); const displayNames = screen.queryAllByLabelText(hintText); expect(displayNames).toHaveLength(3); - expect(lodashGet(displayNames, [0, 'props', 'children', 0])).toBe('Five, Six'); - expect(lodashGet(displayNames, [1, 'props', 'children', 0])).toBe('One, Two'); - expect(lodashGet(displayNames, [2, 'props', 'children', 0])).toBe('Three, Four'); + expect(displayNames[0].props.children[0]).toBe('Five, Six'); + expect(displayNames[1].props.children[0]).toBe('One, Two'); + expect(displayNames[2].props.children[0]).toBe('Three, Four'); }) // When a new report is added @@ -823,10 +895,10 @@ describe('Sidebar', () => { const hintText = Localize.translateLocal('accessibilityHints.chatUserDisplayNames'); const displayNames = screen.queryAllByLabelText(hintText); expect(displayNames).toHaveLength(4); - expect(lodashGet(displayNames, [0, 'props', 'children', 0])).toBe('Five, Six'); - expect(lodashGet(displayNames, [1, 'props', 'children', 0])).toBe('One, Two'); - expect(lodashGet(displayNames, [2, 'props', 'children', 0])).toBe('Seven, Eight'); - expect(lodashGet(displayNames, [3, 'props', 'children', 0])).toBe('Three, Four'); + expect(displayNames[0].props.children[0]).toBe('Five, Six'); + expect(displayNames[1].props.children[0]).toBe('One, Two'); + expect(displayNames[2].props.children[0]).toBe('Seven, Eight'); + expect(displayNames[3].props.children[0]).toBe('Three, Four'); }) ); }); @@ -844,7 +916,15 @@ describe('Sidebar', () => { // Given the user is in all betas const betas = [CONST.BETAS.DEFAULT_ROOMS]; + LHNTestUtils.getDefaultRenderedSidebarLinks('0'); + + const reportCollectionDataSet: ReportCollectionDataSet = { + [`${ONYXKEYS.COLLECTION.REPORT}${report1.reportID}`]: report1, + [`${ONYXKEYS.COLLECTION.REPORT}${report2.reportID}`]: report2, + [`${ONYXKEYS.COLLECTION.REPORT}${report3.reportID}`]: report3, + }; + return ( waitForBatchedUpdates() // When Onyx is updated with the data and the sidebar re-renders @@ -854,9 +934,7 @@ describe('Sidebar', () => { [ONYXKEYS.NVP_PRIORITY_MODE]: CONST.PRIORITY_MODE.GSD, [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, [ONYXKEYS.IS_LOADING_APP]: false, - [`${ONYXKEYS.COLLECTION.REPORT}${report1.reportID}`]: report1, - [`${ONYXKEYS.COLLECTION.REPORT}${report2.reportID}`]: report2, - [`${ONYXKEYS.COLLECTION.REPORT}${report3.reportID}`]: report3, + ...reportCollectionDataSet, }), ) @@ -865,46 +943,46 @@ describe('Sidebar', () => { const hintText = Localize.translateLocal('accessibilityHints.chatUserDisplayNames'); const displayNames = screen.queryAllByLabelText(hintText); expect(displayNames).toHaveLength(3); - expect(lodashGet(displayNames, [0, 'props', 'children', 0])).toBe('Five, Six'); - expect(lodashGet(displayNames, [1, 'props', 'children', 0])).toBe('Three, Four'); - expect(lodashGet(displayNames, [2, 'props', 'children', 0])).toBe('Report (archived)'); + expect(displayNames[0].props.children[0]).toBe('Five, Six'); + expect(displayNames[1].props.children[0]).toBe('Three, Four'); + expect(displayNames[2].props.children[0]).toBe('Report (archived)'); }) ); }); it('orders IOU reports by displayName if amounts are the same', () => { // Given three IOU reports containing the same IOU amounts - const report1 = { + const report1: OnyxTypes.Report = { ...LHNTestUtils.getFakeReport([1, 2]), // This has to be added after the IOU report is generated - iouReportID: null, + iouReportID: undefined, }; - const report2 = { + const report2: OnyxTypes.Report = { ...LHNTestUtils.getFakeReport([3, 4]), // This has to be added after the IOU report is generated - iouReportID: null, + iouReportID: undefined, }; - const report3 = { + const report3: OnyxTypes.Report = { ...LHNTestUtils.getFakeReport([5, 6]), // This has to be added after the IOU report is generated - iouReportID: null, + iouReportID: undefined, }; - const report4 = { + const report4: OnyxTypes.Report = { ...LHNTestUtils.getFakeReport([5, 6]), // This has to be added after the IOU report is generated - iouReportID: null, + iouReportID: undefined, }; - const report5 = { + const report5: OnyxTypes.Report = { ...LHNTestUtils.getFakeReport([5, 6]), // This has to be added after the IOU report is generated - iouReportID: null, + iouReportID: undefined, }; - const iouReport1 = { + const iouReport1: OnyxTypes.Report = { ...LHNTestUtils.getFakeReport([7, 8]), type: CONST.REPORT.TYPE.IOU, ownerAccountID: 2, @@ -916,7 +994,7 @@ describe('Sidebar', () => { stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, statusNum: CONST.REPORT.STATUS_NUM.SUBMITTED, }; - const iouReport2 = { + const iouReport2: OnyxTypes.Report = { ...LHNTestUtils.getFakeReport([9, 10]), type: CONST.REPORT.TYPE.IOU, ownerAccountID: 2, @@ -928,7 +1006,7 @@ describe('Sidebar', () => { stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, statusNum: CONST.REPORT.STATUS_NUM.SUBMITTED, }; - const iouReport3 = { + const iouReport3: OnyxTypes.Report = { ...LHNTestUtils.getFakeReport([11, 12]), type: CONST.REPORT.TYPE.IOU, ownerAccountID: 2, @@ -940,7 +1018,7 @@ describe('Sidebar', () => { stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, statusNum: CONST.REPORT.STATUS_NUM.SUBMITTED, }; - const iouReport4 = { + const iouReport4: OnyxTypes.Report = { ...LHNTestUtils.getFakeReport([11, 12]), type: CONST.REPORT.TYPE.IOU, ownerAccountID: 2, @@ -952,7 +1030,7 @@ describe('Sidebar', () => { stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, statusNum: CONST.REPORT.STATUS_NUM.SUBMITTED, }; - const iouReport5 = { + const iouReport5: OnyxTypes.Report = { ...LHNTestUtils.getFakeReport([11, 12]), type: CONST.REPORT.TYPE.IOU, ownerAccountID: 2, @@ -972,7 +1050,22 @@ describe('Sidebar', () => { report5.iouReportID = iouReport5.reportID; const currentlyLoggedInUserAccountID = 13; + LHNTestUtils.getDefaultRenderedSidebarLinks('0'); + + const reportCollectionDataSet: ReportCollectionDataSet = { + [`${ONYXKEYS.COLLECTION.REPORT}${report1.reportID}`]: report1, + [`${ONYXKEYS.COLLECTION.REPORT}${report2.reportID}`]: report2, + [`${ONYXKEYS.COLLECTION.REPORT}${report3.reportID}`]: report3, + [`${ONYXKEYS.COLLECTION.REPORT}${report4.reportID}`]: report4, + [`${ONYXKEYS.COLLECTION.REPORT}${report5.reportID}`]: report5, + [`${ONYXKEYS.COLLECTION.REPORT}${iouReport1.reportID}`]: iouReport1, + [`${ONYXKEYS.COLLECTION.REPORT}${iouReport2.reportID}`]: iouReport2, + [`${ONYXKEYS.COLLECTION.REPORT}${iouReport3.reportID}`]: iouReport3, + [`${ONYXKEYS.COLLECTION.REPORT}${iouReport4.reportID}`]: iouReport4, + [`${ONYXKEYS.COLLECTION.REPORT}${iouReport5.reportID}`]: iouReport5, + }; + return ( waitForBatchedUpdates() // When Onyx is updated with the data and the sidebar re-renders @@ -982,16 +1075,7 @@ describe('Sidebar', () => { [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, [ONYXKEYS.IS_LOADING_APP]: false, [ONYXKEYS.SESSION]: {accountID: currentlyLoggedInUserAccountID}, - [`${ONYXKEYS.COLLECTION.REPORT}${report1.reportID}`]: report1, - [`${ONYXKEYS.COLLECTION.REPORT}${report2.reportID}`]: report2, - [`${ONYXKEYS.COLLECTION.REPORT}${report3.reportID}`]: report3, - [`${ONYXKEYS.COLLECTION.REPORT}${report4.reportID}`]: report4, - [`${ONYXKEYS.COLLECTION.REPORT}${report5.reportID}`]: report5, - [`${ONYXKEYS.COLLECTION.REPORT}${iouReport1.reportID}`]: iouReport1, - [`${ONYXKEYS.COLLECTION.REPORT}${iouReport2.reportID}`]: iouReport2, - [`${ONYXKEYS.COLLECTION.REPORT}${iouReport3.reportID}`]: iouReport3, - [`${ONYXKEYS.COLLECTION.REPORT}${iouReport4.reportID}`]: iouReport4, - [`${ONYXKEYS.COLLECTION.REPORT}${iouReport5.reportID}`]: iouReport5, + ...reportCollectionDataSet, }), ) @@ -1000,11 +1084,11 @@ describe('Sidebar', () => { const hintText = Localize.translateLocal('accessibilityHints.chatUserDisplayNames'); const displayNames = screen.queryAllByLabelText(hintText); expect(displayNames).toHaveLength(5); - expect(lodashGet(displayNames, [0, 'props', 'children', 0])).toBe('Email Five owes $100.00'); - expect(lodashGet(displayNames, [1, 'props', 'children', 0])).toBe('Email Four owes $1,000.00'); - expect(lodashGet(displayNames, [2, 'props', 'children', 0])).toBe('Email Six owes $100.00'); - expect(lodashGet(displayNames, [3, 'props', 'children', 0])).toBe('Email Three owes $100.00'); - expect(lodashGet(displayNames, [4, 'props', 'children', 0])).toBe('Email Two owes $100.00'); + expect(displayNames[0].props.children[0]).toBe('Email Five owes $100.00'); + expect(displayNames[1].props.children[0]).toBe('Email Four owes $1,000.00'); + expect(displayNames[2].props.children[0]).toBe('Email Six owes $100.00'); + expect(displayNames[3].props.children[0]).toBe('Email Three owes $100.00'); + expect(displayNames[4].props.children[0]).toBe('Email Two owes $100.00'); }) ); }); @@ -1012,15 +1096,15 @@ describe('Sidebar', () => { it('orders nonArchived reports by displayName if created timestamps are the same', () => { // Given three nonArchived reports created at the same time const lastVisibleActionCreated = DateUtils.getDBTime(); - const report1 = { + const report1: OnyxTypes.Report = { ...LHNTestUtils.getFakeReport([1, 2]), lastVisibleActionCreated, }; - const report2 = { + const report2: OnyxTypes.Report = { ...LHNTestUtils.getFakeReport([3, 4]), lastVisibleActionCreated, }; - const report3 = { + const report3: OnyxTypes.Report = { ...LHNTestUtils.getFakeReport([5, 6]), lastVisibleActionCreated, }; @@ -1031,6 +1115,13 @@ describe('Sidebar', () => { Report.addComment(report3.reportID, 'Hi, this is a comment'); LHNTestUtils.getDefaultRenderedSidebarLinks('0'); + + const reportCollectionDataSet: ReportCollectionDataSet = { + [`${ONYXKEYS.COLLECTION.REPORT}${report1.reportID}`]: report1, + [`${ONYXKEYS.COLLECTION.REPORT}${report2.reportID}`]: report2, + [`${ONYXKEYS.COLLECTION.REPORT}${report3.reportID}`]: report3, + }; + return ( waitForBatchedUpdates() // When Onyx is updated with the data and the sidebar re-renders @@ -1039,9 +1130,7 @@ describe('Sidebar', () => { [ONYXKEYS.NVP_PRIORITY_MODE]: CONST.PRIORITY_MODE.DEFAULT, [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, [ONYXKEYS.IS_LOADING_APP]: false, - [`${ONYXKEYS.COLLECTION.REPORT}${report1.reportID}`]: report1, - [`${ONYXKEYS.COLLECTION.REPORT}${report2.reportID}`]: report2, - [`${ONYXKEYS.COLLECTION.REPORT}${report3.reportID}`]: report3, + ...reportCollectionDataSet, }), ) @@ -1050,9 +1139,9 @@ describe('Sidebar', () => { const hintText = Localize.translateLocal('accessibilityHints.chatUserDisplayNames'); const displayNames = screen.queryAllByLabelText(hintText); expect(displayNames).toHaveLength(3); - expect(lodashGet(displayNames, [0, 'props', 'children', 0])).toBe('Five, Six'); - expect(lodashGet(displayNames, [1, 'props', 'children', 0])).toBe('One, Two'); - expect(lodashGet(displayNames, [2, 'props', 'children', 0])).toBe('Three, Four'); + expect(displayNames[0].props.children[0]).toBe('Five, Six'); + expect(displayNames[1].props.children[0]).toBe('One, Two'); + expect(displayNames[2].props.children[0]).toBe('Three, Four'); }) ); }); diff --git a/tests/utils/LHNTestUtils.js b/tests/utils/LHNTestUtils.tsx similarity index 68% rename from tests/utils/LHNTestUtils.js rename to tests/utils/LHNTestUtils.tsx index d44a63d51821..80f28002f975 100644 --- a/tests/utils/LHNTestUtils.js +++ b/tests/utils/LHNTestUtils.tsx @@ -1,21 +1,41 @@ +/* eslint-disable @typescript-eslint/naming-convention */ +import type {NavigationProp} from '@react-navigation/core/src/types'; +import type * as Navigation from '@react-navigation/native'; +import type {ParamListBase} from '@react-navigation/routers'; import {render} from '@testing-library/react-native'; -import PropTypes from 'prop-types'; +import type {ReactElement} from 'react'; import React from 'react'; -import ComposeProviders from '../../src/components/ComposeProviders'; -import {LocaleContextProvider} from '../../src/components/LocaleContextProvider'; -import OnyxProvider from '../../src/components/OnyxProvider'; -import {CurrentReportIDContextProvider} from '../../src/components/withCurrentReportID'; -import {EnvironmentProvider} from '../../src/components/withEnvironment'; -import CONST from '../../src/CONST'; -import DateUtils from '../../src/libs/DateUtils'; -import ReportActionItemSingle from '../../src/pages/home/report/ReportActionItemSingle'; -import reportActionPropTypes from '../../src/pages/home/report/reportActionPropTypes'; -import SidebarLinksData from '../../src/pages/home/sidebar/SidebarLinksData'; -import reportPropTypes from '../../src/pages/reportPropTypes'; +import ComposeProviders from '@components/ComposeProviders'; +import {LocaleContextProvider} from '@components/LocaleContextProvider'; +import OnyxProvider from '@components/OnyxProvider'; +import {CurrentReportIDContextProvider} from '@components/withCurrentReportID'; +import {EnvironmentProvider} from '@components/withEnvironment'; +import DateUtils from '@libs/DateUtils'; +import ReportActionItemSingle from '@pages/home/report/ReportActionItemSingle'; +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'; + +type MockedReportActionItemSingleProps = { + /** Determines if the avatar is displayed as a subscript (positioned lower than normal) */ + shouldShowSubscriptAvatar?: boolean; + + /** Report for this action */ + report: Report; + + /** All the data of the action */ + reportAction: ReportAction; +}; + +type MockedSidebarLinksProps = { + /** Current report id */ + currentReportID?: string; +}; // we have to mock `useIsFocused` because it's used in the SidebarLinks component -const mockedNavigate = jest.fn(); -jest.mock('@react-navigation/native', () => { +const mockedNavigate: jest.MockedFn<NavigationProp<ParamListBase>['navigate']> = jest.fn(); +jest.mock('@react-navigation/native', (): typeof Navigation => { const actualNav = jest.requireActual('@react-navigation/native'); return { ...actualNav, @@ -28,10 +48,10 @@ jest.mock('@react-navigation/native', () => { addListener: jest.fn(), }), createNavigationContainerRef: jest.fn(), - }; + } as typeof Navigation; }); -const fakePersonalDetails = { +const fakePersonalDetails: PersonalDetailsList = { 1: { accountID: 1, login: 'email1@test.com', @@ -101,13 +121,11 @@ let lastFakeReportID = 0; let lastFakeReportActionID = 0; /** - * @param {Number[]} participantAccountIDs - * @param {Number} millisecondsInThePast the number of milliseconds in the past for the last message timestamp (to order reports by most recent messages) - * @param {boolean} isUnread - * @returns {Object} + * @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) { +function getFakeReport(participantAccountIDs = [1, 2], millisecondsInThePast = 0, isUnread = false): Report { const lastVisibleActionCreated = DateUtils.getDBTime(Date.now() - millisecondsInThePast); + return { type: CONST.REPORT.TYPE.CHAT, reportID: `${++lastFakeReportID}`, @@ -119,12 +137,11 @@ function getFakeReport(participantAccountIDs = [1, 2], millisecondsInThePast = 0 } /** - * @param {String} actor - * @param {Number} millisecondsInThePast the number of milliseconds in the past for the last message timestamp (to order reports by most recent messages) - * @returns {Object} + * @param millisecondsInThePast the number of milliseconds in the past for the last message timestamp (to order reports by most recent messages) */ -function getFakeReportAction(actor = 'email1@test.com', millisecondsInThePast = 0) { - const timestamp = DateUtils.getDBTime(Date.now() - millisecondsInThePast); +function getFakeReportAction(actor = 'email1@test.com', millisecondsInThePast = 0): ReportAction { + const timestamp = Date.now() - millisecondsInThePast; + const created = DateUtils.getDBTime(timestamp); return { actor, @@ -132,6 +149,7 @@ function getFakeReportAction(actor = 'email1@test.com', millisecondsInThePast = reportActionID: `${++lastFakeReportActionID}`, actionName: CONST.REPORT.ACTIONS.TYPE.CREATED, shouldShow: true, + created, timestamp, reportActionTimestamp: timestamp, person: [ @@ -195,35 +213,23 @@ function getFakeReportAction(actor = 'email1@test.com', millisecondsInThePast = }; } -/** - * @param {boolean} isArchived - * @param {boolean} isUserCreatedPolicyRoom - * @param {boolean} hasAddWorkspaceError - * @param {boolean} isUnread - * @param {boolean} isPinned - * @param {boolean} hasDraft - * @returns {Object} - */ -function getAdvancedFakeReport(isArchived, isUserCreatedPolicyRoom, hasAddWorkspaceError, isUnread, isPinned, hasDraft) { +function getAdvancedFakeReport(isArchived: boolean, isUserCreatedPolicyRoom: boolean, hasAddWorkspaceError: boolean, isUnread: boolean, isPinned: boolean, hasDraft: boolean): Report { return { ...getFakeReport([1, 2], 0, isUnread), type: CONST.REPORT.TYPE.CHAT, chatType: isUserCreatedPolicyRoom ? CONST.REPORT.CHAT_TYPE.POLICY_ROOM : CONST.REPORT.CHAT_TYPE.POLICY_ADMINS, statusNum: isArchived ? CONST.REPORT.STATUS_NUM.CLOSED : 0, stateNum: isArchived ? CONST.REPORT.STATE_NUM.APPROVED : 0, - errorFields: hasAddWorkspaceError ? {addWorkspaceRoom: 'blah'} : null, + errorFields: hasAddWorkspaceError ? {1708946640843000: {addWorkspaceRoom: 'blah'}} : undefined, isPinned, hasDraft, }; } /** - * @param {Number[]} [participantAccountIDs] - * @param {Number} [millisecondsInThePast] the number of milliseconds in the past for the last message timestamp (to order reports by most recent messages) - * @param {boolean} [isUnread] - * @returns {Object} + * @param millisecondsInThePast the number of milliseconds in the past for the last message timestamp (to order reports by most recent messages) */ -function getFakeReportWithPolicy(participantAccountIDs = [1, 2], millisecondsInThePast = 0, isUnread = false) { +function getFakeReportWithPolicy(participantAccountIDs = [1, 2], millisecondsInThePast = 0, isUnread = false): Report { return { ...getFakeReport(participantAccountIDs, millisecondsInThePast, isUnread), type: CONST.REPORT.TYPE.CHAT, @@ -235,12 +241,7 @@ function getFakeReportWithPolicy(participantAccountIDs = [1, 2], millisecondsInT }; } -/** - * @param {Number} [id] - * @param {String} [name] - * @returns {Object} - */ -function getFakePolicy(id = 1, name = 'Workspace-Test-001') { +function getFakePolicy(id = '1', name = 'Workspace-Test-001'): Policy { return { id, name, @@ -252,7 +253,7 @@ function getFakePolicy(id = 1, name = 'Workspace-Test-001') { avatar: '', employeeList: [], isPolicyExpenseChatEnabled: true, - lastModified: 1697323926777105, + lastModified: '1697323926777105', autoReporting: true, autoReportingFrequency: 'immediate', harvesting: { @@ -268,47 +269,20 @@ function getFakePolicy(id = 1, name = 'Workspace-Test-001') { } /** - * @param {String} actionName - * @param {String} actor - * @param {Number} millisecondsInThePast the number of milliseconds in the past for the last message timestamp (to order reports by most recent messages) - * @returns {Object} + * @param millisecondsInThePast the number of milliseconds in the past for the last message timestamp (to order reports by most recent messages) */ -function getFakeAdvancedReportAction(actionName = 'IOU', actor = 'email1@test.com', millisecondsInThePast = 0) { +function getFakeAdvancedReportAction(actionName: ActionName = 'IOU', actor = 'email1@test.com', millisecondsInThePast = 0): ReportAction { return { ...getFakeReportAction(actor, millisecondsInThePast), actionName, - }; + } as ReportAction; } -/** - * @param {String} [currentReportID] - */ -function getDefaultRenderedSidebarLinks(currentReportID = '') { - // A try-catch block needs to be added to the rendering so that any errors that happen while the component - // renders are caught and logged to the console. Without the try-catch block, Jest might only report the error - // as "The above error occurred in your component", without providing specific details. By using a try-catch block, - // any errors are caught and logged, allowing you to identify the exact error that might be causing a rendering issue - // when developing tests. - - try { - // Wrap the SideBarLinks inside of LocaleContextProvider so that all the locale props - // are passed to the component. If this is not done, then all the locale props are missing - // and there are a lot of render warnings. It needs to be done like this because normally in - // our app (App.js) is when the react application is wrapped in the context providers - render(<MockedSidebarLinks currentReportID={currentReportID} />); - } catch (error) { - console.error(error); - } -} - -/** - * @param {String} [currentReportID] - * @returns {JSX.Element} - */ -function MockedSidebarLinks({currentReportID}) { +function MockedSidebarLinks({currentReportID = ''}: MockedSidebarLinksProps) { return ( <ComposeProviders components={[OnyxProvider, LocaleContextProvider, EnvironmentProvider, CurrentReportIDContextProvider]}> <SidebarLinksData + // @ts-expect-error TODO: Remove this once SidebarLinksData (https://github.com/Expensify/App/issues/25220) is migrated to TypeScript. onLinkClick={() => {}} insets={{ top: 0, @@ -323,18 +297,7 @@ function MockedSidebarLinks({currentReportID}) { ); } -MockedSidebarLinks.propTypes = { - currentReportID: PropTypes.string, -}; - -MockedSidebarLinks.defaultProps = { - currentReportID: '', -}; - -/** - * @param {React.ReactElement} component - */ -function internalRender(component) { +function getDefaultRenderedSidebarLinks(currentReportID = '') { // A try-catch block needs to be added to the rendering so that any errors that happen while the component // renders are caught and logged to the console. Without the try-catch block, Jest might only report the error // as "The above error occurred in your component", without providing specific details. By using a try-catch block, @@ -342,54 +305,36 @@ function internalRender(component) { // when developing tests. try { - render(component); + // Wrap the SideBarLinks inside of LocaleContextProvider so that all the locale props + // are passed to the component. If this is not done, then all the locale props are missing + // and there are a lot of render warnings. It needs to be done like this because normally in + // our app (App.js) is when the react application is wrapped in the context providers + render(<MockedSidebarLinks currentReportID={currentReportID} />); } catch (error) { console.error(error); } } -/** - * @param {Boolean} [shouldShowSubscriptAvatar] - * @param {Object} [report] - * @param {Object} [reportAction] - */ -function getDefaultRenderedReportActionItemSingle(shouldShowSubscriptAvatar = true, report = null, reportAction = null) { - const currentReport = report || getFakeReport(); - const currentReportAction = reportAction || getFakeAdvancedReportAction(); +function internalRender(component: ReactElement) { + // A try-catch block needs to be added to the rendering so that any errors that happen while the component + // renders are caught and logged to the console. Without the try-catch block, Jest might only report the error + // as "The above error occurred in your component", without providing specific details. By using a try-catch block, + // any errors are caught and logged, allowing you to identify the exact error that might be causing a rendering issue + // when developing tests. - internalRender( - <MockedReportActionItemSingle - shouldShowSubscriptAvatar={shouldShowSubscriptAvatar} - report={currentReport} - reportAction={currentReportAction} - />, - ); + try { + render(component); + } catch (error) { + console.error(error); + } } -/** - * @param {Boolean} shouldShowSubscriptAvatar - * @param {Object} report - * @param {Object} reportAction - * @returns {JSX.Element} - */ -function MockedReportActionItemSingle({shouldShowSubscriptAvatar, report, reportAction}) { - const personalDetailsList = { - [reportAction.actorAccountID]: { - accountID: reportAction.actorAccountID, - login: 'email1@test.com', - displayName: 'Email One', - avatar: 'https://example.com/avatar.png', - firstName: 'One', - }, - }; - +function MockedReportActionItemSingle({shouldShowSubscriptAvatar = true, report, reportAction}: MockedReportActionItemSingleProps) { return ( <ComposeProviders components={[OnyxProvider, LocaleContextProvider, EnvironmentProvider, CurrentReportIDContextProvider]}> <ReportActionItemSingle action={reportAction} report={report} - personalDetailsList={personalDetailsList} - wrapperStyles={[{display: 'inline'}]} showHeader shouldShowSubscriptAvatar={shouldShowSubscriptAvatar} hasBeenFlagged={false} @@ -400,17 +345,18 @@ function MockedReportActionItemSingle({shouldShowSubscriptAvatar, report, report ); } -MockedReportActionItemSingle.propTypes = { - shouldShowSubscriptAvatar: PropTypes.bool, - report: reportPropTypes, - reportAction: PropTypes.shape(reportActionPropTypes), -}; +function getDefaultRenderedReportActionItemSingle(shouldShowSubscriptAvatar = true, report?: Report, reportAction?: ReportAction) { + const currentReport = report ?? getFakeReport(); + const currentReportAction = reportAction ?? getFakeAdvancedReportAction(); -MockedReportActionItemSingle.defaultProps = { - shouldShowSubscriptAvatar: true, - report: null, - reportAction: null, -}; + internalRender( + <MockedReportActionItemSingle + shouldShowSubscriptAvatar={shouldShowSubscriptAvatar} + report={currentReport} + reportAction={currentReportAction} + />, + ); +} export { fakePersonalDetails, From c3f8de2cc58a63bc23908fdc0a483976dd930a84 Mon Sep 17 00:00:00 2001 From: VickyStash <vikstash@gmail.com> Date: Tue, 27 Feb 2024 09:39:24 +0100 Subject: [PATCH 3/5] [TS migration] Migrate 'SidebarFilterTest.js' test --- src/types/onyx/Report.ts | 6 +- ...ebarFilterTest.js => SidebarFilterTest.ts} | 194 ++++++++++++------ tests/unit/SidebarOrderTest.ts | 9 +- 3 files changed, 137 insertions(+), 72 deletions(-) rename tests/unit/{SidebarFilterTest.js => SidebarFilterTest.ts} (84%) diff --git a/src/types/onyx/Report.ts b/src/types/onyx/Report.ts index f5c4606fd335..ed6cdda3175e 100644 --- a/src/types/onyx/Report.ts +++ b/src/types/onyx/Report.ts @@ -1,5 +1,7 @@ import type {ValueOf} from 'type-fest'; import type CONST from '@src/CONST'; +import ONYXKEYS from '@src/ONYXKEYS'; +import type * as OnyxTypes from '@src/types/onyx/index'; import type * as OnyxCommon from './OnyxCommon'; import type PersonalDetails from './PersonalDetails'; import type {PolicyReportField} from './PolicyReportField'; @@ -178,6 +180,8 @@ type Report = { reportFields?: Record<string, PolicyReportField>; }; +type ReportCollectionDataSet = Record<`${typeof ONYXKEYS.COLLECTION.REPORT}${string}`, Report>; + export default Report; -export type {NotificationPreference, RoomVisibility, WriteCapability, Note}; +export type {NotificationPreference, RoomVisibility, WriteCapability, Note, ReportCollectionDataSet}; diff --git a/tests/unit/SidebarFilterTest.js b/tests/unit/SidebarFilterTest.ts similarity index 84% rename from tests/unit/SidebarFilterTest.js rename to tests/unit/SidebarFilterTest.ts index 148710cb2d25..58ec66698b83 100644 --- a/tests/unit/SidebarFilterTest.js +++ b/tests/unit/SidebarFilterTest.ts @@ -1,17 +1,18 @@ import {cleanup, screen} from '@testing-library/react-native'; -import lodashGet from 'lodash/get'; import Onyx from 'react-native-onyx'; -import CONST from '../../src/CONST'; -import DateUtils from '../../src/libs/DateUtils'; -import * as Localize from '../../src/libs/Localize'; +import DateUtils from '@libs/DateUtils'; +import * as Localize from '@libs/Localize'; +import CONST from '@src/CONST'; +import type {Report} from '@src/types/onyx'; +import type {ReportCollectionDataSet} from '@src/types/onyx/Report'; import * as LHNTestUtils from '../utils/LHNTestUtils'; import waitForBatchedUpdates from '../utils/waitForBatchedUpdates'; import wrapOnyxWithWaitForBatchedUpdates from '../utils/wrapOnyxWithWaitForBatchedUpdates'; // Be sure to include the mocked permissions library, as some components that are rendered // during the test depend on its methods. -jest.mock('../../src/libs/Permissions'); -jest.mock('../../src/hooks/usePermissions.ts'); +jest.mock('@libs/Permissions'); +jest.mock('@hooks/usePermissions.ts'); const ONYXKEYS = { PERSONAL_DETAILS_LIST: 'personalDetailsList', @@ -25,14 +26,13 @@ const ONYXKEYS = { POLICY: 'policy_', }, NETWORK: 'network', -}; +} as const; // We need to fix this test as a follow up. There seems to be some problems with memory after filtering got more complicated. xdescribe('Sidebar', () => { beforeAll(() => Onyx.init({ keys: ONYXKEYS, - registerStorageEventListener: () => {}, safeEvictionKeys: [ONYXKEYS.COLLECTION.REPORT_ACTIONS], }), ); @@ -57,14 +57,14 @@ xdescribe('Sidebar', () => { // Given a report with no participants const report = LHNTestUtils.getFakeReport([]); + const reportCollectionDataSet: ReportCollectionDataSet = { + [`${ONYXKEYS.COLLECTION.REPORT}${report.reportID}`]: report, + }; + return ( waitForBatchedUpdates() // When Onyx is updated to contain that report - .then(() => - Onyx.multiSet({ - [`${ONYXKEYS.COLLECTION.REPORT}${report.reportID}`]: report, - }), - ) + .then(() => Onyx.multiSet(reportCollectionDataSet)) // Then no reports are rendered in the LHN .then(() => { @@ -79,15 +79,19 @@ xdescribe('Sidebar', () => { LHNTestUtils.getDefaultRenderedSidebarLinks(); // Given a new report - const report = LHNTestUtils.getFakeReport(['emptychat+1@test.com', 'emptychat+2@test.com'], 0); + const report = LHNTestUtils.getFakeReport([1, 2], 0); + + const reportCollectionDataSet: ReportCollectionDataSet = { + [`${ONYXKEYS.COLLECTION.REPORT}${report.reportID}`]: report, + }; return ( waitForBatchedUpdates() // When Onyx is updated to contain that report .then(() => Onyx.multiSet({ - [`${ONYXKEYS.COLLECTION.REPORT}${report.reportID}`]: report, [ONYXKEYS.IS_LOADING_APP]: false, + ...reportCollectionDataSet, }), ) @@ -104,19 +108,23 @@ xdescribe('Sidebar', () => { LHNTestUtils.getDefaultRenderedSidebarLinks(); // Given a new report with a draft text - const report = { + const report: Report = { ...LHNTestUtils.getFakeReport([1, 2], 0), hasDraft: true, }; + const reportCollectionDataSet: ReportCollectionDataSet = { + [`${ONYXKEYS.COLLECTION.REPORT}${report.reportID}`]: report, + }; + return ( waitForBatchedUpdates() // When Onyx is updated to contain that report .then(() => Onyx.multiSet({ - [`${ONYXKEYS.COLLECTION.REPORT}${report.reportID}`]: report, [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, [ONYXKEYS.IS_LOADING_APP]: false, + ...reportCollectionDataSet, }), ) @@ -134,11 +142,15 @@ xdescribe('Sidebar', () => { // Given a user created policy room report // and the user not being in any betas - const report = { + const report: Report = { ...LHNTestUtils.getFakeReport(), chatType: CONST.REPORT.CHAT_TYPE.POLICY_ROOM, }; + const reportCollectionDataSet: ReportCollectionDataSet = { + [`${ONYXKEYS.COLLECTION.REPORT}${report.reportID}`]: report, + }; + return ( waitForBatchedUpdates() // When Onyx is updated to contain that data and the sidebar re-renders @@ -147,7 +159,7 @@ xdescribe('Sidebar', () => { [ONYXKEYS.BETAS]: [], [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, [ONYXKEYS.IS_LOADING_APP]: false, - [`${ONYXKEYS.COLLECTION.REPORT}${report.reportID}`]: report, + ...reportCollectionDataSet, }), ) @@ -165,19 +177,25 @@ xdescribe('Sidebar', () => { // Given three reports with the three different types of default policy rooms // and the user not being in any betas - const report1 = { + const report1: Report = { ...LHNTestUtils.getFakeReport(), chatType: CONST.REPORT.CHAT_TYPE.POLICY_ADMINS, }; - const report2 = { + const report2: Report = { ...LHNTestUtils.getFakeReport([3, 4]), chatType: CONST.REPORT.CHAT_TYPE.POLICY_ANNOUNCE, }; - const report3 = { + const report3: Report = { ...LHNTestUtils.getFakeReport([5, 6]), chatType: CONST.REPORT.CHAT_TYPE.DOMAIN_ALL, }; + const reportCollectionDataSet: ReportCollectionDataSet = { + [`${ONYXKEYS.COLLECTION.REPORT}${report1.reportID}`]: report1, + [`${ONYXKEYS.COLLECTION.REPORT}${report2.reportID}`]: report2, + [`${ONYXKEYS.COLLECTION.REPORT}${report3.reportID}`]: report3, + }; + return ( waitForBatchedUpdates() // When Onyx is updated to contain that data and the sidebar re-renders @@ -186,9 +204,7 @@ xdescribe('Sidebar', () => { [ONYXKEYS.BETAS]: [], [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, [ONYXKEYS.IS_LOADING_APP]: false, - [`${ONYXKEYS.COLLECTION.REPORT}${report1.reportID}`]: report1, - [`${ONYXKEYS.COLLECTION.REPORT}${report2.reportID}`]: report2, - [`${ONYXKEYS.COLLECTION.REPORT}${report3.reportID}`]: report3, + ...reportCollectionDataSet, }), ) @@ -224,12 +240,16 @@ xdescribe('Sidebar', () => { policyID: '1', type: CONST.POLICY.TYPE.FREE, }; - const report = { + const report: Report = { ...LHNTestUtils.getFakeReport(), chatType: CONST.REPORT.CHAT_TYPE.POLICY_ADMINS, policyID: policy.policyID, }; + const reportCollectionDataSet: ReportCollectionDataSet = { + [`${ONYXKEYS.COLLECTION.REPORT}${report.reportID}`]: report, + }; + return ( waitForBatchedUpdates() // When Onyx is updated to contain that data and the sidebar re-renders @@ -238,8 +258,8 @@ xdescribe('Sidebar', () => { [ONYXKEYS.BETAS]: [], [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, [ONYXKEYS.IS_LOADING_APP]: false, - [`${ONYXKEYS.COLLECTION.REPORT}${report.reportID}`]: report, [`${ONYXKEYS.COLLECTION.POLICY}${policy.policyID}`]: policy, + ...reportCollectionDataSet, }), ) @@ -299,7 +319,7 @@ xdescribe('Sidebar', () => { const AMOUNT_OF_VARIABLES = 6; // eslint-disable-next-line no-bitwise for (let i = 0; i < 1 << AMOUNT_OF_VARIABLES; i++) { - const boolArr = []; + const boolArr: boolean[] = []; for (let j = AMOUNT_OF_VARIABLES - 1; j >= 0; j--) { // eslint-disable-next-line no-bitwise boolArr.push(Boolean(i & (1 << j))); @@ -309,13 +329,19 @@ xdescribe('Sidebar', () => { // for the specific case that's failing. You can then debug the code to see why the test is not passing. // const boolArr = [false, false, false, false, false]; - it(`the booleans ${boolArr}`, () => { - const report2 = { - ...LHNTestUtils.getAdvancedFakeReport(...boolArr), + it(`the booleans ${JSON.stringify(boolArr)}`, () => { + const [isArchived, isUserCreatedPolicyRoom, hasAddWorkspaceError, isUnread, isPinned, hasDraft] = boolArr; + const report2: Report = { + ...LHNTestUtils.getAdvancedFakeReport(isArchived, isUserCreatedPolicyRoom, hasAddWorkspaceError, isUnread, isPinned, hasDraft), policyID: policy.policyID, }; LHNTestUtils.getDefaultRenderedSidebarLinks(report1.reportID); + const reportCollectionDataSet: ReportCollectionDataSet = { + [`${ONYXKEYS.COLLECTION.REPORT}${report1.reportID}`]: report1, + [`${ONYXKEYS.COLLECTION.REPORT}${report2.reportID}`]: report2, + }; + return ( waitForBatchedUpdates() // When Onyx is updated to contain that data and the sidebar re-renders @@ -325,9 +351,8 @@ xdescribe('Sidebar', () => { [ONYXKEYS.BETAS]: betas, [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, [ONYXKEYS.IS_LOADING_APP]: false, - [`${ONYXKEYS.COLLECTION.REPORT}${report1.reportID}`]: report1, - [`${ONYXKEYS.COLLECTION.REPORT}${report2.reportID}`]: report2, [`${ONYXKEYS.COLLECTION.POLICY}${policy.policyID}`]: policy, + ...reportCollectionDataSet, }), ) // Then depending on the outcome, either one or two reports are visible @@ -339,7 +364,7 @@ xdescribe('Sidebar', () => { const navigatesToChatHintText = Localize.translateLocal('accessibilityHints.navigatesToChat'); expect(screen.queryAllByAccessibilityHint(navigatesToChatHintText)).toHaveLength(1); expect(displayNames).toHaveLength(1); - expect(lodashGet(displayNames, [0, 'props', 'children', 0])).toBe('Three, Four'); + expect(displayNames[0].props.children[0]).toBe('Three, Four'); } else { // Both reports visible const navigatesToChatHintText = Localize.translateLocal('accessibilityHints.navigatesToChat'); @@ -361,6 +386,12 @@ xdescribe('Sidebar', () => { const report3 = LHNTestUtils.getFakeReport([5, 6]); LHNTestUtils.getDefaultRenderedSidebarLinks(report1.reportID); + const reportCollectionDataSet: ReportCollectionDataSet = { + [`${ONYXKEYS.COLLECTION.REPORT}${report1.reportID}`]: report1, + [`${ONYXKEYS.COLLECTION.REPORT}${report2.reportID}`]: report2, + [`${ONYXKEYS.COLLECTION.REPORT}${report3.reportID}`]: report3, + }; + return ( waitForBatchedUpdates() // When Onyx is updated to contain that data and the sidebar re-renders @@ -369,9 +400,7 @@ xdescribe('Sidebar', () => { [ONYXKEYS.NVP_PRIORITY_MODE]: CONST.PRIORITY_MODE.GSD, [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, [ONYXKEYS.IS_LOADING_APP]: false, - [`${ONYXKEYS.COLLECTION.REPORT}${report1.reportID}`]: report1, - [`${ONYXKEYS.COLLECTION.REPORT}${report2.reportID}`]: report2, - [`${ONYXKEYS.COLLECTION.REPORT}${report3.reportID}`]: report3, + ...reportCollectionDataSet, }), ) @@ -380,8 +409,8 @@ xdescribe('Sidebar', () => { const hintText = Localize.translateLocal('accessibilityHints.chatUserDisplayNames'); const displayNames = screen.queryAllByLabelText(hintText); expect(displayNames).toHaveLength(2); - expect(lodashGet(displayNames, [0, 'props', 'children', 0])).toBe('One, Two'); - expect(lodashGet(displayNames, [1, 'props', 'children', 0])).toBe('Three, Four'); + expect(displayNames[0].props.children[0]).toBe('One, Two'); + expect(displayNames[1].props.children[0]).toBe('Three, Four'); }) // When report3 becomes unread @@ -432,6 +461,11 @@ xdescribe('Sidebar', () => { }; LHNTestUtils.getDefaultRenderedSidebarLinks(draftReport.reportID); + const reportCollectionDataSet: ReportCollectionDataSet = { + [`${ONYXKEYS.COLLECTION.REPORT}${draftReport.reportID}`]: draftReport, + [`${ONYXKEYS.COLLECTION.REPORT}${pinnedReport.reportID}`]: pinnedReport, + }; + return ( waitForBatchedUpdates() // When Onyx is updated to contain that data and the sidebar re-renders @@ -440,8 +474,7 @@ xdescribe('Sidebar', () => { [ONYXKEYS.NVP_PRIORITY_MODE]: CONST.PRIORITY_MODE.GSD, [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, [ONYXKEYS.IS_LOADING_APP]: false, - [`${ONYXKEYS.COLLECTION.REPORT}${draftReport.reportID}`]: draftReport, - [`${ONYXKEYS.COLLECTION.REPORT}${pinnedReport.reportID}`]: pinnedReport, + ...reportCollectionDataSet, }), ) @@ -450,26 +483,26 @@ xdescribe('Sidebar', () => { const hintText = Localize.translateLocal('accessibilityHints.chatUserDisplayNames'); const displayNames = screen.queryAllByLabelText(hintText); expect(displayNames).toHaveLength(2); - expect(lodashGet(displayNames, [0, 'props', 'children', 0])).toBe('Three, Four'); - expect(lodashGet(displayNames, [1, 'props', 'children', 0])).toBe('One, Two'); + expect(displayNames[0].props.children[0]).toBe('Three, Four'); + expect(displayNames[1].props.children[0]).toBe('One, Two'); }) ); }); it('archived rooms are displayed only when they have unread messages', () => { // Given an archived chat report, an archived default policy room, and an archived user created policy room - const archivedReport = { + const archivedReport: Report = { ...LHNTestUtils.getFakeReport([1, 2]), statusNum: CONST.REPORT.STATUS_NUM.CLOSED, stateNum: CONST.REPORT.STATE_NUM.APPROVED, }; - const archivedPolicyRoomReport = { + const archivedPolicyRoomReport: Report = { ...LHNTestUtils.getFakeReport([1, 2]), chatType: CONST.REPORT.CHAT_TYPE.POLICY_ANNOUNCE, statusNum: CONST.REPORT.STATUS_NUM.CLOSED, stateNum: CONST.REPORT.STATE_NUM.APPROVED, }; - const archivedUserCreatedPolicyRoomReport = { + const archivedUserCreatedPolicyRoomReport: Report = { ...LHNTestUtils.getFakeReport([1, 2]), chatType: CONST.REPORT.CHAT_TYPE.POLICY_ROOM, statusNum: CONST.REPORT.STATUS_NUM.CLOSED, @@ -479,6 +512,12 @@ xdescribe('Sidebar', () => { const betas = [CONST.BETAS.DEFAULT_ROOMS]; + const reportCollectionDataSet: ReportCollectionDataSet = { + [`${ONYXKEYS.COLLECTION.REPORT}${archivedReport.reportID}`]: archivedReport, + [`${ONYXKEYS.COLLECTION.REPORT}${archivedPolicyRoomReport.reportID}`]: archivedPolicyRoomReport, + [`${ONYXKEYS.COLLECTION.REPORT}${archivedUserCreatedPolicyRoomReport.reportID}`]: archivedUserCreatedPolicyRoomReport, + }; + return ( waitForBatchedUpdates() // When Onyx is updated to contain that data and the sidebar re-renders @@ -488,9 +527,7 @@ xdescribe('Sidebar', () => { [ONYXKEYS.BETAS]: betas, [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, [ONYXKEYS.IS_LOADING_APP]: false, - [`${ONYXKEYS.COLLECTION.REPORT}${archivedReport.reportID}`]: archivedReport, - [`${ONYXKEYS.COLLECTION.REPORT}${archivedPolicyRoomReport.reportID}`]: archivedPolicyRoomReport, - [`${ONYXKEYS.COLLECTION.REPORT}${archivedUserCreatedPolicyRoomReport.reportID}`]: archivedUserCreatedPolicyRoomReport, + ...reportCollectionDataSet, }), ) @@ -530,11 +567,11 @@ xdescribe('Sidebar', () => { it('policy rooms are displayed only when they have unread messages', () => { // Given a default policy room and user created policy room - const policyRoomReport = { + const policyRoomReport: Report = { ...LHNTestUtils.getFakeReport([1, 2]), chatType: CONST.REPORT.CHAT_TYPE.POLICY_ANNOUNCE, }; - const userCreatedPolicyRoomReport = { + const userCreatedPolicyRoomReport: Report = { ...LHNTestUtils.getFakeReport([1, 2]), chatType: CONST.REPORT.CHAT_TYPE.POLICY_ROOM, }; @@ -542,6 +579,11 @@ xdescribe('Sidebar', () => { const betas = [CONST.BETAS.DEFAULT_ROOMS]; + const reportCollectionDataSet: ReportCollectionDataSet = { + [`${ONYXKEYS.COLLECTION.REPORT}${policyRoomReport.reportID}`]: policyRoomReport, + [`${ONYXKEYS.COLLECTION.REPORT}${userCreatedPolicyRoomReport.reportID}`]: userCreatedPolicyRoomReport, + }; + return ( waitForBatchedUpdates() // When Onyx is updated to contain that data and the sidebar re-renders @@ -551,8 +593,7 @@ xdescribe('Sidebar', () => { [ONYXKEYS.BETAS]: betas, [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, [ONYXKEYS.IS_LOADING_APP]: false, - [`${ONYXKEYS.COLLECTION.REPORT}${policyRoomReport.reportID}`]: policyRoomReport, - [`${ONYXKEYS.COLLECTION.REPORT}${userCreatedPolicyRoomReport.reportID}`]: userCreatedPolicyRoomReport, + ...reportCollectionDataSet, }), ) @@ -622,7 +663,7 @@ xdescribe('Sidebar', () => { const AMOUNT_OF_VARIABLES = 6; // eslint-disable-next-line no-bitwise for (let i = 0; i < 1 << AMOUNT_OF_VARIABLES; i++) { - const boolArr = []; + const boolArr: boolean[] = []; for (let j = AMOUNT_OF_VARIABLES - 1; j >= 0; j--) { // eslint-disable-next-line no-bitwise boolArr.push(Boolean(i & (1 << j))); @@ -633,12 +674,18 @@ xdescribe('Sidebar', () => { // const boolArr = [false, false, false, true, false, false, false]; it(`the booleans ${JSON.stringify(boolArr)}`, () => { + const [isArchived, isUserCreatedPolicyRoom, hasAddWorkspaceError, isUnread, isPinned, hasDraft] = boolArr; const report2 = { - ...LHNTestUtils.getAdvancedFakeReport(...boolArr), + ...LHNTestUtils.getAdvancedFakeReport(isArchived, isUserCreatedPolicyRoom, hasAddWorkspaceError, isUnread, isPinned, hasDraft), policyID: policy.policyID, }; LHNTestUtils.getDefaultRenderedSidebarLinks(report1.reportID); + const reportCollectionDataSet: ReportCollectionDataSet = { + [`${ONYXKEYS.COLLECTION.REPORT}${report1.reportID}`]: report1, + [`${ONYXKEYS.COLLECTION.REPORT}${report2.reportID}`]: report2, + }; + return ( waitForBatchedUpdates() // When Onyx is updated to contain that data and the sidebar re-renders @@ -648,9 +695,8 @@ xdescribe('Sidebar', () => { [ONYXKEYS.BETAS]: betas, [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, [ONYXKEYS.IS_LOADING_APP]: false, - [`${ONYXKEYS.COLLECTION.REPORT}${report1.reportID}`]: report1, - [`${ONYXKEYS.COLLECTION.REPORT}${report2.reportID}`]: report2, [`${ONYXKEYS.COLLECTION.POLICY}${policy.policyID}`]: policy, + ...reportCollectionDataSet, }), ) @@ -663,7 +709,7 @@ xdescribe('Sidebar', () => { const navigatesToChatHintText = Localize.translateLocal('accessibilityHints.navigatesToChat'); expect(screen.queryAllByAccessibilityHint(navigatesToChatHintText)).toHaveLength(1); expect(displayNames).toHaveLength(1); - expect(lodashGet(displayNames, [0, 'props', 'children', 0])).toBe('Three, Four'); + expect(displayNames[0].props.children[0]).toBe('Three, Four'); } else { // Both reports visible const navigatesToChatHintText = Localize.translateLocal('accessibilityHints.navigatesToChat'); @@ -681,7 +727,7 @@ xdescribe('Sidebar', () => { LHNTestUtils.getDefaultRenderedSidebarLinks(); // Given an archived report with no comments - const report = { + const report: Report = { ...LHNTestUtils.getFakeReport(), lastVisibleActionCreated: '2022-11-22 03:48:27.267', statusNum: CONST.REPORT.STATUS_NUM.CLOSED, @@ -691,6 +737,10 @@ xdescribe('Sidebar', () => { // Given the user is in all betas const betas = [CONST.BETAS.DEFAULT_ROOMS]; + const reportCollectionDataSet: ReportCollectionDataSet = { + [`${ONYXKEYS.COLLECTION.REPORT}${report.reportID}`]: report, + }; + return ( waitForBatchedUpdates() // When Onyx is updated to contain that data and the sidebar re-renders @@ -700,7 +750,7 @@ xdescribe('Sidebar', () => { [ONYXKEYS.BETAS]: betas, [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, [ONYXKEYS.IS_LOADING_APP]: false, - [`${ONYXKEYS.COLLECTION.REPORT}${report.reportID}`]: report, + ...reportCollectionDataSet, }), ) @@ -733,7 +783,7 @@ xdescribe('Sidebar', () => { LHNTestUtils.getDefaultRenderedSidebarLinks(); // Given an archived report that has all comments read - const report = { + const report: Report = { ...LHNTestUtils.getFakeReport(), statusNum: CONST.REPORT.STATUS_NUM.CLOSED, stateNum: CONST.REPORT.STATE_NUM.APPROVED, @@ -742,6 +792,10 @@ xdescribe('Sidebar', () => { // Given the user is in all betas const betas = [CONST.BETAS.DEFAULT_ROOMS]; + const reportCollectionDataSet: ReportCollectionDataSet = { + [`${ONYXKEYS.COLLECTION.REPORT}${report.reportID}`]: report, + }; + return ( waitForBatchedUpdates() // When Onyx is updated to contain that data and the sidebar re-renders @@ -751,7 +805,7 @@ xdescribe('Sidebar', () => { [ONYXKEYS.BETAS]: betas, [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, [ONYXKEYS.IS_LOADING_APP]: false, - [`${ONYXKEYS.COLLECTION.REPORT}${report.reportID}`]: report, + ...reportCollectionDataSet, }), ) @@ -781,7 +835,7 @@ xdescribe('Sidebar', () => { LHNTestUtils.getDefaultRenderedSidebarLinks(); // Given an archived report that is not pinned - const report = { + const report: Report = { ...LHNTestUtils.getFakeReport(), isPinned: false, statusNum: CONST.REPORT.STATUS_NUM.CLOSED, @@ -791,6 +845,10 @@ xdescribe('Sidebar', () => { // Given the user is in all betas const betas = [CONST.BETAS.DEFAULT_ROOMS]; + const reportCollectionDataSet: ReportCollectionDataSet = { + [`${ONYXKEYS.COLLECTION.REPORT}${report.reportID}`]: report, + }; + return ( waitForBatchedUpdates() // When Onyx is updated to contain that data and the sidebar re-renders @@ -800,7 +858,7 @@ xdescribe('Sidebar', () => { [ONYXKEYS.BETAS]: betas, [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, [ONYXKEYS.IS_LOADING_APP]: false, - [`${ONYXKEYS.COLLECTION.REPORT}${report.reportID}`]: report, + ...reportCollectionDataSet, }), ) @@ -827,7 +885,7 @@ xdescribe('Sidebar', () => { LHNTestUtils.getDefaultRenderedSidebarLinks(); // Given an archived report that is not the active report - const report = { + const report: Report = { ...LHNTestUtils.getFakeReport(), statusNum: CONST.REPORT.STATUS_NUM.CLOSED, stateNum: CONST.REPORT.STATE_NUM.APPROVED, @@ -836,6 +894,10 @@ xdescribe('Sidebar', () => { // Given the user is in all betas const betas = [CONST.BETAS.DEFAULT_ROOMS]; + const reportCollectionDataSet: ReportCollectionDataSet = { + [`${ONYXKEYS.COLLECTION.REPORT}${report.reportID}`]: report, + }; + return ( waitForBatchedUpdates() // When Onyx is updated to contain that data and the sidebar re-renders @@ -845,7 +907,7 @@ xdescribe('Sidebar', () => { [ONYXKEYS.BETAS]: betas, [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, [ONYXKEYS.IS_LOADING_APP]: false, - [`${ONYXKEYS.COLLECTION.REPORT}${report.reportID}`]: report, + ...reportCollectionDataSet, }), ) diff --git a/tests/unit/SidebarOrderTest.ts b/tests/unit/SidebarOrderTest.ts index 9e70347764df..27da8348f43d 100644 --- a/tests/unit/SidebarOrderTest.ts +++ b/tests/unit/SidebarOrderTest.ts @@ -5,16 +5,15 @@ import DateUtils from '@libs/DateUtils'; import * as Localize from '@libs/Localize'; import CONST from '@src/CONST'; import type * as OnyxTypes from '@src/types/onyx'; +import type {ReportCollectionDataSet} from '@src/types/onyx/Report'; import * as LHNTestUtils from '../utils/LHNTestUtils'; import waitForBatchedUpdates from '../utils/waitForBatchedUpdates'; import wrapOnyxWithWaitForBatchedUpdates from '../utils/wrapOnyxWithWaitForBatchedUpdates'; -type ReportCollectionDataSet = Record<`${typeof ONYXKEYS.COLLECTION.REPORT}${string}`, OnyxTypes.Report>; - // Be sure to include the mocked Permissions and Expensicons libraries as well as the usePermissions hook or else the beta tests won't work -jest.mock('../../src/libs/Permissions'); -jest.mock('../../src/hooks/usePermissions.ts'); -jest.mock('../../src/components/Icon/Expensicons'); +jest.mock('@libs/Permissions'); +jest.mock('@hooks/usePermissions.ts'); +jest.mock('@components/Icon/Expensicons'); const ONYXKEYS = { PERSONAL_DETAILS_LIST: 'personalDetailsList', From aa4522beebc54a73a1a7bfcf34a7cad3d9ce87c0 Mon Sep 17 00:00:00 2001 From: VickyStash <vikstash@gmail.com> Date: Tue, 27 Feb 2024 10:29:33 +0100 Subject: [PATCH 4/5] [TS migration] Migrate 'SessionTest.js' test --- src/types/onyx/Report.ts | 3 +- .../{SessionTest.js => SessionTest.ts} | 44 +++++++++---------- 2 files changed, 23 insertions(+), 24 deletions(-) rename tests/actions/{SessionTest.js => SessionTest.ts} (74%) diff --git a/src/types/onyx/Report.ts b/src/types/onyx/Report.ts index ed6cdda3175e..6151064a26e2 100644 --- a/src/types/onyx/Report.ts +++ b/src/types/onyx/Report.ts @@ -1,7 +1,6 @@ import type {ValueOf} from 'type-fest'; import type CONST from '@src/CONST'; -import ONYXKEYS from '@src/ONYXKEYS'; -import type * as OnyxTypes from '@src/types/onyx/index'; +import type ONYXKEYS from '@src/ONYXKEYS'; import type * as OnyxCommon from './OnyxCommon'; import type PersonalDetails from './PersonalDetails'; import type {PolicyReportField} from './PolicyReportField'; diff --git a/tests/actions/SessionTest.js b/tests/actions/SessionTest.ts similarity index 74% rename from tests/actions/SessionTest.js rename to tests/actions/SessionTest.ts index f7d7f8ed5835..f4c4d186ff50 100644 --- a/tests/actions/SessionTest.js +++ b/tests/actions/SessionTest.ts @@ -1,27 +1,27 @@ import {beforeEach, jest, test} from '@jest/globals'; import Onyx from 'react-native-onyx'; -import CONST from '../../src/CONST'; -import * as App from '../../src/libs/actions/App'; -import OnyxUpdateManager from '../../src/libs/actions/OnyxUpdateManager'; -import HttpUtils from '../../src/libs/HttpUtils'; -import PushNotification from '../../src/libs/Notification/PushNotification'; +import type {OnyxEntry} from 'react-native-onyx'; +import * as App from '@libs/actions/App'; +import OnyxUpdateManager from '@libs/actions/OnyxUpdateManager'; +import HttpUtils from '@libs/HttpUtils'; +import PushNotification from '@libs/Notification/PushNotification'; // This lib needs to be imported, but it has nothing to export since all it contains is an Onyx connection -// eslint-disable-next-line no-unused-vars -import subscribePushNotification from '../../src/libs/Notification/PushNotification/subscribePushNotification'; -import ONYXKEYS from '../../src/ONYXKEYS'; +import '@libs/Notification/PushNotification/subscribePushNotification'; +import CONST from '@src/CONST'; +import ONYXKEYS from '@src/ONYXKEYS'; +import type {Credentials, Session} from '@src/types/onyx'; import * as TestHelper from '../utils/TestHelper'; import waitForBatchedUpdates from '../utils/waitForBatchedUpdates'; // We are mocking this method so that we can later test to see if it was called and what arguments it was called with. // We test HttpUtils.xhr() since this means that our API command turned into a network request and isn't only queued. -HttpUtils.xhr = jest.fn(); +HttpUtils.xhr = jest.fn<typeof HttpUtils.xhr>(); // Mocked to ensure push notifications are subscribed/unsubscribed as the session changes -jest.mock('../../src/libs/Notification/PushNotification'); +jest.mock('@libs/Notification/PushNotification'); Onyx.init({ keys: ONYXKEYS, - registerStorageEventListener: () => {}, }); OnyxUpdateManager(); @@ -35,13 +35,13 @@ describe('Session', () => { const TEST_INITIAL_AUTH_TOKEN = 'initialAuthToken'; const TEST_REFRESHED_AUTH_TOKEN = 'refreshedAuthToken'; - let credentials; + let credentials: OnyxEntry<Credentials> = null; Onyx.connect({ key: ONYXKEYS.CREDENTIALS, - callback: (val) => (credentials = val || {}), + callback: (val) => (credentials = val), }); - let session; + let session: OnyxEntry<Session> = null; Onyx.connect({ key: ONYXKEYS.SESSION, callback: (val) => (session = val), @@ -53,19 +53,19 @@ describe('Session', () => { .then(() => { // Then our re-authentication credentials should be generated and our session data // have the correct information + initial authToken. - expect(credentials.login).toBe(TEST_USER_LOGIN); - expect(credentials.autoGeneratedLogin).not.toBeUndefined(); - expect(credentials.autoGeneratedPassword).not.toBeUndefined(); - expect(session.authToken).toBe(TEST_INITIAL_AUTH_TOKEN); - expect(session.accountID).toBe(TEST_USER_ACCOUNT_ID); - expect(session.email).toBe(TEST_USER_LOGIN); + expect(credentials?.login).toBe(TEST_USER_LOGIN); + expect(credentials?.autoGeneratedLogin).not.toBeUndefined(); + expect(credentials?.autoGeneratedPassword).not.toBeUndefined(); + expect(session?.authToken).toBe(TEST_INITIAL_AUTH_TOKEN); + expect(session?.accountID).toBe(TEST_USER_ACCOUNT_ID); + expect(session?.email).toBe(TEST_USER_LOGIN); // At this point we have an authToken. To simulate it expiring we'll just make another // request and mock the response so it returns 407. Once this happens we should attempt // to Re-Authenticate with the stored credentials. Our next call will be to Authenticate // so we will mock that response with a new authToken and then verify that Onyx has our // data. - HttpUtils.xhr + (HttpUtils.xhr as jest.MockedFunction<typeof HttpUtils.xhr>) // This will make the call to OpenApp below return with an expired session code .mockImplementationOnce(() => @@ -92,7 +92,7 @@ describe('Session', () => { .then(() => { // Then it should fail and reauthenticate the user adding the new authToken to the session // data in Onyx - expect(session.authToken).toBe(TEST_REFRESHED_AUTH_TOKEN); + expect(session?.authToken).toBe(TEST_REFRESHED_AUTH_TOKEN); }); }); From 34fc6664a7c9b5bf3b35e969aa4af934a9cad588 Mon Sep 17 00:00:00 2001 From: VickyStash <vikstash@gmail.com> Date: Tue, 27 Feb 2024 13:04:47 +0100 Subject: [PATCH 5/5] Implement CollectionDataSet type --- src/ONYXKEYS.ts | 2 +- src/types/onyx/Report.ts | 3 ++- src/types/utils/CollectionDataSet.ts | 6 ++++++ 3 files changed, 9 insertions(+), 2 deletions(-) create mode 100644 src/types/utils/CollectionDataSet.ts diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index f0b400687b12..cda3097dd431 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -584,4 +584,4 @@ type MissingOnyxKeysError = `Error: Types don't match, OnyxKey type is missing: type AssertOnyxKeys = AssertTypesEqual<AllOnyxKeys, OnyxKey, MissingOnyxKeysError>; export default ONYXKEYS; -export type {OnyxValues, OnyxKey, OnyxCollectionKey, OnyxValue, OnyxValueKey, OnyxFormKey, OnyxFormValuesMapping, OnyxFormDraftKey}; +export type {OnyxValues, OnyxKey, OnyxCollectionKey, OnyxValue, OnyxValueKey, OnyxFormKey, OnyxFormValuesMapping, OnyxFormDraftKey, OnyxCollectionValuesMapping}; diff --git a/src/types/onyx/Report.ts b/src/types/onyx/Report.ts index 6151064a26e2..282013cddb89 100644 --- a/src/types/onyx/Report.ts +++ b/src/types/onyx/Report.ts @@ -1,6 +1,7 @@ import type {ValueOf} from 'type-fest'; import type CONST from '@src/CONST'; import type ONYXKEYS from '@src/ONYXKEYS'; +import type CollectionDataSet from '@src/types/utils/CollectionDataSet'; import type * as OnyxCommon from './OnyxCommon'; import type PersonalDetails from './PersonalDetails'; import type {PolicyReportField} from './PolicyReportField'; @@ -179,7 +180,7 @@ type Report = { reportFields?: Record<string, PolicyReportField>; }; -type ReportCollectionDataSet = Record<`${typeof ONYXKEYS.COLLECTION.REPORT}${string}`, Report>; +type ReportCollectionDataSet = CollectionDataSet<typeof ONYXKEYS.COLLECTION.REPORT>; export default Report; diff --git a/src/types/utils/CollectionDataSet.ts b/src/types/utils/CollectionDataSet.ts new file mode 100644 index 000000000000..fc95a69dc9bf --- /dev/null +++ b/src/types/utils/CollectionDataSet.ts @@ -0,0 +1,6 @@ +import type {OnyxCollectionKey, OnyxCollectionValuesMapping} from '@src/ONYXKEYS'; + +/** Helps with typing a collection item update inside Onyx.multiSet call */ +type CollectionDataSet<TCollectionKey extends OnyxCollectionKey> = Record<`${TCollectionKey}${string}`, OnyxCollectionValuesMapping[TCollectionKey]>; + +export default CollectionDataSet;