From 9297f160b82d5178a6598a0a17a8ef120874442f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Mon, 28 Aug 2023 15:48:55 +0200 Subject: [PATCH 01/23] fix tests --- jest.config.js | 2 +- jest/setupAfterEnv.js | 1 + tests/unit/APITest.js | 1 - tests/unit/NetworkTest.js | 1 - tests/utils/waitForPromisesToResolve.js | 2 +- 5 files changed, 3 insertions(+), 4 deletions(-) create mode 100644 jest/setupAfterEnv.js diff --git a/jest.config.js b/jest.config.js index 1f540a679b9a..6cf44b6b3695 100644 --- a/jest.config.js +++ b/jest.config.js @@ -23,6 +23,6 @@ module.exports = { }, testEnvironment: 'jsdom', setupFiles: ['/jest/setup.js', './node_modules/@react-native-google-signin/google-signin/jest/build/setup.js'], - setupFilesAfterEnv: ['@testing-library/jest-native/extend-expect'], + setupFilesAfterEnv: ['@testing-library/jest-native/extend-expect', '/jest/setupAfterEnv.js'], cacheDirectory: '/.jest-cache', }; diff --git a/jest/setupAfterEnv.js b/jest/setupAfterEnv.js new file mode 100644 index 000000000000..a24f9ad4750e --- /dev/null +++ b/jest/setupAfterEnv.js @@ -0,0 +1 @@ +jest.useRealTimers(); \ No newline at end of file diff --git a/tests/unit/APITest.js b/tests/unit/APITest.js index eeeddc70fc47..e6f45e7826ee 100644 --- a/tests/unit/APITest.js +++ b/tests/unit/APITest.js @@ -14,7 +14,6 @@ import * as SequentialQueue from '../../src/libs/Network/SequentialQueue'; import * as Request from '../../src/libs/Request'; jest.mock('../../src/libs/Log'); -jest.useFakeTimers(); Onyx.init({ keys: ONYXKEYS, diff --git a/tests/unit/NetworkTest.js b/tests/unit/NetworkTest.js index c8dcda0e2af5..5dc7b000b352 100644 --- a/tests/unit/NetworkTest.js +++ b/tests/unit/NetworkTest.js @@ -16,7 +16,6 @@ import * as App from '../../src/libs/actions/App'; import NetworkConnection from '../../src/libs/NetworkConnection'; jest.mock('../../src/libs/Log'); -jest.useFakeTimers(); Onyx.init({ keys: ONYXKEYS, diff --git a/tests/utils/waitForPromisesToResolve.js b/tests/utils/waitForPromisesToResolve.js index 97146e6a8d86..dec3616ed168 100644 --- a/tests/utils/waitForPromisesToResolve.js +++ b/tests/utils/waitForPromisesToResolve.js @@ -5,4 +5,4 @@ * * @returns {Promise} */ -export default () => new Promise(setImmediate); +export default () => new Promise((resolve) => setTimeout(resolve, 0)); From 9a3cfe5c119b771887ec514f1a5feb1ceadabc4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Tue, 29 Aug 2023 13:00:00 +0200 Subject: [PATCH 02/23] fix waitForPromise method to exhaust microtask queue --- tests/utils/waitForPromisesToResolve.js | 29 ++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/tests/utils/waitForPromisesToResolve.js b/tests/utils/waitForPromisesToResolve.js index dec3616ed168..cb47ea92ff04 100644 --- a/tests/utils/waitForPromisesToResolve.js +++ b/tests/utils/waitForPromisesToResolve.js @@ -3,6 +3,33 @@ * that expect some Onyx value to be available. This way we do not have to explicitly wait for an action to finish * (e.g. by making it a promise and waiting for it to resolve). * + * **Note:** It is recommended to wait for the Onyx operations, so in your tests its preferred to do: + * ✅ Onyx.merge(...).then(...) + * than to do + * ❌ Onyx.merge(...) + * waitForPromisesToResolve().then(...) + * * @returns {Promise} */ -export default () => new Promise((resolve) => setTimeout(resolve, 0)); +export default () => new Promise((outerResolve) => { + // We first need to exhaust the microtask queue, before we schedule the next task in the macrotask queue (setTimeout). + // This is because we need to wait for all async onyx operations to finish, as they might schedule other macrotasks, + // and we want those task to run before our scheduled task. + // E.g. this makes the following code work for tests: + // + // Onyx.merge(...) + // return waitForPromiseToResolve().then(...); + // + // Note: Ideally, you'd just await the Onyx.merge promise. + + new Promise((innerResolve) => { + setImmediate(() => { + innerResolve("Flush all micro tasks that pushed by using '.then' method"); + }); + }).then(() => { + setTimeout(outerResolve, 0); + }); +}); + + +// export default () => new Promise((resolve) => setTimeout(resolve, 0)); From c4c241eb3b969fe693f3d6d495a78bfa7682202c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Tue, 29 Aug 2023 13:00:24 +0200 Subject: [PATCH 03/23] fix Emoji tests --- tests/unit/EmojiTest.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/unit/EmojiTest.js b/tests/unit/EmojiTest.js index 0e9b7a7c8c0f..66f79ffb7fe4 100644 --- a/tests/unit/EmojiTest.js +++ b/tests/unit/EmojiTest.js @@ -170,8 +170,7 @@ describe('EmojiTest', () => { beforeEach(() => { spy.mockClear(); - Onyx.clear(); - return waitForPromisesToResolve(); + return Onyx.clear(); }); it('should put a less frequent and recent used emoji behind', () => { From b76b005ea33ffd855801acebc3934d218a4a61fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Tue, 29 Aug 2023 13:00:33 +0200 Subject: [PATCH 04/23] fix SidebarFilterTest --- tests/unit/SidebarFilterTest.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/unit/SidebarFilterTest.js b/tests/unit/SidebarFilterTest.js index 85d409969133..37fae51e48c9 100644 --- a/tests/unit/SidebarFilterTest.js +++ b/tests/unit/SidebarFilterTest.js @@ -38,13 +38,13 @@ describe('Sidebar', () => { // Wrap Onyx each onyx action with waitForPromiseToResolve wrapOnyxWithWaitForPromisesToResolve(Onyx); // Initialize the network key for OfflineWithFeedback - Onyx.merge(ONYXKEYS.NETWORK, {isOffline: false}); + return Onyx.merge(ONYXKEYS.NETWORK, {isOffline: false}); }); // Cleanup (ie. unmount) all rendered components and clear out Onyx after each test so that each test starts with a clean slate afterEach(() => { cleanup(); - Onyx.clear(); + return Onyx.clear(); }); describe('in default (most recent) mode', () => { From 66c995f4f11ff98b9f2c49350ae32ea1e48a4c97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Tue, 29 Aug 2023 13:13:41 +0200 Subject: [PATCH 05/23] wip --- src/libs/actions/PersistedRequests.js | 2 +- tests/unit/NetworkTest.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libs/actions/PersistedRequests.js b/src/libs/actions/PersistedRequests.js index be30e6b3c8ed..ff6d083c58bb 100644 --- a/src/libs/actions/PersistedRequests.js +++ b/src/libs/actions/PersistedRequests.js @@ -10,7 +10,7 @@ Onyx.connect({ }); function clear() { - Onyx.set(ONYXKEYS.PERSISTED_REQUESTS, []); + return Onyx.set(ONYXKEYS.PERSISTED_REQUESTS, []); } /** diff --git a/tests/unit/NetworkTest.js b/tests/unit/NetworkTest.js index 5dc7b000b352..129999c902cd 100644 --- a/tests/unit/NetworkTest.js +++ b/tests/unit/NetworkTest.js @@ -28,12 +28,12 @@ beforeEach(() => { HttpUtils.xhr = originalXHR; MainQueue.clear(); HttpUtils.cancelPendingRequests(); - PersistedRequests.clear(); NetworkStore.checkRequiredData(); // Wait for any Log command to finish and Onyx to fully clear - jest.advanceTimersByTime(CONST.NETWORK.PROCESS_REQUEST_DELAY_MS); + // jest.advanceTimersByTime(CONST.NETWORK.PROCESS_REQUEST_DELAY_MS); return waitForPromisesToResolve() + .then(() => PersistedRequests.clear()) .then(() => Onyx.clear()) .then(waitForPromisesToResolve); }); From ac31c74b596acef3c9a88d91692aa718cf0be9a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szymon=20Kapa=C5=82a?= Date: Mon, 11 Sep 2023 19:17:26 +0200 Subject: [PATCH 06/23] stash work --- src/libs/Network/SequentialQueue.js | 7 +++- src/libs/actions/Report.js | 1 + src/libs/actions/User.js | 3 ++ tests/actions/IOUTest.js | 13 +++++++- tests/actions/ReportTest.js | 43 +++++++++++++++++++++++-- tests/actions/SessionTest.js | 2 +- tests/unit/APITest.js | 24 +++++++------- tests/utils/TestHelper.js | 6 ++-- tests/utils/waitForPromisesToResolve.js | 10 +++++- 9 files changed, 89 insertions(+), 20 deletions(-) diff --git a/src/libs/Network/SequentialQueue.js b/src/libs/Network/SequentialQueue.js index f8ea396663a5..f43056aea6de 100644 --- a/src/libs/Network/SequentialQueue.js +++ b/src/libs/Network/SequentialQueue.js @@ -42,6 +42,8 @@ function process() { } const requestToProcess = persistedRequests[0]; + console.log('trying to process', requestToProcess) + // Set the current request to a promise awaiting its processing so that getCurrentRequest can be used to take some action after the current request has processed. currentRequest = Request.processWithMiddleware(requestToProcess, true) .then(() => { @@ -50,6 +52,7 @@ function process() { return process(); }) .catch((error) => { + console.log('error processing ',requestToProcess, "error:", error) // On sign out we cancel any in flight requests from the user. Since that user is no longer signed in their requests should not be retried. // Duplicate records don't need to be retried as they just mean the record already exists on the server if (error.name === CONST.ERROR.REQUEST_CANCELLED || error.message === CONST.ERROR.DUPLICATE_RECORD) { @@ -94,7 +97,8 @@ function flush() { isSequentialQueueRunning = false; resolveIsReadyPromise(); currentRequest = null; - Onyx.update(QueuedOnyxUpdates.getQueuedUpdates()).then(QueuedOnyxUpdates.clear); + console.log(' about to onyx.updates') + Onyx.update(QueuedOnyxUpdates.getQueuedUpdates()).then(() => { console.log('about clear queue'); return QueuedOnyxUpdates.clear()}); }); }, }); @@ -135,6 +139,7 @@ function push(request) { * @returns {Promise} */ function getCurrentRequest() { + console.log('currentRequestwas null', currentRequest === null) if (currentRequest === null) { return Promise.resolve(); } diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index 8b898a6aaaea..b6ae21317075 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -215,6 +215,7 @@ function notifyNewAction(reportID, accountID, reportActionID) { return; } const isFromCurrentUser = accountID === currentUserAccountID; + console.log('calling callback') actionSubscriber.callback(isFromCurrentUser, reportActionID); } diff --git a/src/libs/actions/User.js b/src/libs/actions/User.js index b77c5b278bc9..5f8f7622244b 100644 --- a/src/libs/actions/User.js +++ b/src/libs/actions/User.js @@ -561,6 +561,8 @@ function subscribeToUserEvents() { updates = pushJSON.updates; OnyxUpdates.saveUpdateIDs(Number(pushJSON.lastUpdateID || 0), Number(pushJSON.previousUpdateID || 0)); } + + console.log('listener') _.each(updates, (multipleEvent) => { PusherUtils.triggerMultiEventHandler(multipleEvent.eventType, multipleEvent.data); }); @@ -569,6 +571,7 @@ function subscribeToUserEvents() { // Handles Onyx updates coming from Pusher through the mega multipleEvents. PusherUtils.subscribeToMultiEvent(Pusher.TYPE.MULTIPLE_EVENT_TYPE.ONYX_API_UPDATE, (pushJSON) => { SequentialQueue.getCurrentRequest().then(() => { + console.log('listener 2') // If we don't have the currentUserAccountID (user is logged out) we don't want to update Onyx with data from Pusher if (!currentUserAccountID) { return; diff --git a/tests/actions/IOUTest.js b/tests/actions/IOUTest.js index 6fbbe19cec8e..8090096135c9 100644 --- a/tests/actions/IOUTest.js +++ b/tests/actions/IOUTest.js @@ -28,7 +28,7 @@ describe('actions/IOU', () => { beforeEach(() => { global.fetch = TestHelper.getGlobalFetchMock(); - return Onyx.clear().then(waitForPromisesToResolve); + return Onyx.clear().then(waitForPromisesToResolve).then(() => {console.log('before each clean')}); }); describe('requestMoney', () => { @@ -307,6 +307,7 @@ describe('actions/IOU', () => { }), ) .then(fetch.resume) + .then(waitForPromisesToResolve) .then( () => new Promise((resolve) => { @@ -403,6 +404,7 @@ describe('actions/IOU', () => { .then( () => new Promise((resolve) => { + console.log('about to connnect') const connectionID = Onyx.connect({ key: ONYXKEYS.COLLECTION.REPORT, waitForCollectionCallback: true, @@ -428,6 +430,7 @@ describe('actions/IOU', () => { .then( () => new Promise((resolve) => { + console.log('about to connnect') const connectionID = Onyx.connect({ key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReportID}`, waitForCollectionCallback: true, @@ -489,15 +492,20 @@ describe('actions/IOU', () => { }), ) .then(fetch.resume) + .then(waitForPromisesToResolve) + .then(waitForPromisesToResolve) .then( () => new Promise((resolve) => { + console.log('about to connnect') const connectionID = Onyx.connect({ key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReportID}`, waitForCollectionCallback: true, callback: (reportActionsForIOUReport) => { Onyx.disconnect(connectionID); + console.log('disconnect') expect(_.size(reportActionsForIOUReport)).toBe(3); + console.log(reportActionsForIOUReport) _.each(reportActionsForIOUReport, (reportAction) => expect(reportAction.pendingAction).toBeFalsy()); resolve(); }, @@ -507,6 +515,7 @@ describe('actions/IOU', () => { .then( () => new Promise((resolve) => { + console.log('about to connnect') const connectionID = Onyx.connect({ key: ONYXKEYS.COLLECTION.TRANSACTION, waitForCollectionCallback: true, @@ -1125,6 +1134,8 @@ describe('actions/IOU', () => { }), ) .then(fetch.resume) + .then(waitForPromisesToResolve) + .then(waitForPromisesToResolve) .then( () => new Promise((resolve) => { diff --git a/tests/actions/ReportTest.js b/tests/actions/ReportTest.js index c06d3bc83766..1b71994d1b65 100644 --- a/tests/actions/ReportTest.js +++ b/tests/actions/ReportTest.js @@ -14,6 +14,7 @@ import * as PersistedRequests from '../../src/libs/actions/PersistedRequests'; import * as User from '../../src/libs/actions/User'; import * as ReportUtils from '../../src/libs/ReportUtils'; import DateUtils from '../../src/libs/DateUtils'; +import * as SequentialQueue from '../../src/libs/Network/SequentialQueue'; jest.mock('../../src/libs/actions/Report', () => { const originalModule = jest.requireActual('../../src/libs/actions/Report'); @@ -33,7 +34,11 @@ describe('actions/Report', () => { }); }); - beforeEach(() => Onyx.clear().then(waitForPromisesToResolve)); + beforeEach(() => { + const promise = Onyx.clear().then(jest.useRealTimers) + waitForPromisesToResolve() + return promise + }); afterEach(PusherHelper.teardown); @@ -178,6 +183,8 @@ describe('actions/Report', () => { }); it('should be updated correctly when new comments are added, deleted or marked as unread', () => { + jest.useFakeTimers() + global.fetch = TestHelper.getGlobalFetchMock(); const REPORT_ID = '1'; let report; let reportActionCreatedDate; @@ -196,13 +203,16 @@ describe('actions/Report', () => { const USER_1_LOGIN = 'user@test.com'; const USER_1_ACCOUNT_ID = 1; const USER_2_ACCOUNT_ID = 2; - return Onyx.set(`${ONYXKEYS.COLLECTION.REPORT}${REPORT_ID}`, {reportName: 'Test', reportID: REPORT_ID}) + const setPromise = Onyx.set(`${ONYXKEYS.COLLECTION.REPORT}${REPORT_ID}`, {reportName: 'Test', reportID: REPORT_ID}) .then(() => TestHelper.signInWithTestUser(USER_1_ACCOUNT_ID, USER_1_LOGIN)) + .then(waitForPromisesToResolve) + .then(waitForPromisesToResolve) .then(() => { // Given a test user that is subscribed to Pusher events User.subscribeToUserEvents(); return waitForPromisesToResolve(); }) + .then(waitForPromisesToResolve) .then(() => TestHelper.setPersonalDetails(USER_1_LOGIN, USER_1_ACCOUNT_ID)) .then(() => { // When a Pusher event is handled for a new report comment that includes a mention of the current user @@ -241,6 +251,8 @@ describe('actions/Report', () => { ]); return waitForPromisesToResolve(); }) + .then(waitForPromisesToResolve) + .then(waitForPromisesToResolve) .then(() => { // Then the report will be unread expect(ReportUtils.isUnread(report)).toBe(true); @@ -253,6 +265,7 @@ describe('actions/Report', () => { currentTime = DateUtils.getDBTime(); Report.openReport(REPORT_ID); Report.readNewestAction(REPORT_ID); + waitForPromisesToResolve() return waitForPromisesToResolve(); }) .then(() => { @@ -305,6 +318,9 @@ describe('actions/Report', () => { Report.addComment(REPORT_ID, 'Current User Comment 3'); return waitForPromisesToResolve(); }) + .then(waitForPromisesToResolve) + .then(waitForPromisesToResolve) + .then(waitForPromisesToResolve) .then(() => { // The report will be read and the lastReadTime updated expect(ReportUtils.isUnread(report)).toBe(false); @@ -367,13 +383,29 @@ describe('actions/Report', () => { optimisticReportActions, ]); + console.log('emmited update through pusher') + return waitForPromisesToResolve(); }) + .then(() => {console.log("i;m here")}) + //.then(SequentialQueue.getCurrentRequest) + .then(() => {console.log("i;m here 2")}) + .then(waitForPromisesToResolve) + .then(waitForPromisesToResolve) + .then(() => { + expect(report.lastReadTime).toBe(reportActionCreatedDate); + }) + .then(waitForPromisesToResolve) + .then(waitForPromisesToResolve) .then(() => { // If the user deletes a comment that is before the last read Report.deleteReportComment(REPORT_ID, {...reportActions[200]}); return waitForPromisesToResolve(); }) + .then(waitForPromisesToResolve) + .then(waitForPromisesToResolve) + .then(waitForPromisesToResolve) + .then(waitForPromisesToResolve) .then(() => { // Then no change will occur expect(report.lastReadTime).toBe(reportActionCreatedDate); @@ -396,6 +428,8 @@ describe('actions/Report', () => { expect(ReportUtils.isUnread(report)).toBe(false); expect(report.lastMessageText).toBe('Current User Comment 2'); }); + waitForPromisesToResolve() // flushing onyx.set as it wull be batched + return setPromise }); it('Should properly update comment with links', () => { @@ -404,6 +438,8 @@ describe('actions/Report', () => { * already in the comment and the user deleted it on purpose. */ + global.fetch = TestHelper.getGlobalFetchMock(); + // User edits comment to add link // We should generate link let originalCommentHTML = 'Original Comment'; @@ -486,6 +522,7 @@ describe('actions/Report', () => { // Setup user and pusher listeners return TestHelper.signInWithTestUser(TEST_USER_ACCOUNT_ID) + .then(waitForPromisesToResolve) .then(() => { User.subscribeToUserEvents(); return waitForPromisesToResolve(); @@ -502,7 +539,7 @@ describe('actions/Report', () => { shouldNotify: true, }, ]); - return waitForPromisesToResolve(); + return SequentialQueue.getCurrentRequest().then(waitForPromisesToResolve); }) .then(() => { // Ensure we show a notification for this new report action diff --git a/tests/actions/SessionTest.js b/tests/actions/SessionTest.js index d8bfa144e358..2271ca199ad2 100644 --- a/tests/actions/SessionTest.js +++ b/tests/actions/SessionTest.js @@ -94,7 +94,7 @@ describe('Session', () => { }); }); - test('Push notifications are subscribed after signing in', () => TestHelper.signInWithTestUser().then(() => expect(PushNotification.register).toBeCalled())); + test('Push notifications are subscribed after signing in', () => TestHelper.signInWithTestUser().then(waitForPromisesToResolve).then(() => expect(PushNotification.register).toBeCalled())); test('Push notifications are unsubscribed after signing out', () => TestHelper.signInWithTestUser() diff --git a/tests/unit/APITest.js b/tests/unit/APITest.js index e6f45e7826ee..4f16ff3b0867 100644 --- a/tests/unit/APITest.js +++ b/tests/unit/APITest.js @@ -30,7 +30,6 @@ beforeEach(() => { NetworkStore.checkRequiredData(); // Wait for any Log command to finish and Onyx to fully clear - jest.advanceTimersByTime(CONST.NETWORK.PROCESS_REQUEST_DELAY_MS); return waitForPromisesToResolve() .then(() => Onyx.clear()) .then(waitForPromisesToResolve); @@ -167,8 +166,7 @@ describe('APITests', () => { expect(PersistedRequests.getAll()).toEqual([expect.objectContaining({command: 'mock command', data: expect.objectContaining({param2: 'value2'})})]); // We need to advance past the request throttle back off timer because the request won't be retried until then - jest.advanceTimersByTime(CONST.NETWORK.MAX_RANDOM_RETRY_WAIT_TIME_MS); - return waitForPromisesToResolve(); + return new Promise((resolve) => setTimeout(resolve, 1000)).then(waitForPromisesToResolve); }) .then(() => { // Finally, after it succeeds the queue should be empty @@ -203,7 +201,7 @@ describe('APITests', () => { .then(() => { // When API Write commands are made API.write('mock command', {param1: 'value1'}); - return waitForPromisesToResolve(); + return waitForPromisesToResolve().then(waitForPromisesToResolve); }) // When we resume connectivity @@ -218,8 +216,7 @@ describe('APITests', () => { expect(PersistedRequests.getAll()).toEqual([expect.objectContaining({command: 'mock command', data: expect.objectContaining({param1: 'value1'})})]); // We let the SequentialQueue process again after its wait time - jest.runOnlyPendingTimers(); - return waitForPromisesToResolve(); + return new Promise((resolve) => setTimeout(resolve, CONST.NETWORK.MAX_RANDOM_RETRY_WAIT_TIME_MS)).then(waitForPromisesToResolve); }) .then(() => { // Then we have retried the failing request @@ -230,8 +227,7 @@ describe('APITests', () => { expect(PersistedRequests.getAll()).toEqual([expect.objectContaining({command: 'mock command', data: expect.objectContaining({param1: 'value1'})})]); // We let the SequentialQueue process again after its wait time - jest.runOnlyPendingTimers(); - return waitForPromisesToResolve(); + return new Promise((resolve) => setTimeout(resolve, 2 * CONST.NETWORK.MAX_RANDOM_RETRY_WAIT_TIME_MS)).then(waitForPromisesToResolve); }) .then(() => { // Then the request is retried again @@ -384,7 +380,7 @@ describe('APITests', () => { }); }); - test('Sequential queue will succeed if triggered while reauthentication via main queue is in progress', () => { + test.only('Sequential queue will succeed if triggered while reauthentication via main queue is in progress', () => { // Given offline state where all requests will eventualy succeed without issue and assumed to be valid credentials const xhr = jest .spyOn(HttpUtils, 'xhr') @@ -400,12 +396,14 @@ describe('APITests', () => { .then(() => { // When we queue both non-persistable and persistable commands that will trigger reauthentication and go offline at the same time API.makeRequestWithSideEffects('AuthenticatePusher', {content: 'value1'}); + Onyx.set(ONYXKEYS.NETWORK, {isOffline: true}); expect(NetworkStore.isOffline()).toBe(false); expect(NetworkStore.isAuthenticating()).toBe(false); - return waitForPromisesToResolve(); + return waitForPromisesToResolve().then(waitForPromisesToResolve).then(waitForPromisesToResolve); }) .then(() => { + console.log(xhr.mock.calls) API.write('MockCommand'); expect(PersistedRequests.getAll().length).toBe(1); expect(NetworkStore.isOffline()).toBe(true); @@ -415,8 +413,12 @@ describe('APITests', () => { // We should only have a single call at this point as the main queue is stopped since we've gone offline expect(xhr.mock.calls.length).toBe(1); + waitForPromisesToResolve() + // Come back from offline to trigger the sequential queue flush - return Onyx.set(ONYXKEYS.NETWORK, {isOffline: false}); + const promise = Onyx.set(ONYXKEYS.NETWORK, {isOffline: false}); + waitForPromisesToResolve() + return promise.then(waitForPromisesToResolve); }) .then(() => { // When we wait for the sequential queue to finish diff --git a/tests/utils/TestHelper.js b/tests/utils/TestHelper.js index a8424d14ed33..2a92001d3f44 100644 --- a/tests/utils/TestHelper.js +++ b/tests/utils/TestHelper.js @@ -153,8 +153,9 @@ function getGlobalFetchMock() { let isPaused = false; let shouldFail = false; - const getResponse = () => - shouldFail + const getResponse = () => { + console.log('resolving getResponse') + return shouldFail ? { ok: true, json: () => Promise.resolve({jsonCode: 400}), @@ -163,6 +164,7 @@ function getGlobalFetchMock() { ok: true, json: () => Promise.resolve({jsonCode: 200}), }; + } const mockFetch = jest.fn().mockImplementation(() => { if (!isPaused) { diff --git a/tests/utils/waitForPromisesToResolve.js b/tests/utils/waitForPromisesToResolve.js index cb47ea92ff04..fe5b5f65166c 100644 --- a/tests/utils/waitForPromisesToResolve.js +++ b/tests/utils/waitForPromisesToResolve.js @@ -27,9 +27,17 @@ export default () => new Promise((outerResolve) => { innerResolve("Flush all micro tasks that pushed by using '.then' method"); }); }).then(() => { - setTimeout(outerResolve, 0); + if (usingFakeTimers()) { + jest.runOnlyPendingTimers() + outerResolve() + return + } + setTimeout(() => { console.log('resolving waitForPromistesToResolve'); outerResolve()}, 0); }); }); +const usingFakeTimers = () => { + return !!(global.setTimeout.mock||global.setTimeout.clock) +} // export default () => new Promise((resolve) => setTimeout(resolve, 0)); From 5200d56fce949363e53f87baf5c5c40f13406312 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szymon=20Kapa=C5=82a?= Date: Mon, 11 Sep 2023 19:43:01 +0200 Subject: [PATCH 07/23] stash work --- src/libs/Network/SequentialQueue.js | 2 ++ tests/actions/SessionTest.js | 1 + tests/unit/APITest.js | 10 +++++----- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/libs/Network/SequentialQueue.js b/src/libs/Network/SequentialQueue.js index f43056aea6de..bcffd33b32d6 100644 --- a/src/libs/Network/SequentialQueue.js +++ b/src/libs/Network/SequentialQueue.js @@ -83,6 +83,8 @@ function flush() { isSequentialQueueRunning = true; + console.log('flush()') + // Reset the isReadyPromise so that the queue will be flushed as soon as the request is finished isReadyPromise = new Promise((resolve) => { resolveIsReadyPromise = resolve; diff --git a/tests/actions/SessionTest.js b/tests/actions/SessionTest.js index 2271ca199ad2..99e9613be8e4 100644 --- a/tests/actions/SessionTest.js +++ b/tests/actions/SessionTest.js @@ -48,6 +48,7 @@ describe('Session', () => { // When we sign in with the test user return TestHelper.signInWithTestUser(TEST_USER_ACCOUNT_ID, TEST_USER_LOGIN, 'Password1', TEST_INITIAL_AUTH_TOKEN) + .then(waitForPromisesToResolve) .then(() => { // Then our re-authentication credentials should be generated and our session data // have the correct information + initial authToken. diff --git a/tests/unit/APITest.js b/tests/unit/APITest.js index 4f16ff3b0867..8e56ac5d1c9e 100644 --- a/tests/unit/APITest.js +++ b/tests/unit/APITest.js @@ -380,7 +380,7 @@ describe('APITests', () => { }); }); - test.only('Sequential queue will succeed if triggered while reauthentication via main queue is in progress', () => { + test('Sequential queue will succeed if triggered while reauthentication via main queue is in progress', () => { // Given offline state where all requests will eventualy succeed without issue and assumed to be valid credentials const xhr = jest .spyOn(HttpUtils, 'xhr') @@ -400,7 +400,7 @@ describe('APITests', () => { Onyx.set(ONYXKEYS.NETWORK, {isOffline: true}); expect(NetworkStore.isOffline()).toBe(false); expect(NetworkStore.isAuthenticating()).toBe(false); - return waitForPromisesToResolve().then(waitForPromisesToResolve).then(waitForPromisesToResolve); + return waitForPromisesToResolve(); }) .then(() => { console.log(xhr.mock.calls) @@ -416,12 +416,12 @@ describe('APITests', () => { waitForPromisesToResolve() // Come back from offline to trigger the sequential queue flush - const promise = Onyx.set(ONYXKEYS.NETWORK, {isOffline: false}); - waitForPromisesToResolve() - return promise.then(waitForPromisesToResolve); + console.log('about to set isOffline false') + Onyx.set(ONYXKEYS.NETWORK, {isOffline: false}); }) .then(() => { // When we wait for the sequential queue to finish + console.log('checking isRunning') expect(SequentialQueue.isRunning()).toBe(true); return waitForPromisesToResolve(); }) From e717c1ed92fac83f2472da088fcddb0f19f1b625 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szymon=20Kapa=C5=82a?= Date: Tue, 12 Sep 2023 08:48:53 +0200 Subject: [PATCH 08/23] remove console.logs --- src/libs/Network/SequentialQueue.js | 9 +-------- src/libs/actions/Report.js | 1 - src/libs/actions/User.js | 3 --- tests/actions/IOUTest.js | 8 +------- tests/actions/ReportTest.js | 5 ----- tests/unit/APITest.js | 3 --- tests/unit/NetworkTest.js | 1 - tests/utils/TestHelper.js | 7 +++---- tests/utils/waitForPromisesToResolve.js | 4 +--- 9 files changed, 6 insertions(+), 35 deletions(-) diff --git a/src/libs/Network/SequentialQueue.js b/src/libs/Network/SequentialQueue.js index bcffd33b32d6..f8ea396663a5 100644 --- a/src/libs/Network/SequentialQueue.js +++ b/src/libs/Network/SequentialQueue.js @@ -42,8 +42,6 @@ function process() { } const requestToProcess = persistedRequests[0]; - console.log('trying to process', requestToProcess) - // Set the current request to a promise awaiting its processing so that getCurrentRequest can be used to take some action after the current request has processed. currentRequest = Request.processWithMiddleware(requestToProcess, true) .then(() => { @@ -52,7 +50,6 @@ function process() { return process(); }) .catch((error) => { - console.log('error processing ',requestToProcess, "error:", error) // On sign out we cancel any in flight requests from the user. Since that user is no longer signed in their requests should not be retried. // Duplicate records don't need to be retried as they just mean the record already exists on the server if (error.name === CONST.ERROR.REQUEST_CANCELLED || error.message === CONST.ERROR.DUPLICATE_RECORD) { @@ -83,8 +80,6 @@ function flush() { isSequentialQueueRunning = true; - console.log('flush()') - // Reset the isReadyPromise so that the queue will be flushed as soon as the request is finished isReadyPromise = new Promise((resolve) => { resolveIsReadyPromise = resolve; @@ -99,8 +94,7 @@ function flush() { isSequentialQueueRunning = false; resolveIsReadyPromise(); currentRequest = null; - console.log(' about to onyx.updates') - Onyx.update(QueuedOnyxUpdates.getQueuedUpdates()).then(() => { console.log('about clear queue'); return QueuedOnyxUpdates.clear()}); + Onyx.update(QueuedOnyxUpdates.getQueuedUpdates()).then(QueuedOnyxUpdates.clear); }); }, }); @@ -141,7 +135,6 @@ function push(request) { * @returns {Promise} */ function getCurrentRequest() { - console.log('currentRequestwas null', currentRequest === null) if (currentRequest === null) { return Promise.resolve(); } diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index b6ae21317075..8b898a6aaaea 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -215,7 +215,6 @@ function notifyNewAction(reportID, accountID, reportActionID) { return; } const isFromCurrentUser = accountID === currentUserAccountID; - console.log('calling callback') actionSubscriber.callback(isFromCurrentUser, reportActionID); } diff --git a/src/libs/actions/User.js b/src/libs/actions/User.js index 5f8f7622244b..b77c5b278bc9 100644 --- a/src/libs/actions/User.js +++ b/src/libs/actions/User.js @@ -561,8 +561,6 @@ function subscribeToUserEvents() { updates = pushJSON.updates; OnyxUpdates.saveUpdateIDs(Number(pushJSON.lastUpdateID || 0), Number(pushJSON.previousUpdateID || 0)); } - - console.log('listener') _.each(updates, (multipleEvent) => { PusherUtils.triggerMultiEventHandler(multipleEvent.eventType, multipleEvent.data); }); @@ -571,7 +569,6 @@ function subscribeToUserEvents() { // Handles Onyx updates coming from Pusher through the mega multipleEvents. PusherUtils.subscribeToMultiEvent(Pusher.TYPE.MULTIPLE_EVENT_TYPE.ONYX_API_UPDATE, (pushJSON) => { SequentialQueue.getCurrentRequest().then(() => { - console.log('listener 2') // If we don't have the currentUserAccountID (user is logged out) we don't want to update Onyx with data from Pusher if (!currentUserAccountID) { return; diff --git a/tests/actions/IOUTest.js b/tests/actions/IOUTest.js index 8090096135c9..910140d56fe7 100644 --- a/tests/actions/IOUTest.js +++ b/tests/actions/IOUTest.js @@ -28,7 +28,7 @@ describe('actions/IOU', () => { beforeEach(() => { global.fetch = TestHelper.getGlobalFetchMock(); - return Onyx.clear().then(waitForPromisesToResolve).then(() => {console.log('before each clean')}); + return Onyx.clear().then(waitForPromisesToResolve); }); describe('requestMoney', () => { @@ -404,7 +404,6 @@ describe('actions/IOU', () => { .then( () => new Promise((resolve) => { - console.log('about to connnect') const connectionID = Onyx.connect({ key: ONYXKEYS.COLLECTION.REPORT, waitForCollectionCallback: true, @@ -430,7 +429,6 @@ describe('actions/IOU', () => { .then( () => new Promise((resolve) => { - console.log('about to connnect') const connectionID = Onyx.connect({ key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReportID}`, waitForCollectionCallback: true, @@ -497,15 +495,12 @@ describe('actions/IOU', () => { .then( () => new Promise((resolve) => { - console.log('about to connnect') const connectionID = Onyx.connect({ key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReportID}`, waitForCollectionCallback: true, callback: (reportActionsForIOUReport) => { Onyx.disconnect(connectionID); - console.log('disconnect') expect(_.size(reportActionsForIOUReport)).toBe(3); - console.log(reportActionsForIOUReport) _.each(reportActionsForIOUReport, (reportAction) => expect(reportAction.pendingAction).toBeFalsy()); resolve(); }, @@ -515,7 +510,6 @@ describe('actions/IOU', () => { .then( () => new Promise((resolve) => { - console.log('about to connnect') const connectionID = Onyx.connect({ key: ONYXKEYS.COLLECTION.TRANSACTION, waitForCollectionCallback: true, diff --git a/tests/actions/ReportTest.js b/tests/actions/ReportTest.js index 1b71994d1b65..68b0e3ffe37f 100644 --- a/tests/actions/ReportTest.js +++ b/tests/actions/ReportTest.js @@ -382,14 +382,9 @@ describe('actions/Report', () => { }, optimisticReportActions, ]); - - console.log('emmited update through pusher') return waitForPromisesToResolve(); }) - .then(() => {console.log("i;m here")}) - //.then(SequentialQueue.getCurrentRequest) - .then(() => {console.log("i;m here 2")}) .then(waitForPromisesToResolve) .then(waitForPromisesToResolve) .then(() => { diff --git a/tests/unit/APITest.js b/tests/unit/APITest.js index 8e56ac5d1c9e..7506d1fbcde4 100644 --- a/tests/unit/APITest.js +++ b/tests/unit/APITest.js @@ -403,7 +403,6 @@ describe('APITests', () => { return waitForPromisesToResolve(); }) .then(() => { - console.log(xhr.mock.calls) API.write('MockCommand'); expect(PersistedRequests.getAll().length).toBe(1); expect(NetworkStore.isOffline()).toBe(true); @@ -416,12 +415,10 @@ describe('APITests', () => { waitForPromisesToResolve() // Come back from offline to trigger the sequential queue flush - console.log('about to set isOffline false') Onyx.set(ONYXKEYS.NETWORK, {isOffline: false}); }) .then(() => { // When we wait for the sequential queue to finish - console.log('checking isRunning') expect(SequentialQueue.isRunning()).toBe(true); return waitForPromisesToResolve(); }) diff --git a/tests/unit/NetworkTest.js b/tests/unit/NetworkTest.js index 129999c902cd..6fa1237dbaa8 100644 --- a/tests/unit/NetworkTest.js +++ b/tests/unit/NetworkTest.js @@ -31,7 +31,6 @@ beforeEach(() => { NetworkStore.checkRequiredData(); // Wait for any Log command to finish and Onyx to fully clear - // jest.advanceTimersByTime(CONST.NETWORK.PROCESS_REQUEST_DELAY_MS); return waitForPromisesToResolve() .then(() => PersistedRequests.clear()) .then(() => Onyx.clear()) diff --git a/tests/utils/TestHelper.js b/tests/utils/TestHelper.js index 2a92001d3f44..03a3d2cb1480 100644 --- a/tests/utils/TestHelper.js +++ b/tests/utils/TestHelper.js @@ -153,9 +153,8 @@ function getGlobalFetchMock() { let isPaused = false; let shouldFail = false; - const getResponse = () => { - console.log('resolving getResponse') - return shouldFail + const getResponse = () => + shouldFail ? { ok: true, json: () => Promise.resolve({jsonCode: 400}), @@ -164,7 +163,7 @@ function getGlobalFetchMock() { ok: true, json: () => Promise.resolve({jsonCode: 200}), }; - } + const mockFetch = jest.fn().mockImplementation(() => { if (!isPaused) { diff --git a/tests/utils/waitForPromisesToResolve.js b/tests/utils/waitForPromisesToResolve.js index fe5b5f65166c..7b30f68f48ec 100644 --- a/tests/utils/waitForPromisesToResolve.js +++ b/tests/utils/waitForPromisesToResolve.js @@ -32,12 +32,10 @@ export default () => new Promise((outerResolve) => { outerResolve() return } - setTimeout(() => { console.log('resolving waitForPromistesToResolve'); outerResolve()}, 0); + setTimeout(outerResolve, 0); }); }); const usingFakeTimers = () => { return !!(global.setTimeout.mock||global.setTimeout.clock) } - -// export default () => new Promise((resolve) => setTimeout(resolve, 0)); From fba544d8ca48272a15d4e9e82592301dc2415b49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szymon=20Kapa=C5=82a?= Date: Tue, 12 Sep 2023 10:18:59 +0200 Subject: [PATCH 09/23] make FileUtilsTest more stable --- tests/unit/FileUtilsTest.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/unit/FileUtilsTest.js b/tests/unit/FileUtilsTest.js index 34dc0dfcf129..a2af56abdfac 100644 --- a/tests/unit/FileUtilsTest.js +++ b/tests/unit/FileUtilsTest.js @@ -2,6 +2,8 @@ import CONST from '../../src/CONST'; import DateUtils from '../../src/libs/DateUtils'; import * as FileUtils from '../../src/libs/fileDownload/FileUtils'; +jest.useFakeTimers() + describe('FileUtils', () => { describe('splitExtensionFromFileName', () => { it('should return correct file name and extension', () => { From 0185bbfae8d9849065b484f0911758380d48d28b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szymon=20Kapa=C5=82a?= Date: Tue, 12 Sep 2023 12:45:48 +0200 Subject: [PATCH 10/23] make it more stable --- src/libs/RequestThrottle.js | 9 ++++++++- tests/unit/APITest.js | 8 ++++---- tests/utils/waitForPromisesToResolve.js | 6 ++---- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/libs/RequestThrottle.js b/src/libs/RequestThrottle.js index 4725a3ad5c38..e499cd2b40f7 100644 --- a/src/libs/RequestThrottle.js +++ b/src/libs/RequestThrottle.js @@ -19,6 +19,13 @@ function getRequestWaitTime() { return requestWaitTime; } +/** + * @returns {Number} time to wait in ms + */ +function getRequestWaitTimeForTests() { + return requestWaitTime; +} + /** * @returns {Promise} */ @@ -26,4 +33,4 @@ function sleep() { return new Promise((resolve) => setTimeout(resolve, getRequestWaitTime())); } -export {clear, getRequestWaitTime, sleep}; +export {clear, getRequestWaitTime, sleep, getRequestWaitTimeForTests}; diff --git a/tests/unit/APITest.js b/tests/unit/APITest.js index 7506d1fbcde4..037ce6a582a0 100644 --- a/tests/unit/APITest.js +++ b/tests/unit/APITest.js @@ -12,6 +12,7 @@ import * as MainQueue from '../../src/libs/Network/MainQueue'; import * as API from '../../src/libs/API'; import * as SequentialQueue from '../../src/libs/Network/SequentialQueue'; import * as Request from '../../src/libs/Request'; +import * as RequestThrottle from '../../src/libs/RequestThrottle'; jest.mock('../../src/libs/Log'); @@ -216,7 +217,7 @@ describe('APITests', () => { expect(PersistedRequests.getAll()).toEqual([expect.objectContaining({command: 'mock command', data: expect.objectContaining({param1: 'value1'})})]); // We let the SequentialQueue process again after its wait time - return new Promise((resolve) => setTimeout(resolve, CONST.NETWORK.MAX_RANDOM_RETRY_WAIT_TIME_MS)).then(waitForPromisesToResolve); + return new Promise((resolve) => setTimeout(resolve, RequestThrottle.getRequestWaitTimeForTests())) }) .then(() => { // Then we have retried the failing request @@ -227,7 +228,7 @@ describe('APITests', () => { expect(PersistedRequests.getAll()).toEqual([expect.objectContaining({command: 'mock command', data: expect.objectContaining({param1: 'value1'})})]); // We let the SequentialQueue process again after its wait time - return new Promise((resolve) => setTimeout(resolve, 2 * CONST.NETWORK.MAX_RANDOM_RETRY_WAIT_TIME_MS)).then(waitForPromisesToResolve); + return new Promise((resolve) => setTimeout(resolve, RequestThrottle.getRequestWaitTimeForTests())).then(waitForPromisesToResolve); }) .then(() => { // Then the request is retried again @@ -533,8 +534,7 @@ describe('APITests', () => { expect(secondRequestCommandName).toBe('MockCommandThree'); // WHEN we advance the main queue timer and wait for promises - jest.advanceTimersByTime(CONST.NETWORK.PROCESS_REQUEST_DELAY_MS); - return waitForPromisesToResolve(); + return new Promise((resolve) => setTimeout(resolve, CONST.NETWORK.PROCESS_REQUEST_DELAY_MS)) }) .then(() => { // THEN we should see that our third (non-persistable) request has run last diff --git a/tests/utils/waitForPromisesToResolve.js b/tests/utils/waitForPromisesToResolve.js index 7b30f68f48ec..9241bef09d2e 100644 --- a/tests/utils/waitForPromisesToResolve.js +++ b/tests/utils/waitForPromisesToResolve.js @@ -1,3 +1,5 @@ +const usingFakeTimers = () => !!(global.setTimeout.mock||global.setTimeout.clock) + /** * Method which waits for all asynchronous JS to stop executing before proceeding. This helps test things like actions * that expect some Onyx value to be available. This way we do not have to explicitly wait for an action to finish @@ -35,7 +37,3 @@ export default () => new Promise((outerResolve) => { setTimeout(outerResolve, 0); }); }); - -const usingFakeTimers = () => { - return !!(global.setTimeout.mock||global.setTimeout.clock) -} From 5b80d4b159a7813e5569391e952ce80548ed9212 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szymon=20Kapa=C5=82a?= Date: Tue, 12 Sep 2023 12:47:00 +0200 Subject: [PATCH 11/23] better naming --- src/libs/RequestThrottle.js | 4 ++-- tests/unit/APITest.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libs/RequestThrottle.js b/src/libs/RequestThrottle.js index e499cd2b40f7..623362334d4a 100644 --- a/src/libs/RequestThrottle.js +++ b/src/libs/RequestThrottle.js @@ -22,7 +22,7 @@ function getRequestWaitTime() { /** * @returns {Number} time to wait in ms */ -function getRequestWaitTimeForTests() { +function getLastRequestWaitTime() { return requestWaitTime; } @@ -33,4 +33,4 @@ function sleep() { return new Promise((resolve) => setTimeout(resolve, getRequestWaitTime())); } -export {clear, getRequestWaitTime, sleep, getRequestWaitTimeForTests}; +export {clear, getRequestWaitTime, sleep, getLastRequestWaitTime}; diff --git a/tests/unit/APITest.js b/tests/unit/APITest.js index 037ce6a582a0..6331b8af5ca8 100644 --- a/tests/unit/APITest.js +++ b/tests/unit/APITest.js @@ -217,7 +217,7 @@ describe('APITests', () => { expect(PersistedRequests.getAll()).toEqual([expect.objectContaining({command: 'mock command', data: expect.objectContaining({param1: 'value1'})})]); // We let the SequentialQueue process again after its wait time - return new Promise((resolve) => setTimeout(resolve, RequestThrottle.getRequestWaitTimeForTests())) + return new Promise((resolve) => setTimeout(resolve, RequestThrottle.getLastRequestWaitTime())) }) .then(() => { // Then we have retried the failing request @@ -228,7 +228,7 @@ describe('APITests', () => { expect(PersistedRequests.getAll()).toEqual([expect.objectContaining({command: 'mock command', data: expect.objectContaining({param1: 'value1'})})]); // We let the SequentialQueue process again after its wait time - return new Promise((resolve) => setTimeout(resolve, RequestThrottle.getRequestWaitTimeForTests())).then(waitForPromisesToResolve); + return new Promise((resolve) => setTimeout(resolve, RequestThrottle.getLastRequestWaitTime())).then(waitForPromisesToResolve); }) .then(() => { // Then the request is retried again From 2f2f7b1832fe1bf281c5a49965860c538369a472 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szymon=20Kapa=C5=82a?= Date: Tue, 12 Sep 2023 12:53:31 +0200 Subject: [PATCH 12/23] remove unnecessary waitForPromise --- tests/actions/ReportTest.js | 9 --------- 1 file changed, 9 deletions(-) diff --git a/tests/actions/ReportTest.js b/tests/actions/ReportTest.js index 68b0e3ffe37f..6e8d24395e5b 100644 --- a/tests/actions/ReportTest.js +++ b/tests/actions/ReportTest.js @@ -318,9 +318,6 @@ describe('actions/Report', () => { Report.addComment(REPORT_ID, 'Current User Comment 3'); return waitForPromisesToResolve(); }) - .then(waitForPromisesToResolve) - .then(waitForPromisesToResolve) - .then(waitForPromisesToResolve) .then(() => { // The report will be read and the lastReadTime updated expect(ReportUtils.isUnread(report)).toBe(false); @@ -390,17 +387,11 @@ describe('actions/Report', () => { .then(() => { expect(report.lastReadTime).toBe(reportActionCreatedDate); }) - .then(waitForPromisesToResolve) - .then(waitForPromisesToResolve) .then(() => { // If the user deletes a comment that is before the last read Report.deleteReportComment(REPORT_ID, {...reportActions[200]}); return waitForPromisesToResolve(); }) - .then(waitForPromisesToResolve) - .then(waitForPromisesToResolve) - .then(waitForPromisesToResolve) - .then(waitForPromisesToResolve) .then(() => { // Then no change will occur expect(report.lastReadTime).toBe(reportActionCreatedDate); From 098375f046d2bd06776cc36f989712c7611336e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szymon=20Kapa=C5=82a?= Date: Tue, 12 Sep 2023 12:58:58 +0200 Subject: [PATCH 13/23] cleanup --- tests/actions/ReportTest.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/actions/ReportTest.js b/tests/actions/ReportTest.js index 6e8d24395e5b..72411537bfa6 100644 --- a/tests/actions/ReportTest.js +++ b/tests/actions/ReportTest.js @@ -383,10 +383,6 @@ describe('actions/Report', () => { return waitForPromisesToResolve(); }) .then(waitForPromisesToResolve) - .then(waitForPromisesToResolve) - .then(() => { - expect(report.lastReadTime).toBe(reportActionCreatedDate); - }) .then(() => { // If the user deletes a comment that is before the last read Report.deleteReportComment(REPORT_ID, {...reportActions[200]}); From d2aa3167cd48517ba78d7625ee89ac28181d36cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szymon=20Kapa=C5=82a?= Date: Tue, 12 Sep 2023 13:33:55 +0200 Subject: [PATCH 14/23] prettier --- jest/setupAfterEnv.js | 2 +- tests/actions/ReportTest.js | 18 +++++----- tests/actions/SessionTest.js | 5 ++- tests/unit/APITest.js | 8 ++--- tests/unit/FileUtilsTest.js | 2 +- tests/utils/TestHelper.js | 3 +- tests/utils/waitForPromisesToResolve.js | 45 +++++++++++++------------ 7 files changed, 43 insertions(+), 40 deletions(-) diff --git a/jest/setupAfterEnv.js b/jest/setupAfterEnv.js index a24f9ad4750e..6f7836b64dbb 100644 --- a/jest/setupAfterEnv.js +++ b/jest/setupAfterEnv.js @@ -1 +1 @@ -jest.useRealTimers(); \ No newline at end of file +jest.useRealTimers(); diff --git a/tests/actions/ReportTest.js b/tests/actions/ReportTest.js index 417742ebc5a2..bd6118646a7a 100644 --- a/tests/actions/ReportTest.js +++ b/tests/actions/ReportTest.js @@ -37,9 +37,9 @@ describe('actions/Report', () => { }); beforeEach(() => { - const promise = Onyx.clear().then(jest.useRealTimers) - waitForPromisesToResolve() - return promise + const promise = Onyx.clear().then(jest.useRealTimers); + waitForPromisesToResolve(); + return promise; }); afterEach(PusherHelper.teardown); @@ -185,7 +185,7 @@ describe('actions/Report', () => { }); it('should be updated correctly when new comments are added, deleted or marked as unread', () => { - jest.useFakeTimers() + jest.useFakeTimers(); global.fetch = TestHelper.getGlobalFetchMock(); const REPORT_ID = '1'; let report; @@ -205,7 +205,7 @@ describe('actions/Report', () => { const USER_1_LOGIN = 'user@test.com'; const USER_1_ACCOUNT_ID = 1; const USER_2_ACCOUNT_ID = 2; - const setPromise = Onyx.set(`${ONYXKEYS.COLLECTION.REPORT}${REPORT_ID}`, {reportName: 'Test', reportID: REPORT_ID}) + const setPromise = Onyx.set(`${ONYXKEYS.COLLECTION.REPORT}${REPORT_ID}`, {reportName: 'Test', reportID: REPORT_ID}) .then(() => TestHelper.signInWithTestUser(USER_1_ACCOUNT_ID, USER_1_LOGIN)) .then(waitForPromisesToResolve) .then(waitForPromisesToResolve) @@ -267,7 +267,7 @@ describe('actions/Report', () => { currentTime = DateUtils.getDBTime(); Report.openReport(REPORT_ID); Report.readNewestAction(REPORT_ID); - waitForPromisesToResolve() + waitForPromisesToResolve(); return waitForPromisesToResolve(); }) .then(() => { @@ -381,7 +381,7 @@ describe('actions/Report', () => { }, optimisticReportActions, ]); - + return waitForPromisesToResolve(); }) .then(waitForPromisesToResolve) @@ -412,8 +412,8 @@ describe('actions/Report', () => { expect(ReportUtils.isUnread(report)).toBe(false); expect(report.lastMessageText).toBe('Current User Comment 2'); }); - waitForPromisesToResolve() // flushing onyx.set as it wull be batched - return setPromise + waitForPromisesToResolve(); // flushing onyx.set as it wull be batched + return setPromise; }); it('Should properly update comment with links', () => { diff --git a/tests/actions/SessionTest.js b/tests/actions/SessionTest.js index c96455510555..c558d877433b 100644 --- a/tests/actions/SessionTest.js +++ b/tests/actions/SessionTest.js @@ -97,7 +97,10 @@ describe('Session', () => { }); }); - test('Push notifications are subscribed after signing in', () => TestHelper.signInWithTestUser().then(waitForPromisesToResolve).then(() => expect(PushNotification.register).toBeCalled())); + test('Push notifications are subscribed after signing in', () => + TestHelper.signInWithTestUser() + .then(waitForPromisesToResolve) + .then(() => expect(PushNotification.register).toBeCalled())); test('Push notifications are unsubscribed after signing out', () => TestHelper.signInWithTestUser() diff --git a/tests/unit/APITest.js b/tests/unit/APITest.js index 6331b8af5ca8..29e5532eabfe 100644 --- a/tests/unit/APITest.js +++ b/tests/unit/APITest.js @@ -217,7 +217,7 @@ describe('APITests', () => { expect(PersistedRequests.getAll()).toEqual([expect.objectContaining({command: 'mock command', data: expect.objectContaining({param1: 'value1'})})]); // We let the SequentialQueue process again after its wait time - return new Promise((resolve) => setTimeout(resolve, RequestThrottle.getLastRequestWaitTime())) + return new Promise((resolve) => setTimeout(resolve, RequestThrottle.getLastRequestWaitTime())); }) .then(() => { // Then we have retried the failing request @@ -397,7 +397,7 @@ describe('APITests', () => { .then(() => { // When we queue both non-persistable and persistable commands that will trigger reauthentication and go offline at the same time API.makeRequestWithSideEffects('AuthenticatePusher', {content: 'value1'}); - + Onyx.set(ONYXKEYS.NETWORK, {isOffline: true}); expect(NetworkStore.isOffline()).toBe(false); expect(NetworkStore.isAuthenticating()).toBe(false); @@ -413,7 +413,7 @@ describe('APITests', () => { // We should only have a single call at this point as the main queue is stopped since we've gone offline expect(xhr.mock.calls.length).toBe(1); - waitForPromisesToResolve() + waitForPromisesToResolve(); // Come back from offline to trigger the sequential queue flush Onyx.set(ONYXKEYS.NETWORK, {isOffline: false}); @@ -534,7 +534,7 @@ describe('APITests', () => { expect(secondRequestCommandName).toBe('MockCommandThree'); // WHEN we advance the main queue timer and wait for promises - return new Promise((resolve) => setTimeout(resolve, CONST.NETWORK.PROCESS_REQUEST_DELAY_MS)) + return new Promise((resolve) => setTimeout(resolve, CONST.NETWORK.PROCESS_REQUEST_DELAY_MS)); }) .then(() => { // THEN we should see that our third (non-persistable) request has run last diff --git a/tests/unit/FileUtilsTest.js b/tests/unit/FileUtilsTest.js index a2af56abdfac..a5f4f34fe913 100644 --- a/tests/unit/FileUtilsTest.js +++ b/tests/unit/FileUtilsTest.js @@ -2,7 +2,7 @@ import CONST from '../../src/CONST'; import DateUtils from '../../src/libs/DateUtils'; import * as FileUtils from '../../src/libs/fileDownload/FileUtils'; -jest.useFakeTimers() +jest.useFakeTimers(); describe('FileUtils', () => { describe('splitExtensionFromFileName', () => { diff --git a/tests/utils/TestHelper.js b/tests/utils/TestHelper.js index 03a3d2cb1480..a8424d14ed33 100644 --- a/tests/utils/TestHelper.js +++ b/tests/utils/TestHelper.js @@ -153,7 +153,7 @@ function getGlobalFetchMock() { let isPaused = false; let shouldFail = false; - const getResponse = () => + const getResponse = () => shouldFail ? { ok: true, @@ -163,7 +163,6 @@ function getGlobalFetchMock() { ok: true, json: () => Promise.resolve({jsonCode: 200}), }; - const mockFetch = jest.fn().mockImplementation(() => { if (!isPaused) { diff --git a/tests/utils/waitForPromisesToResolve.js b/tests/utils/waitForPromisesToResolve.js index 9241bef09d2e..39af03d2b200 100644 --- a/tests/utils/waitForPromisesToResolve.js +++ b/tests/utils/waitForPromisesToResolve.js @@ -1,4 +1,4 @@ -const usingFakeTimers = () => !!(global.setTimeout.mock||global.setTimeout.clock) +const usingFakeTimers = () => !!(global.setTimeout.mock || global.setTimeout.clock); /** * Method which waits for all asynchronous JS to stop executing before proceeding. This helps test things like actions @@ -13,27 +13,28 @@ const usingFakeTimers = () => !!(global.setTimeout.mock||global.setTimeout.clock * * @returns {Promise} */ -export default () => new Promise((outerResolve) => { - // We first need to exhaust the microtask queue, before we schedule the next task in the macrotask queue (setTimeout). - // This is because we need to wait for all async onyx operations to finish, as they might schedule other macrotasks, - // and we want those task to run before our scheduled task. - // E.g. this makes the following code work for tests: - // - // Onyx.merge(...) - // return waitForPromiseToResolve().then(...); - // - // Note: Ideally, you'd just await the Onyx.merge promise. +export default () => + new Promise((outerResolve) => { + // We first need to exhaust the microtask queue, before we schedule the next task in the macrotask queue (setTimeout). + // This is because we need to wait for all async onyx operations to finish, as they might schedule other macrotasks, + // and we want those task to run before our scheduled task. + // E.g. this makes the following code work for tests: + // + // Onyx.merge(...) + // return waitForPromiseToResolve().then(...); + // + // Note: Ideally, you'd just await the Onyx.merge promise. - new Promise((innerResolve) => { - setImmediate(() => { - innerResolve("Flush all micro tasks that pushed by using '.then' method"); + new Promise((innerResolve) => { + setImmediate(() => { + innerResolve("Flush all micro tasks that pushed by using '.then' method"); + }); + }).then(() => { + if (usingFakeTimers()) { + jest.runOnlyPendingTimers(); + outerResolve(); + return; + } + setTimeout(outerResolve, 0); }); - }).then(() => { - if (usingFakeTimers()) { - jest.runOnlyPendingTimers() - outerResolve() - return - } - setTimeout(outerResolve, 0); }); -}); From 36a390a23ecfc52869dc9bc51a93ed591524aa1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szymon=20Kapa=C5=82a?= Date: Thu, 14 Sep 2023 13:11:32 +0200 Subject: [PATCH 15/23] Update tests/utils/waitForPromisesToResolve.js Co-authored-by: Marc Glasser --- tests/utils/waitForPromisesToResolve.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/utils/waitForPromisesToResolve.js b/tests/utils/waitForPromisesToResolve.js index 39af03d2b200..1bc0929d1097 100644 --- a/tests/utils/waitForPromisesToResolve.js +++ b/tests/utils/waitForPromisesToResolve.js @@ -1,4 +1,4 @@ -const usingFakeTimers = () => !!(global.setTimeout.mock || global.setTimeout.clock); +const getIsUsingFakeTimers = () => Boolean(global.setTimeout.mock || global.setTimeout.clock); /** * Method which waits for all asynchronous JS to stop executing before proceeding. This helps test things like actions From c5a7d4055fc472154242f685d337f158dd25f777 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szymon=20Kapa=C5=82a?= Date: Thu, 14 Sep 2023 13:11:42 +0200 Subject: [PATCH 16/23] Update tests/actions/ReportTest.js Co-authored-by: Marc Glasser --- tests/actions/ReportTest.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/actions/ReportTest.js b/tests/actions/ReportTest.js index bd6118646a7a..2fa3b87df300 100644 --- a/tests/actions/ReportTest.js +++ b/tests/actions/ReportTest.js @@ -412,7 +412,7 @@ describe('actions/Report', () => { expect(ReportUtils.isUnread(report)).toBe(false); expect(report.lastMessageText).toBe('Current User Comment 2'); }); - waitForPromisesToResolve(); // flushing onyx.set as it wull be batched + waitForPromisesToResolve(); // flushing onyx.set as it will be batched return setPromise; }); From 577fda34cc15520819ab7997ca692cd0b9e84555 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szymon=20Kapa=C5=82a?= Date: Thu, 14 Sep 2023 13:27:44 +0200 Subject: [PATCH 17/23] clean up --- tests/actions/IOUTest.js | 7 +++---- tests/actions/ReportTest.js | 12 ++++-------- tests/unit/APITest.js | 3 ++- tests/utils/fastForwardTwoMicrotasksCycles.js | 14 ++++++++++++++ tests/utils/waitForPromisesToResolve.js | 2 +- 5 files changed, 24 insertions(+), 14 deletions(-) create mode 100644 tests/utils/fastForwardTwoMicrotasksCycles.js diff --git a/tests/actions/IOUTest.js b/tests/actions/IOUTest.js index e14334e8e3d2..470a62bcc314 100644 --- a/tests/actions/IOUTest.js +++ b/tests/actions/IOUTest.js @@ -10,6 +10,7 @@ import * as NumberUtils from '../../src/libs/NumberUtils'; import * as ReportActions from '../../src/libs/actions/ReportActions'; import * as Report from '../../src/libs/actions/Report'; import OnyxUpdateManager from '../../src/libs/actions/OnyxUpdateManager'; +import fastForwardTwoMicrotasksCycles from '../utils/fastForwardTwoMicrotasksCycles'; const CARLOS_EMAIL = 'cmartins@expensifail.com'; const CARLOS_ACCOUNT_ID = 1; @@ -492,8 +493,7 @@ describe('actions/IOU', () => { }), ) .then(fetch.resume) - .then(waitForPromisesToResolve) - .then(waitForPromisesToResolve) + .then(fastForwardTwoMicrotasksCycles) .then( () => new Promise((resolve) => { @@ -1130,8 +1130,7 @@ describe('actions/IOU', () => { }), ) .then(fetch.resume) - .then(waitForPromisesToResolve) - .then(waitForPromisesToResolve) + .then(fastForwardTwoMicrotasksCycles) .then( () => new Promise((resolve) => { diff --git a/tests/actions/ReportTest.js b/tests/actions/ReportTest.js index 2fa3b87df300..c3a6d99f058d 100644 --- a/tests/actions/ReportTest.js +++ b/tests/actions/ReportTest.js @@ -16,6 +16,7 @@ import * as ReportUtils from '../../src/libs/ReportUtils'; import DateUtils from '../../src/libs/DateUtils'; import * as SequentialQueue from '../../src/libs/Network/SequentialQueue'; import OnyxUpdateManager from '../../src/libs/actions/OnyxUpdateManager'; +import fastForwardTwoMicrotasksCycles from '../utils/fastForwardTwoMicrotasksCycles'; jest.mock('../../src/libs/actions/Report', () => { const originalModule = jest.requireActual('../../src/libs/actions/Report'); @@ -207,14 +208,12 @@ describe('actions/Report', () => { const USER_2_ACCOUNT_ID = 2; const setPromise = Onyx.set(`${ONYXKEYS.COLLECTION.REPORT}${REPORT_ID}`, {reportName: 'Test', reportID: REPORT_ID}) .then(() => TestHelper.signInWithTestUser(USER_1_ACCOUNT_ID, USER_1_LOGIN)) - .then(waitForPromisesToResolve) - .then(waitForPromisesToResolve) + .then(fastForwardTwoMicrotasksCycles) .then(() => { // Given a test user that is subscribed to Pusher events User.subscribeToUserEvents(); return waitForPromisesToResolve(); }) - .then(waitForPromisesToResolve) .then(() => TestHelper.setPersonalDetails(USER_1_LOGIN, USER_1_ACCOUNT_ID)) .then(() => { // When a Pusher event is handled for a new report comment that includes a mention of the current user @@ -251,10 +250,8 @@ describe('actions/Report', () => { }, }, ]); - return waitForPromisesToResolve(); + return fastForwardTwoMicrotasksCycles(); }) - .then(waitForPromisesToResolve) - .then(waitForPromisesToResolve) .then(() => { // Then the report will be unread expect(ReportUtils.isUnread(report)).toBe(true); @@ -382,9 +379,8 @@ describe('actions/Report', () => { optimisticReportActions, ]); - return waitForPromisesToResolve(); + return fastForwardTwoMicrotasksCycles(); }) - .then(waitForPromisesToResolve) .then(() => { // If the user deletes a comment that is before the last read Report.deleteReportComment(REPORT_ID, {...reportActions[200]}); diff --git a/tests/unit/APITest.js b/tests/unit/APITest.js index 29e5532eabfe..6d768b13945b 100644 --- a/tests/unit/APITest.js +++ b/tests/unit/APITest.js @@ -13,6 +13,7 @@ import * as API from '../../src/libs/API'; import * as SequentialQueue from '../../src/libs/Network/SequentialQueue'; import * as Request from '../../src/libs/Request'; import * as RequestThrottle from '../../src/libs/RequestThrottle'; +import fastForwardTwoMicrotasksCycles from '../utils/fastForwardTwoMicrotasksCycles'; jest.mock('../../src/libs/Log'); @@ -202,7 +203,7 @@ describe('APITests', () => { .then(() => { // When API Write commands are made API.write('mock command', {param1: 'value1'}); - return waitForPromisesToResolve().then(waitForPromisesToResolve); + return fastForwardTwoMicrotasksCycles(); }) // When we resume connectivity diff --git a/tests/utils/fastForwardTwoMicrotasksCycles.js b/tests/utils/fastForwardTwoMicrotasksCycles.js new file mode 100644 index 000000000000..4a9cbce41887 --- /dev/null +++ b/tests/utils/fastForwardTwoMicrotasksCycles.js @@ -0,0 +1,14 @@ +import waitForPromisesToResolve from './waitForPromisesToResolve'; + +/** + * Method flushes microtasks and pending timers twice. Because we batch onyx updates + * Some operations like for instance network requests takes 2 microtask cycles to resolve + * **Note:** It is recommended to wait for the Onyx operations, so in your tests its preferred to do: + * ✅ Onyx.merge(...).then(...) + * than to do + * ❌ Onyx.merge(...) + * waitForPromisesToResolve().then(...) + * + * @returns {Promise} + */ +export default () => waitForPromisesToResolve().then(waitForPromisesToResolve); diff --git a/tests/utils/waitForPromisesToResolve.js b/tests/utils/waitForPromisesToResolve.js index 1bc0929d1097..c868476af402 100644 --- a/tests/utils/waitForPromisesToResolve.js +++ b/tests/utils/waitForPromisesToResolve.js @@ -30,7 +30,7 @@ export default () => innerResolve("Flush all micro tasks that pushed by using '.then' method"); }); }).then(() => { - if (usingFakeTimers()) { + if (getIsUsingFakeTimers()) { jest.runOnlyPendingTimers(); outerResolve(); return; From dcc2ab2b9cf78ea959592d044fd07fe61fe1621b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szymon=20Kapa=C5=82a?= Date: Thu, 14 Sep 2023 20:12:28 +0200 Subject: [PATCH 18/23] clean up --- tests/actions/ReportTest.js | 7 ++++++- tests/unit/APITest.js | 2 +- tests/utils/getIsUsingFakeTimers.js | 1 + tests/utils/waitForPromisesToResolve.js | 3 +-- 4 files changed, 9 insertions(+), 4 deletions(-) create mode 100644 tests/utils/getIsUsingFakeTimers.js diff --git a/tests/actions/ReportTest.js b/tests/actions/ReportTest.js index c3a6d99f058d..4fcccb97da20 100644 --- a/tests/actions/ReportTest.js +++ b/tests/actions/ReportTest.js @@ -17,6 +17,7 @@ import DateUtils from '../../src/libs/DateUtils'; import * as SequentialQueue from '../../src/libs/Network/SequentialQueue'; import OnyxUpdateManager from '../../src/libs/actions/OnyxUpdateManager'; import fastForwardTwoMicrotasksCycles from '../utils/fastForwardTwoMicrotasksCycles'; +import getIsUsingFakeTimers from '../utils/getIsUsingFakeTimers'; jest.mock('../../src/libs/actions/Report', () => { const originalModule = jest.requireActual('../../src/libs/actions/Report'); @@ -39,7 +40,11 @@ describe('actions/Report', () => { beforeEach(() => { const promise = Onyx.clear().then(jest.useRealTimers); - waitForPromisesToResolve(); + if (getIsUsingFakeTimers()) { + // flushing pending timers + // Onyx.clear() promise is resolved in batch which happends after the current microtasks cycle + setImmediate(jest.runOnlyPendingTimers); + } return promise; }); diff --git a/tests/unit/APITest.js b/tests/unit/APITest.js index 6d768b13945b..9e936dfb7aa6 100644 --- a/tests/unit/APITest.js +++ b/tests/unit/APITest.js @@ -168,7 +168,7 @@ describe('APITests', () => { expect(PersistedRequests.getAll()).toEqual([expect.objectContaining({command: 'mock command', data: expect.objectContaining({param2: 'value2'})})]); // We need to advance past the request throttle back off timer because the request won't be retried until then - return new Promise((resolve) => setTimeout(resolve, 1000)).then(waitForPromisesToResolve); + return new Promise((resolve) => setTimeout(resolve, CONST.NETWORK.MAX_RANDOM_RETRY_WAIT_TIME_MS)).then(waitForPromisesToResolve); }) .then(() => { // Finally, after it succeeds the queue should be empty diff --git a/tests/utils/getIsUsingFakeTimers.js b/tests/utils/getIsUsingFakeTimers.js new file mode 100644 index 000000000000..376312ac6c06 --- /dev/null +++ b/tests/utils/getIsUsingFakeTimers.js @@ -0,0 +1 @@ +export default () => Boolean(global.setTimeout.mock || global.setTimeout.clock); diff --git a/tests/utils/waitForPromisesToResolve.js b/tests/utils/waitForPromisesToResolve.js index c868476af402..f42ac73477bd 100644 --- a/tests/utils/waitForPromisesToResolve.js +++ b/tests/utils/waitForPromisesToResolve.js @@ -1,5 +1,4 @@ -const getIsUsingFakeTimers = () => Boolean(global.setTimeout.mock || global.setTimeout.clock); - +import getIsUsingFakeTimers from './getIsUsingFakeTimers'; /** * Method which waits for all asynchronous JS to stop executing before proceeding. This helps test things like actions * that expect some Onyx value to be available. This way we do not have to explicitly wait for an action to finish From f386d30460d139d117a21a9f731056d170ad82a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szymon=20Kapa=C5=82a?= Date: Thu, 14 Sep 2023 21:56:43 +0200 Subject: [PATCH 19/23] rename to waitForNetworkPromises and waitForBatchedUpdates --- src/libs/actions/PersistedRequests.js | 4 ++ tests/README.md | 4 +- tests/actions/IOUTest.js | 26 +++---- tests/actions/ReportTest.js | 70 +++++++++---------- tests/actions/SessionTest.js | 10 +-- tests/perf-test/SidebarLinks.perf-test.js | 4 +- tests/ui/UnreadIndicatorsTest.js | 28 ++++---- tests/unit/APITest.js | 62 ++++++++-------- tests/unit/CurrencyUtilsTest.js | 4 +- tests/unit/DateUtilsTest.js | 4 +- tests/unit/EmojiTest.js | 10 +-- tests/unit/IOUUtilsTest.js | 4 +- tests/unit/LocalePhoneNumberTest.js | 4 +- tests/unit/LocalizeTests.js | 4 +- tests/unit/MigrationTest.js | 6 +- tests/unit/NetworkTest.js | 28 ++++---- tests/unit/OptionsListUtilsTest.js | 6 +- tests/unit/ReportUtilsTest.js | 6 +- tests/unit/RequestTest.js | 6 +- tests/unit/SidebarFilterTest.js | 44 ++++++------ tests/unit/SidebarOrderTest.js | 42 +++++------ tests/unit/SidebarTest.js | 12 ++-- tests/unit/enhanceParametersTest.js | 6 +- tests/utils/TestHelper.js | 12 ++-- ...sToResolve.js => waitForBatchedUpdates.js} | 4 +- ...Act.js => waitForBatchedUpdatesWithAct.js} | 10 +-- ...sksCycles.js => waitForNetworkPromises.js} | 6 +- ...s => wrapOnyxWithWaitForBatchedUpdates.js} | 8 +-- 28 files changed, 219 insertions(+), 215 deletions(-) rename tests/utils/{waitForPromisesToResolve.js => waitForBatchedUpdates.js} (93%) rename tests/utils/{waitForPromisesToResolveWithAct.js => waitForBatchedUpdatesWithAct.js} (84%) rename tests/utils/{fastForwardTwoMicrotasksCycles.js => waitForNetworkPromises.js} (66%) rename tests/utils/{wrapOnyxWithWaitForPromisesToResolve.js => wrapOnyxWithWaitForBatchedUpdates.js} (73%) diff --git a/src/libs/actions/PersistedRequests.js b/src/libs/actions/PersistedRequests.js index ff6d083c58bb..e7cbfc18efcd 100644 --- a/src/libs/actions/PersistedRequests.js +++ b/src/libs/actions/PersistedRequests.js @@ -9,6 +9,10 @@ Onyx.connect({ callback: (val) => (persistedRequests = val || []), }); +/** + * This promise is only used by tests. DO NOT USE THIS PROMISE IN THE APPLICATION CODE + * @returns {void} + */ function clear() { return Onyx.set(ONYXKEYS.PERSISTED_REQUESTS, []); } diff --git a/tests/README.md b/tests/README.md index 4ac21499c0f4..dd5b5fc1635f 100644 --- a/tests/README.md +++ b/tests/README.md @@ -6,7 +6,7 @@ - Much of the logic in the app is asynchronous in nature. [`react-native-onyx`](https://github.com/expensify/react-native-onyx) relies on [`AsyncStorage`](https://github.com/react-native-async-storage/async-storage) and writes data async before updating subscribers. - [Actions](https://github.com/Expensify/App#actions) do not typically return a `Promise` and therefore can't always be "awaited" before running an assertion. -- To test a result after some asynchronous code has run we can use [`Onyx.connect()`](https://github.com/Expensify/react-native-onyx/blob/2c94a94e51fab20330f7bd5381b72ea6c25553d9/lib/Onyx.js#L217-L231) and the helper method [`waitForPromisesToResolve()`](https://github.com/Expensify/ReactNativeChat/blob/ca2fa88a5789b82463d35eddc3d57f70a7286868/tests/utils/waitForPromisesToResolve.js#L1-L9) which returns a `Promise` and will ensure that all other `Promises` have finished running before resolving. +- To test a result after some asynchronous code has run we can use [`Onyx.connect()`](https://github.com/Expensify/react-native-onyx/blob/2c94a94e51fab20330f7bd5381b72ea6c25553d9/lib/Onyx.js#L217-L231) and the helper method [`waitForBatchedUpdates()`](https://github.com/Expensify/ReactNativeChat/blob/ca2fa88a5789b82463d35eddc3d57f70a7286868/tests/utils/waitForBatchedUpdates.js#L1-L9) which returns a `Promise` and will ensure that all other `Promises` have finished running before resolving. - **Important Note:** When writing any asynchronous Jest test it's very important that your test itself **return a `Promise`**. ## Mocking Network Requests @@ -65,7 +65,7 @@ describe('actions/Report', () => { // When we add a new action to that report Report.addComment(REPORT_ID, 'Hello!'); - return waitForPromisesToResolve() + return waitForBatchedUpdates() .then(() => { const action = reportActions[ACTION_ID]; diff --git a/tests/actions/IOUTest.js b/tests/actions/IOUTest.js index 470a62bcc314..01c2b4711ce7 100644 --- a/tests/actions/IOUTest.js +++ b/tests/actions/IOUTest.js @@ -2,7 +2,7 @@ import _ from 'underscore'; import Onyx from 'react-native-onyx'; import CONST from '../../src/CONST'; import ONYXKEYS from '../../src/ONYXKEYS'; -import waitForPromisesToResolve from '../utils/waitForPromisesToResolve'; +import waitForBatchedUpdates from '../utils/waitForBatchedUpdates'; import * as IOU from '../../src/libs/actions/IOU'; import * as TestHelper from '../utils/TestHelper'; import DateUtils from '../../src/libs/DateUtils'; @@ -10,7 +10,7 @@ import * as NumberUtils from '../../src/libs/NumberUtils'; import * as ReportActions from '../../src/libs/actions/ReportActions'; import * as Report from '../../src/libs/actions/Report'; import OnyxUpdateManager from '../../src/libs/actions/OnyxUpdateManager'; -import fastForwardTwoMicrotasksCycles from '../utils/fastForwardTwoMicrotasksCycles'; +import waitForNetworkPromises from '../utils/waitForNetworkPromises'; const CARLOS_EMAIL = 'cmartins@expensifail.com'; const CARLOS_ACCOUNT_ID = 1; @@ -31,7 +31,7 @@ describe('actions/IOU', () => { beforeEach(() => { global.fetch = TestHelper.getGlobalFetchMock(); - return Onyx.clear().then(waitForPromisesToResolve); + return Onyx.clear().then(waitForBatchedUpdates); }); describe('requestMoney', () => { @@ -45,7 +45,7 @@ describe('actions/IOU', () => { let transactionID; fetch.pause(); IOU.requestMoney({}, amount, CONST.CURRENCY.USD, '', merchant, RORY_EMAIL, RORY_ACCOUNT_ID, {login: CARLOS_EMAIL, accountID: CARLOS_ACCOUNT_ID}, comment); - return waitForPromisesToResolve() + return waitForBatchedUpdates() .then( () => new Promise((resolve) => { @@ -210,7 +210,7 @@ describe('actions/IOU', () => { ) .then(() => { IOU.requestMoney(chatReport, amount, CONST.CURRENCY.USD, '', '', RORY_EMAIL, RORY_ACCOUNT_ID, {login: CARLOS_EMAIL, accountID: CARLOS_ACCOUNT_ID}, comment); - return waitForPromisesToResolve(); + return waitForBatchedUpdates(); }) .then( () => @@ -310,7 +310,7 @@ describe('actions/IOU', () => { }), ) .then(fetch.resume) - .then(waitForPromisesToResolve) + .then(waitForBatchedUpdates) .then( () => new Promise((resolve) => { @@ -402,7 +402,7 @@ describe('actions/IOU', () => { .then(() => Onyx.set(`${ONYXKEYS.COLLECTION.TRANSACTION}${existingTransaction.transactionID}`, existingTransaction)) .then(() => { IOU.requestMoney(chatReport, amount, CONST.CURRENCY.USD, '', '', RORY_EMAIL, RORY_ACCOUNT_ID, {login: CARLOS_EMAIL, accountID: CARLOS_ACCOUNT_ID}, comment); - return waitForPromisesToResolve(); + return waitForBatchedUpdates(); }) .then( () => @@ -493,7 +493,7 @@ describe('actions/IOU', () => { }), ) .then(fetch.resume) - .then(fastForwardTwoMicrotasksCycles) + .then(waitForNetworkPromises) .then( () => new Promise((resolve) => { @@ -536,7 +536,7 @@ describe('actions/IOU', () => { fetch.pause(); IOU.requestMoney({}, amount, CONST.CURRENCY.USD, '', '', RORY_EMAIL, RORY_ACCOUNT_ID, {login: CARLOS_EMAIL, accountID: CARLOS_ACCOUNT_ID}, comment); return ( - waitForPromisesToResolve() + waitForBatchedUpdates() .then( () => new Promise((resolve) => { @@ -907,7 +907,7 @@ describe('actions/IOU', () => { comment, CONST.CURRENCY.USD, ); - return waitForPromisesToResolve(); + return waitForBatchedUpdates(); }) .then( () => @@ -1130,7 +1130,7 @@ describe('actions/IOU', () => { }), ) .then(fetch.resume) - .then(fastForwardTwoMicrotasksCycles) + .then(waitForNetworkPromises) .then( () => new Promise((resolve) => { @@ -1191,7 +1191,7 @@ describe('actions/IOU', () => { let payIOUAction; let transaction; IOU.requestMoney({}, amount, CONST.CURRENCY.USD, '', '', RORY_EMAIL, RORY_ACCOUNT_ID, {login: CARLOS_EMAIL, accountID: CARLOS_ACCOUNT_ID}, comment); - return waitForPromisesToResolve() + return waitForBatchedUpdates() .then( () => new Promise((resolve) => { @@ -1271,7 +1271,7 @@ describe('actions/IOU', () => { .then(() => { fetch.pause(); IOU.payMoneyRequest(CONST.IOU.PAYMENT_TYPE.ELSEWHERE, chatReport, iouReport); - return waitForPromisesToResolve(); + return waitForBatchedUpdates(); }) .then( () => diff --git a/tests/actions/ReportTest.js b/tests/actions/ReportTest.js index 4fcccb97da20..62109089665c 100644 --- a/tests/actions/ReportTest.js +++ b/tests/actions/ReportTest.js @@ -6,7 +6,7 @@ import {beforeEach, beforeAll, afterEach, describe, it, expect} from '@jest/glob import ONYXKEYS from '../../src/ONYXKEYS'; import CONST from '../../src/CONST'; import * as Report from '../../src/libs/actions/Report'; -import waitForPromisesToResolve from '../utils/waitForPromisesToResolve'; +import waitForBatchedUpdates from '../utils/waitForBatchedUpdates'; import PusherHelper from '../utils/PusherHelper'; import * as TestHelper from '../utils/TestHelper'; import Log from '../../src/libs/Log'; @@ -16,7 +16,7 @@ import * as ReportUtils from '../../src/libs/ReportUtils'; import DateUtils from '../../src/libs/DateUtils'; import * as SequentialQueue from '../../src/libs/Network/SequentialQueue'; import OnyxUpdateManager from '../../src/libs/actions/OnyxUpdateManager'; -import fastForwardTwoMicrotasksCycles from '../utils/fastForwardTwoMicrotasksCycles'; +import waitForNetworkPromises from '../utils/waitForNetworkPromises'; import getIsUsingFakeTimers from '../utils/getIsUsingFakeTimers'; jest.mock('../../src/libs/actions/Report', () => { @@ -77,14 +77,14 @@ describe('actions/Report', () => { return TestHelper.signInWithTestUser(TEST_USER_ACCOUNT_ID, TEST_USER_LOGIN) .then(() => { User.subscribeToUserEvents(); - return waitForPromisesToResolve(); + return waitForBatchedUpdates(); }) .then(() => TestHelper.setPersonalDetails(TEST_USER_LOGIN, TEST_USER_ACCOUNT_ID)) .then(() => { // This is a fire and forget response, but once it completes we should be able to verify that we // have an "optimistic" report action in Onyx. Report.addComment(REPORT_ID, 'Testing a comment'); - return waitForPromisesToResolve(); + return waitForBatchedUpdates(); }) .then(() => { const resultAction = _.first(_.values(reportActions)); @@ -120,7 +120,7 @@ describe('actions/Report', () => { // Once a reportComment event is emitted to the Pusher channel we should see the comment get processed // by the Pusher callback and added to the storage so we must wait for promises to resolve again and // then verify the data is in Onyx. - return waitForPromisesToResolve(); + return waitForBatchedUpdates(); }) .then(() => { // Verify there is only one action and our optimistic comment has been removed @@ -148,7 +148,7 @@ describe('actions/Report', () => { return TestHelper.signInWithTestUser(TEST_USER_ACCOUNT_ID, TEST_USER_LOGIN) .then(() => { Report.togglePinnedState(REPORT_ID, false); - return waitForPromisesToResolve(); + return waitForBatchedUpdates(); }) .then(() => { // Test that Onyx immediately updated the report pin state. @@ -180,7 +180,7 @@ describe('actions/Report', () => { expect(PersistedRequests.getAll().length).toBe(1); // When we wait for the queue to run - return waitForPromisesToResolve(); + return waitForBatchedUpdates(); }) .then(() => { // THEN only ONE call to AddComment will happen @@ -213,11 +213,11 @@ describe('actions/Report', () => { const USER_2_ACCOUNT_ID = 2; const setPromise = Onyx.set(`${ONYXKEYS.COLLECTION.REPORT}${REPORT_ID}`, {reportName: 'Test', reportID: REPORT_ID}) .then(() => TestHelper.signInWithTestUser(USER_1_ACCOUNT_ID, USER_1_LOGIN)) - .then(fastForwardTwoMicrotasksCycles) + .then(waitForNetworkPromises) .then(() => { // Given a test user that is subscribed to Pusher events User.subscribeToUserEvents(); - return waitForPromisesToResolve(); + return waitForBatchedUpdates(); }) .then(() => TestHelper.setPersonalDetails(USER_1_LOGIN, USER_1_ACCOUNT_ID)) .then(() => { @@ -255,7 +255,7 @@ describe('actions/Report', () => { }, }, ]); - return fastForwardTwoMicrotasksCycles(); + return waitForNetworkPromises(); }) .then(() => { // Then the report will be unread @@ -269,8 +269,8 @@ describe('actions/Report', () => { currentTime = DateUtils.getDBTime(); Report.openReport(REPORT_ID); Report.readNewestAction(REPORT_ID); - waitForPromisesToResolve(); - return waitForPromisesToResolve(); + waitForBatchedUpdates(); + return waitForBatchedUpdates(); }) .then(() => { // The report will be read @@ -283,7 +283,7 @@ describe('actions/Report', () => { // When the user manually marks a message as "unread" jest.advanceTimersByTime(10); Report.markCommentAsUnread(REPORT_ID, reportActionCreatedDate); - return waitForPromisesToResolve(); + return waitForBatchedUpdates(); }) .then(() => { // Then the report will be unread and show the green dot for unread mentions in LHN @@ -295,7 +295,7 @@ describe('actions/Report', () => { jest.advanceTimersByTime(10); currentTime = DateUtils.getDBTime(); Report.addComment(REPORT_ID, 'Current User Comment 1'); - return waitForPromisesToResolve(); + return waitForBatchedUpdates(); }) .then(() => { // The report will be read, the green dot for unread mentions will go away, and the lastReadTime updated @@ -308,7 +308,7 @@ describe('actions/Report', () => { jest.advanceTimersByTime(10); currentTime = DateUtils.getDBTime(); Report.addComment(REPORT_ID, 'Current User Comment 2'); - return waitForPromisesToResolve(); + return waitForBatchedUpdates(); }) .then(() => { // The report will be read and the lastReadTime updated @@ -320,7 +320,7 @@ describe('actions/Report', () => { jest.advanceTimersByTime(10); currentTime = DateUtils.getDBTime(); Report.addComment(REPORT_ID, 'Current User Comment 3'); - return waitForPromisesToResolve(); + return waitForBatchedUpdates(); }) .then(() => { // The report will be read and the lastReadTime updated @@ -384,12 +384,12 @@ describe('actions/Report', () => { optimisticReportActions, ]); - return fastForwardTwoMicrotasksCycles(); + return waitForNetworkPromises(); }) .then(() => { // If the user deletes a comment that is before the last read Report.deleteReportComment(REPORT_ID, {...reportActions[200]}); - return waitForPromisesToResolve(); + return waitForBatchedUpdates(); }) .then(() => { // Then no change will occur @@ -398,7 +398,7 @@ describe('actions/Report', () => { // When the user manually marks a message as "unread" Report.markCommentAsUnread(REPORT_ID, reportActionCreatedDate); - return waitForPromisesToResolve(); + return waitForBatchedUpdates(); }) .then(() => { // Then we should expect the report to be to be unread @@ -407,13 +407,13 @@ describe('actions/Report', () => { // If the user deletes the last comment after the lastReadTime the lastMessageText will reflect the new last comment Report.deleteReportComment(REPORT_ID, {...reportActions[400]}); - return waitForPromisesToResolve(); + return waitForBatchedUpdates(); }) .then(() => { expect(ReportUtils.isUnread(report)).toBe(false); expect(report.lastMessageText).toBe('Current User Comment 2'); }); - waitForPromisesToResolve(); // flushing onyx.set as it will be batched + waitForBatchedUpdates(); // flushing onyx.set as it will be batched return setPromise; }); @@ -507,10 +507,10 @@ describe('actions/Report', () => { // Setup user and pusher listeners return TestHelper.signInWithTestUser(TEST_USER_ACCOUNT_ID) - .then(waitForPromisesToResolve) + .then(waitForBatchedUpdates) .then(() => { User.subscribeToUserEvents(); - return waitForPromisesToResolve(); + return waitForBatchedUpdates(); }) .then(() => { // Simulate a Pusher Onyx update with a report action with shouldNotify @@ -524,7 +524,7 @@ describe('actions/Report', () => { shouldNotify: true, }, ]); - return SequentialQueue.getCurrentRequest().then(waitForPromisesToResolve); + return SequentialQueue.getCurrentRequest().then(waitForBatchedUpdates); }) .then(() => { // Ensure we show a notification for this new report action @@ -566,14 +566,14 @@ describe('actions/Report', () => { return TestHelper.signInWithTestUser(TEST_USER_ACCOUNT_ID, TEST_USER_LOGIN) .then(() => { User.subscribeToUserEvents(); - return waitForPromisesToResolve(); + return waitForBatchedUpdates(); }) .then(() => TestHelper.setPersonalDetails(TEST_USER_LOGIN, TEST_USER_ACCOUNT_ID)) .then(() => { // This is a fire and forget response, but once it completes we should be able to verify that we // have an "optimistic" report action in Onyx. Report.addComment(REPORT_ID, 'Testing a comment'); - return waitForPromisesToResolve(); + return waitForBatchedUpdates(); }) .then(() => { reportAction = _.first(_.values(reportActions)); @@ -581,7 +581,7 @@ describe('actions/Report', () => { // Add a reaction to the comment Report.toggleEmojiReaction(REPORT_ID, reportAction, EMOJI); - return waitForPromisesToResolve(); + return waitForBatchedUpdates(); }) .then(() => { reportAction = _.first(_.values(reportActions)); @@ -599,7 +599,7 @@ describe('actions/Report', () => { // Now we remove the reaction Report.toggleEmojiReaction(REPORT_ID, reportAction, EMOJI, reportActionReaction); - return waitForPromisesToResolve(); + return waitForBatchedUpdates(); }) .then(() => { // Expect the reaction to have null where the users reaction used to be @@ -612,13 +612,13 @@ describe('actions/Report', () => { // Add the same reaction to the same report action with a different skintone Report.toggleEmojiReaction(REPORT_ID, reportAction, EMOJI); - return waitForPromisesToResolve() + return waitForBatchedUpdates() .then(() => { reportAction = _.first(_.values(reportActions)); const reportActionReaction = reportActionsReactions[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS_REACTIONS}${reportActionID}`]; Report.toggleEmojiReaction(REPORT_ID, reportAction, EMOJI, reportActionReaction, EMOJI_SKIN_TONE); - return waitForPromisesToResolve(); + return waitForBatchedUpdates(); }) .then(() => { reportAction = _.first(_.values(reportActions)); @@ -641,7 +641,7 @@ describe('actions/Report', () => { // Now we remove the reaction, and expect that both variations are removed Report.toggleEmojiReaction(REPORT_ID, reportAction, EMOJI, reportActionReaction); - return waitForPromisesToResolve(); + return waitForBatchedUpdates(); }) .then(() => { // Expect the reaction to have null where the users reaction used to be @@ -684,21 +684,21 @@ describe('actions/Report', () => { return TestHelper.signInWithTestUser(TEST_USER_ACCOUNT_ID, TEST_USER_LOGIN) .then(() => { User.subscribeToUserEvents(); - return waitForPromisesToResolve(); + return waitForBatchedUpdates(); }) .then(() => TestHelper.setPersonalDetails(TEST_USER_LOGIN, TEST_USER_ACCOUNT_ID)) .then(() => { // This is a fire and forget response, but once it completes we should be able to verify that we // have an "optimistic" report action in Onyx. Report.addComment(REPORT_ID, 'Testing a comment'); - return waitForPromisesToResolve(); + return waitForBatchedUpdates(); }) .then(() => { resultAction = _.first(_.values(reportActions)); // Add a reaction to the comment Report.toggleEmojiReaction(REPORT_ID, resultAction, EMOJI, {}); - return waitForPromisesToResolve(); + return waitForBatchedUpdates(); }) .then(() => { resultAction = _.first(_.values(reportActions)); @@ -708,7 +708,7 @@ describe('actions/Report', () => { // should get removed instead of added again. const reportActionReaction = reportActionsReactions[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS_REACTIONS}${resultAction.reportActionID}`]; Report.toggleEmojiReaction(REPORT_ID, resultAction, EMOJI, reportActionReaction, 2); - return waitForPromisesToResolve(); + return waitForBatchedUpdates(); }) .then(() => { // Expect the reaction to have null where the users reaction used to be diff --git a/tests/actions/SessionTest.js b/tests/actions/SessionTest.js index c558d877433b..4ecb2a33b763 100644 --- a/tests/actions/SessionTest.js +++ b/tests/actions/SessionTest.js @@ -1,7 +1,7 @@ import Onyx from 'react-native-onyx'; import {beforeEach, jest, test} from '@jest/globals'; import HttpUtils from '../../src/libs/HttpUtils'; -import waitForPromisesToResolve from '../utils/waitForPromisesToResolve'; +import waitForBatchedUpdates from '../utils/waitForBatchedUpdates'; import ONYXKEYS from '../../src/ONYXKEYS'; import * as TestHelper from '../utils/TestHelper'; import CONST from '../../src/CONST'; @@ -26,7 +26,7 @@ Onyx.init({ }); OnyxUpdateManager(); -beforeEach(() => Onyx.clear().then(waitForPromisesToResolve)); +beforeEach(() => Onyx.clear().then(waitForBatchedUpdates)); describe('Session', () => { test('Authenticate is called with saved credentials when a session expires', () => { @@ -50,7 +50,7 @@ describe('Session', () => { // When we sign in with the test user return TestHelper.signInWithTestUser(TEST_USER_ACCOUNT_ID, TEST_USER_LOGIN, 'Password1', TEST_INITIAL_AUTH_TOKEN) - .then(waitForPromisesToResolve) + .then(waitForBatchedUpdates) .then(() => { // Then our re-authentication credentials should be generated and our session data // have the correct information + initial authToken. @@ -88,7 +88,7 @@ describe('Session', () => { // When we attempt to fetch the initial app data via the API App.confirmReadyToOpenApp(); App.openApp(); - return waitForPromisesToResolve(); + return waitForBatchedUpdates(); }) .then(() => { // Then it should fail and reauthenticate the user adding the new authToken to the session @@ -99,7 +99,7 @@ describe('Session', () => { test('Push notifications are subscribed after signing in', () => TestHelper.signInWithTestUser() - .then(waitForPromisesToResolve) + .then(waitForBatchedUpdates) .then(() => expect(PushNotification.register).toBeCalled())); test('Push notifications are unsubscribed after signing out', () => diff --git a/tests/perf-test/SidebarLinks.perf-test.js b/tests/perf-test/SidebarLinks.perf-test.js index 4600f42bfd1d..87d2648f78dd 100644 --- a/tests/perf-test/SidebarLinks.perf-test.js +++ b/tests/perf-test/SidebarLinks.perf-test.js @@ -3,7 +3,7 @@ import Onyx from 'react-native-onyx'; import _ from 'underscore'; import * as LHNTestUtils from '../utils/LHNTestUtils'; import CONST from '../../src/CONST'; -import waitForPromisesToResolve from '../utils/waitForPromisesToResolve'; +import waitForBatchedUpdates from '../utils/waitForBatchedUpdates'; jest.mock('../../src/libs/Permissions'); jest.mock('../../src/components/Icon/Expensicons'); @@ -45,7 +45,7 @@ test('simple Sidebar render with hundred of reports', () => { }); const mockOnyxReports = _.assign({}, ...mockReports); - return waitForPromisesToResolve() + return waitForBatchedUpdates() .then(() => Onyx.multiSet({ [ONYXKEYS.NVP_PRIORITY_MODE]: CONST.PRIORITY_MODE.DEFAULT, diff --git a/tests/ui/UnreadIndicatorsTest.js b/tests/ui/UnreadIndicatorsTest.js index 1666ffb87400..6a64dda85b37 100644 --- a/tests/ui/UnreadIndicatorsTest.js +++ b/tests/ui/UnreadIndicatorsTest.js @@ -7,8 +7,8 @@ import moment from 'moment'; import App from '../../src/App'; import CONST from '../../src/CONST'; import ONYXKEYS from '../../src/ONYXKEYS'; -import waitForPromisesToResolve from '../utils/waitForPromisesToResolve'; -import waitForPromisesToResolveWithAct from '../utils/waitForPromisesToResolveWithAct'; +import waitForBatchedUpdates from '../utils/waitForBatchedUpdates'; +import waitForBatchedUpdatesWithAct from '../utils/waitForBatchedUpdatesWithAct'; import * as TestHelper from '../utils/TestHelper'; import appSetup from '../../src/setup'; import fontWeightBold from '../../src/styles/fontWeight/bold'; @@ -87,7 +87,7 @@ function navigateToSidebar() { const hintText = Localize.translateLocal('accessibilityHints.navigateToChatsList'); const reportHeaderBackButton = screen.queryByAccessibilityHint(hintText); fireEvent(reportHeaderBackButton, 'press'); - return waitForPromisesToResolve(); + return waitForBatchedUpdates(); } /** @@ -98,7 +98,7 @@ function navigateToSidebarOption(index) { const hintText = Localize.translateLocal('accessibilityHints.navigatesToChat'); const optionRows = screen.queryAllByAccessibilityHint(hintText); fireEvent(optionRows[index], 'press'); - return waitForPromisesToResolve(); + return waitForBatchedUpdates(); } /** @@ -129,7 +129,7 @@ let reportAction9CreatedDate; function signInAndGetAppWithUnreadChat() { // Render the App and sign in as a test user. render(); - return waitForPromisesToResolveWithAct() + return waitForBatchedUpdatesWithAct() .then(() => { const hintText = Localize.translateLocal('loginForm.loginForm'); const loginForm = screen.queryAllByLabelText(hintText); @@ -139,7 +139,7 @@ function signInAndGetAppWithUnreadChat() { }) .then(() => { User.subscribeToUserEvents(); - return waitForPromisesToResolve(); + return waitForBatchedUpdates(); }) .then(() => { const MOMENT_TEN_MINUTES_AGO = moment().subtract(10, 'minutes'); @@ -192,7 +192,7 @@ function signInAndGetAppWithUnreadChat() { // We manually setting the sidebar as loaded since the onLayout event does not fire in tests AppActions.setSidebarLoaded(true); - return waitForPromisesToResolve(); + return waitForBatchedUpdates(); }); } @@ -342,7 +342,7 @@ describe('Unread Indicators', () => { ], }, ]); - return waitForPromisesToResolve(); + return waitForBatchedUpdates(); }) .then(() => { // Verify notification was created @@ -388,7 +388,7 @@ describe('Unread Indicators', () => { // It's difficult to trigger marking a report comment as unread since we would have to mock the long press event and then // another press on the context menu item so we will do it via the action directly and then test if the UI has updated properly Report.markCommentAsUnread(REPORT_ID, reportAction3CreatedDate); - return waitForPromisesToResolve(); + return waitForBatchedUpdates(); }) .then(() => { // Verify the indicator appears above the last action @@ -454,7 +454,7 @@ describe('Unread Indicators', () => { // Leave a comment as the current user and verify the indicator is removed Report.addComment(REPORT_ID, 'Current User Comment 1'); - return waitForPromisesToResolve(); + return waitForBatchedUpdates(); }) .then(() => { const newMessageLineIndicatorHintText = Localize.translateLocal('accessibilityHints.newMessageLineIndicator'); @@ -487,7 +487,7 @@ describe('Unread Indicators', () => { // Mark a previous comment as unread and verify the unread action indicator returns Report.markCommentAsUnread(REPORT_ID, reportAction9CreatedDate); - return waitForPromisesToResolve(); + return waitForBatchedUpdates(); }) .then(() => { const newMessageLineIndicatorHintText = Localize.translateLocal('accessibilityHints.newMessageLineIndicator'); @@ -517,7 +517,7 @@ describe('Unread Indicators', () => { .then(() => { // Leave a comment as the current user Report.addComment(REPORT_ID, 'Current User Comment 1'); - return waitForPromisesToResolve(); + return waitForBatchedUpdates(); }) .then(() => { // Simulate the response from the server so that the comment can be deleted in this test @@ -528,7 +528,7 @@ describe('Unread Indicators', () => { lastActorAccountID: lastReportAction.actorAccountID, reportID: REPORT_ID, }); - return waitForPromisesToResolve(); + return waitForBatchedUpdates(); }) .then(() => { // Verify the chat preview text matches the last comment from the current user @@ -538,7 +538,7 @@ describe('Unread Indicators', () => { expect(alternateText[0].props.children).toBe('Current User Comment 1'); Report.deleteReportComment(REPORT_ID, lastReportAction); - return waitForPromisesToResolve(); + return waitForBatchedUpdates(); }) .then(() => { const hintText = Localize.translateLocal('accessibilityHints.lastChatMessagePreview'); diff --git a/tests/unit/APITest.js b/tests/unit/APITest.js index 9e936dfb7aa6..395f1438b666 100644 --- a/tests/unit/APITest.js +++ b/tests/unit/APITest.js @@ -3,7 +3,7 @@ import _ from 'underscore'; import * as TestHelper from '../utils/TestHelper'; import HttpUtils from '../../src/libs/HttpUtils'; -import waitForPromisesToResolve from '../utils/waitForPromisesToResolve'; +import waitForBatchedUpdates from '../utils/waitForBatchedUpdates'; import ONYXKEYS from '../../src/ONYXKEYS'; import CONST from '../../src/CONST'; import * as NetworkStore from '../../src/libs/Network/NetworkStore'; @@ -13,7 +13,7 @@ import * as API from '../../src/libs/API'; import * as SequentialQueue from '../../src/libs/Network/SequentialQueue'; import * as Request from '../../src/libs/Request'; import * as RequestThrottle from '../../src/libs/RequestThrottle'; -import fastForwardTwoMicrotasksCycles from '../utils/fastForwardTwoMicrotasksCycles'; +import waitForNetworkPromises from '../utils/waitForNetworkPromises'; jest.mock('../../src/libs/Log'); @@ -32,9 +32,9 @@ beforeEach(() => { NetworkStore.checkRequiredData(); // Wait for any Log command to finish and Onyx to fully clear - return waitForPromisesToResolve() + return waitForBatchedUpdates() .then(() => Onyx.clear()) - .then(waitForPromisesToResolve); + .then(waitForBatchedUpdates); }); afterEach(() => { @@ -57,7 +57,7 @@ describe('APITests', () => { API.write('mock command', {param1: 'value1'}); API.read('mock command', {param2: 'value2'}); API.write('mock command', {param3: 'value3'}); - return waitForPromisesToResolve(); + return waitForBatchedUpdates(); }) .then(() => { // Then `xhr` should only be called for the read (where it would not succeed in real life) and write requests should be persisted to storage @@ -70,7 +70,7 @@ describe('APITests', () => { ]); PersistedRequests.clear(); - return waitForPromisesToResolve(); + return waitForBatchedUpdates(); }) .then(() => { expect(PersistedRequests.getAll()).toEqual([]); @@ -92,7 +92,7 @@ describe('APITests', () => { // When API Write commands are made API.write('mock command', {param1: 'value1'}); API.write('mock command', {param2: 'value2'}); - return waitForPromisesToResolve(); + return waitForBatchedUpdates(); }) .then(() => { const persisted = PersistedRequests.getAll(); @@ -101,7 +101,7 @@ describe('APITests', () => { // When we resume connectivity .then(() => Onyx.set(ONYXKEYS.NETWORK, {isOffline: false})) - .then(waitForPromisesToResolve) + .then(waitForBatchedUpdates) .then(() => { expect(NetworkStore.isOffline()).toBe(false); expect(SequentialQueue.isRunning()).toBe(false); @@ -141,39 +141,39 @@ describe('APITests', () => { // When API Write commands are made API.write('mock command', {param1: 'value1'}); API.write('mock command', {param2: 'value2'}); - return waitForPromisesToResolve(); + return waitForBatchedUpdates(); }) // When we resume connectivity .then(() => Onyx.set(ONYXKEYS.NETWORK, {isOffline: false})) - .then(waitForPromisesToResolve) + .then(waitForBatchedUpdates) .then(() => { // Then requests should remain persisted until the xhr call is resolved expect(_.size(PersistedRequests.getAll())).toEqual(2); xhrCalls[0].resolve({jsonCode: CONST.JSON_CODE.SUCCESS}); - return waitForPromisesToResolve(); + return waitForBatchedUpdates(); }) - .then(waitForPromisesToResolve) + .then(waitForBatchedUpdates) .then(() => { expect(_.size(PersistedRequests.getAll())).toEqual(1); expect(PersistedRequests.getAll()).toEqual([expect.objectContaining({command: 'mock command', data: expect.objectContaining({param2: 'value2'})})]); // When a request fails it should be retried xhrCalls[1].reject(new Error(CONST.ERROR.FAILED_TO_FETCH)); - return waitForPromisesToResolve(); + return waitForBatchedUpdates(); }) .then(() => { expect(_.size(PersistedRequests.getAll())).toEqual(1); expect(PersistedRequests.getAll()).toEqual([expect.objectContaining({command: 'mock command', data: expect.objectContaining({param2: 'value2'})})]); // We need to advance past the request throttle back off timer because the request won't be retried until then - return new Promise((resolve) => setTimeout(resolve, CONST.NETWORK.MAX_RANDOM_RETRY_WAIT_TIME_MS)).then(waitForPromisesToResolve); + return new Promise((resolve) => setTimeout(resolve, CONST.NETWORK.MAX_RANDOM_RETRY_WAIT_TIME_MS)).then(waitForBatchedUpdates); }) .then(() => { // Finally, after it succeeds the queue should be empty xhrCalls[2].resolve({jsonCode: CONST.JSON_CODE.SUCCESS}); - return waitForPromisesToResolve(); + return waitForBatchedUpdates(); }) .then(() => { expect(_.size(PersistedRequests.getAll())).toEqual(0); @@ -203,12 +203,12 @@ describe('APITests', () => { .then(() => { // When API Write commands are made API.write('mock command', {param1: 'value1'}); - return fastForwardTwoMicrotasksCycles(); + return waitForNetworkPromises(); }) // When we resume connectivity .then(() => Onyx.set(ONYXKEYS.NETWORK, {isOffline: false})) - .then(waitForPromisesToResolve) + .then(waitForBatchedUpdates) .then(() => { // Then there has only been one request so far expect(global.fetch).toHaveBeenCalledTimes(1); @@ -229,7 +229,7 @@ describe('APITests', () => { expect(PersistedRequests.getAll()).toEqual([expect.objectContaining({command: 'mock command', data: expect.objectContaining({param1: 'value1'})})]); // We let the SequentialQueue process again after its wait time - return new Promise((resolve) => setTimeout(resolve, RequestThrottle.getLastRequestWaitTime())).then(waitForPromisesToResolve); + return new Promise((resolve) => setTimeout(resolve, RequestThrottle.getLastRequestWaitTime())).then(waitForBatchedUpdates); }) .then(() => { // Then the request is retried again @@ -281,16 +281,16 @@ describe('APITests', () => { // Given we have a request made while we're offline and we have credentials available to reauthenticate Onyx.merge(ONYXKEYS.CREDENTIALS, {autoGeneratedLogin: 'test', autoGeneratedPassword: 'passwd'}); return ( - waitForPromisesToResolve() + waitForBatchedUpdates() .then(() => Onyx.set(ONYXKEYS.NETWORK, {isOffline: true})) .then(() => { API.write('Mock', {param1: 'value1'}); - return waitForPromisesToResolve(); + return waitForBatchedUpdates(); }) // When we resume connectivity .then(() => Onyx.set(ONYXKEYS.NETWORK, {isOffline: false})) - .then(waitForPromisesToResolve) + .then(waitForBatchedUpdates) .then(() => { const nonLogCalls = _.filter(xhr.mock.calls, ([commandName]) => commandName !== 'Log'); @@ -325,10 +325,10 @@ describe('APITests', () => { API.write('MockCommand', {content: 'value5'}); API.write('MockCommand', {content: 'value6'}); - return waitForPromisesToResolve(); + return waitForBatchedUpdates(); }) .then(() => Onyx.set(ONYXKEYS.NETWORK, {isOffline: false})) - .then(waitForPromisesToResolve) + .then(waitForBatchedUpdates) .then(() => { // Then expect all 7 calls to have been made and for the Writes to be made in the order that we made them // The read command would have been made first (and would have failed in real-life) @@ -360,10 +360,10 @@ describe('APITests', () => { API.write('MockCommand', {content: 'value4'}); API.write('MockCommand', {content: 'value5'}); API.write('MockCommand', {content: 'value6'}); - return waitForPromisesToResolve(); + return waitForBatchedUpdates(); }) .then(() => Onyx.set(ONYXKEYS.NETWORK, {isOffline: false})) - .then(waitForPromisesToResolve) + .then(waitForBatchedUpdates) .then(() => { // Then expect only 8 calls to have been made total and for them to be made in the order that we made them despite requiring reauthentication expect(xhr.mock.calls.length).toBe(8); @@ -402,7 +402,7 @@ describe('APITests', () => { Onyx.set(ONYXKEYS.NETWORK, {isOffline: true}); expect(NetworkStore.isOffline()).toBe(false); expect(NetworkStore.isAuthenticating()).toBe(false); - return waitForPromisesToResolve(); + return waitForBatchedUpdates(); }) .then(() => { API.write('MockCommand'); @@ -414,7 +414,7 @@ describe('APITests', () => { // We should only have a single call at this point as the main queue is stopped since we've gone offline expect(xhr.mock.calls.length).toBe(1); - waitForPromisesToResolve(); + waitForBatchedUpdates(); // Come back from offline to trigger the sequential queue flush Onyx.set(ONYXKEYS.NETWORK, {isOffline: false}); @@ -422,7 +422,7 @@ describe('APITests', () => { .then(() => { // When we wait for the sequential queue to finish expect(SequentialQueue.isRunning()).toBe(true); - return waitForPromisesToResolve(); + return waitForBatchedUpdates(); }) .then(() => { // Then we should expect to see that... @@ -482,7 +482,7 @@ describe('APITests', () => { // When we go online and wait for promises to resolve return Onyx.set(ONYXKEYS.NETWORK, {isOffline: false}); }) - .then(waitForPromisesToResolve) + .then(waitForBatchedUpdates) .then(() => { expect(processWithMiddleware).toHaveBeenCalled(); @@ -495,7 +495,7 @@ describe('APITests', () => { [ONYXKEYS.SESSION]: {authToken: 'oldToken'}, }); }) - .then(waitForPromisesToResolve) + .then(waitForBatchedUpdates) .then(() => { // Then we should expect XHR to run expect(xhr).toHaveBeenCalled(); @@ -518,7 +518,7 @@ describe('APITests', () => { expect(PersistedRequests.getAll().length).toBe(2); // WHEN we wait for the queue to run and finish processing - return waitForPromisesToResolve(); + return waitForBatchedUpdates(); }) .then(() => { // THEN the queue should be stopped and there should be no more requests to run diff --git a/tests/unit/CurrencyUtilsTest.js b/tests/unit/CurrencyUtilsTest.js index 5058c56bfa00..ba61775f30da 100644 --- a/tests/unit/CurrencyUtilsTest.js +++ b/tests/unit/CurrencyUtilsTest.js @@ -2,7 +2,7 @@ import _ from 'underscore'; import Onyx from 'react-native-onyx'; import ONYXKEYS from '../../src/ONYXKEYS'; import CONST from '../../src/CONST'; -import waitForPromisesToResolve from '../utils/waitForPromisesToResolve'; +import waitForBatchedUpdates from '../utils/waitForBatchedUpdates'; import * as CurrencyUtils from '../../src/libs/CurrencyUtils'; import LocaleListener from '../../src/libs/Localize/LocaleListener'; @@ -30,7 +30,7 @@ describe('CurrencyUtils', () => { }, }); LocaleListener.connect(); - return waitForPromisesToResolve(); + return waitForBatchedUpdates(); }); afterEach(() => Onyx.clear()); diff --git a/tests/unit/DateUtilsTest.js b/tests/unit/DateUtilsTest.js index d17c1c052929..d8ea5e3b147a 100644 --- a/tests/unit/DateUtilsTest.js +++ b/tests/unit/DateUtilsTest.js @@ -4,7 +4,7 @@ import {addMinutes, subHours, subMinutes, subSeconds, format, setMinutes, setHou import CONST from '../../src/CONST'; import DateUtils from '../../src/libs/DateUtils'; import ONYXKEYS from '../../src/ONYXKEYS'; -import waitForPromisesToResolve from '../utils/waitForPromisesToResolve'; +import waitForBatchedUpdates from '../utils/waitForBatchedUpdates'; const LOCALE = CONST.LOCALES.EN; @@ -17,7 +17,7 @@ describe('DateUtils', () => { [ONYXKEYS.PERSONAL_DETAILS_LIST]: {999: {timezone: {selected: 'UTC'}}}, }, }); - return waitForPromisesToResolve(); + return waitForBatchedUpdates(); }); afterEach(() => { diff --git a/tests/unit/EmojiTest.js b/tests/unit/EmojiTest.js index 66f79ffb7fe4..2cc38648f0d9 100644 --- a/tests/unit/EmojiTest.js +++ b/tests/unit/EmojiTest.js @@ -6,7 +6,7 @@ import Emoji from '../../assets/emojis'; import * as EmojiUtils from '../../src/libs/EmojiUtils'; import ONYXKEYS from '../../src/ONYXKEYS'; import * as User from '../../src/libs/actions/User'; -import waitForPromisesToResolve from '../utils/waitForPromisesToResolve'; +import waitForBatchedUpdates from '../utils/waitForBatchedUpdates'; import * as TestHelper from '../utils/TestHelper'; import CONST from '../../src/CONST'; @@ -204,7 +204,7 @@ describe('EmojiTest', () => { ]; Onyx.merge(ONYXKEYS.FREQUENTLY_USED_EMOJIS, frequentlyEmojisList); - return waitForPromisesToResolve().then(() => { + return waitForBatchedUpdates().then(() => { // When add a new emoji const currentTime = moment().unix(); const smileEmoji = {code: '😄', name: 'smile'}; @@ -252,7 +252,7 @@ describe('EmojiTest', () => { ]; Onyx.merge(ONYXKEYS.FREQUENTLY_USED_EMOJIS, frequentlyEmojisList); - return waitForPromisesToResolve().then(() => { + return waitForBatchedUpdates().then(() => { // When add an emoji that exists in the list const currentTime = moment().unix(); const newEmoji = [smileEmoji]; @@ -294,7 +294,7 @@ describe('EmojiTest', () => { ]; Onyx.merge(ONYXKEYS.FREQUENTLY_USED_EMOJIS, frequentlyEmojisList); - return waitForPromisesToResolve().then(() => { + return waitForBatchedUpdates().then(() => { // When add multiple emojis that either exist or not exist in the list const currentTime = moment().unix(); const newEmoji = [smileEmoji, zzzEmoji, impEmoji]; @@ -465,7 +465,7 @@ describe('EmojiTest', () => { expect(frequentlyEmojisList.length).toBe(CONST.EMOJI_FREQUENT_ROW_COUNT * CONST.EMOJI_NUM_PER_ROW); Onyx.merge(ONYXKEYS.FREQUENTLY_USED_EMOJIS, frequentlyEmojisList); - return waitForPromisesToResolve().then(() => { + return waitForBatchedUpdates().then(() => { // When add new emojis const currentTime = moment().unix(); const newEmoji = [bookEmoji, smileEmoji, zzzEmoji, impEmoji, smileEmoji]; diff --git a/tests/unit/IOUUtilsTest.js b/tests/unit/IOUUtilsTest.js index 22790ebe721f..9ea30638af87 100644 --- a/tests/unit/IOUUtilsTest.js +++ b/tests/unit/IOUUtilsTest.js @@ -2,7 +2,7 @@ import Onyx from 'react-native-onyx'; import * as IOUUtils from '../../src/libs/IOUUtils'; import * as ReportUtils from '../../src/libs/ReportUtils'; import ONYXKEYS from '../../src/ONYXKEYS'; -import waitForPromisesToResolve from '../utils/waitForPromisesToResolve'; +import waitForBatchedUpdates from '../utils/waitForBatchedUpdates'; import currencyList from './currencyList.json'; import * as TransactionUtils from '../../src/libs/TransactionUtils'; @@ -13,7 +13,7 @@ function initCurrencyList() { [ONYXKEYS.CURRENCY_LIST]: currencyList, }, }); - return waitForPromisesToResolve(); + return waitForBatchedUpdates(); } describe('IOUUtils', () => { diff --git a/tests/unit/LocalePhoneNumberTest.js b/tests/unit/LocalePhoneNumberTest.js index e265cb7a35e6..1435e0819fa4 100644 --- a/tests/unit/LocalePhoneNumberTest.js +++ b/tests/unit/LocalePhoneNumberTest.js @@ -1,7 +1,7 @@ import Onyx from 'react-native-onyx'; import ONYXKEYS from '../../src/ONYXKEYS'; import * as LocalePhoneNumber from '../../src/libs/LocalePhoneNumber'; -import waitForPromisesToResolve from '../utils/waitForPromisesToResolve'; +import waitForBatchedUpdates from '../utils/waitForBatchedUpdates'; const ES_NUMBER = '+34702474537'; const US_NUMBER = '+18332403627'; @@ -20,7 +20,7 @@ describe('LocalePhoneNumber utils', () => { Onyx.multiSet({ [ONYXKEYS.SESSION]: {email: 'current@user.com'}, [ONYXKEYS.COUNTRY_CODE]: 1, - }).then(waitForPromisesToResolve), + }).then(waitForBatchedUpdates), ); afterEach(() => Onyx.clear()); diff --git a/tests/unit/LocalizeTests.js b/tests/unit/LocalizeTests.js index eebc3d13ab7b..921cf158a47c 100644 --- a/tests/unit/LocalizeTests.js +++ b/tests/unit/LocalizeTests.js @@ -1,5 +1,5 @@ import Onyx from 'react-native-onyx'; -import waitForPromisesToResolve from '../utils/waitForPromisesToResolve'; +import waitForBatchedUpdates from '../utils/waitForBatchedUpdates'; import CONST from '../../src/CONST'; import ONYXKEYS from '../../src/ONYXKEYS'; import * as Localize from '../../src/libs/Localize'; @@ -10,7 +10,7 @@ describe('localize', () => { keys: {NVP_PREFERRED_LOCALE: ONYXKEYS.NVP_PREFERRED_LOCALE}, initialKeyStates: {[ONYXKEYS.NVP_PREFERRED_LOCALE]: CONST.LOCALES.DEFAULT}, }); - return waitForPromisesToResolve(); + return waitForBatchedUpdates(); }); afterEach(() => Onyx.clear()); diff --git a/tests/unit/MigrationTest.js b/tests/unit/MigrationTest.js index 0171ee640226..39280e71cc84 100644 --- a/tests/unit/MigrationTest.js +++ b/tests/unit/MigrationTest.js @@ -1,6 +1,6 @@ import Onyx from 'react-native-onyx'; import _ from 'underscore'; -import waitForPromisesToResolve from '../utils/waitForPromisesToResolve'; +import waitForBatchedUpdates from '../utils/waitForBatchedUpdates'; import CONST from '../../src/CONST'; import Log from '../../src/libs/Log'; import getPlatform from '../../src/libs/getPlatform'; @@ -20,13 +20,13 @@ describe('Migrations', () => { Onyx.init({keys: ONYXKEYS}); LogSpy = jest.spyOn(Log, 'info'); Log.serverLoggingCallback = () => {}; - return waitForPromisesToResolve(); + return waitForBatchedUpdates(); }); beforeEach(() => { jest.clearAllMocks(); Onyx.clear(); - return waitForPromisesToResolve(); + return waitForBatchedUpdates(); }); describe('MoveToIndexedDb', () => { diff --git a/tests/unit/NetworkTest.js b/tests/unit/NetworkTest.js index 805b05f098ae..bd45ae3c2187 100644 --- a/tests/unit/NetworkTest.js +++ b/tests/unit/NetworkTest.js @@ -3,7 +3,7 @@ import Onyx from 'react-native-onyx'; import * as TestHelper from '../utils/TestHelper'; import HttpUtils from '../../src/libs/HttpUtils'; -import waitForPromisesToResolve from '../utils/waitForPromisesToResolve'; +import waitForBatchedUpdates from '../utils/waitForBatchedUpdates'; import ONYXKEYS from '../../src/ONYXKEYS'; import CONST from '../../src/CONST'; import * as Network from '../../src/libs/Network'; @@ -33,10 +33,10 @@ beforeEach(() => { NetworkStore.checkRequiredData(); // Wait for any Log command to finish and Onyx to fully clear - return waitForPromisesToResolve() + return waitForBatchedUpdates() .then(() => PersistedRequests.clear()) .then(() => Onyx.clear()) - .then(waitForPromisesToResolve); + .then(waitForBatchedUpdates); }); afterEach(() => { @@ -104,14 +104,14 @@ describe('NetworkTests', () => { // This should first trigger re-authentication and then a Failed to fetch App.confirmReadyToOpenApp(); App.openApp(); - return waitForPromisesToResolve() + return waitForBatchedUpdates() .then(() => Onyx.set(ONYXKEYS.NETWORK, {isOffline: false})) .then(() => { expect(isOffline).toBe(false); // Advance the network request queue by 1 second so that it can realize it's back online jest.advanceTimersByTime(CONST.NETWORK.PROCESS_REQUEST_DELAY_MS); - return waitForPromisesToResolve(); + return waitForBatchedUpdates(); }) .then(() => { // Then we will eventually have 3 calls to chatList and 2 calls to Authenticate @@ -172,7 +172,7 @@ describe('NetworkTests', () => { App.openApp(); App.openApp(); App.openApp(); - return waitForPromisesToResolve(); + return waitForBatchedUpdates(); }) .then(() => { // We should expect to see the three calls to OpenApp, but only one call to Authenticate. @@ -212,7 +212,7 @@ describe('NetworkTests', () => { // Once credentials are set and we wait for promises to resolve Onyx.merge(ONYXKEYS.CREDENTIALS, {login: 'test-login'}); Onyx.merge(ONYXKEYS.SESSION, {authToken: 'test-auth-token'}); - return waitForPromisesToResolve().then(() => { + return waitForBatchedUpdates().then(() => { // Then we should expect the request to have been made since the network is now ready expect(spyHttpUtilsXhr).not.toHaveBeenCalled(); }); @@ -228,16 +228,16 @@ describe('NetworkTests', () => { // Given a non-retryable request (that is bound to fail) const promise = Network.post('Get'); - return waitForPromisesToResolve() + return waitForBatchedUpdates() .then(() => { // When network connection is recovered Onyx.merge(ONYXKEYS.NETWORK, {isOffline: false}); - return waitForPromisesToResolve(); + return waitForBatchedUpdates(); }) .then(() => { // Advance the network request queue by 1 second so that it can realize it's back online jest.advanceTimersByTime(CONST.NETWORK.PROCESS_REQUEST_DELAY_MS); - return waitForPromisesToResolve(); + return waitForBatchedUpdates(); }) .then(() => { // Then the request should only have been attempted once and we should get an unable to retry @@ -257,7 +257,7 @@ describe('NetworkTests', () => { return Onyx.set(ONYXKEYS.NETWORK, {isOffline: false}) .then(() => { Network.post('MockBadNetworkResponse', {param1: 'value1'}); - return waitForPromisesToResolve(); + return waitForBatchedUpdates(); }) .then(() => { expect(logHmmmSpy).toHaveBeenCalled(); @@ -273,7 +273,7 @@ describe('NetworkTests', () => { return Onyx.set(ONYXKEYS.NETWORK, {isOffline: false}) .then(() => { Network.post('MockBadNetworkResponse', {param1: 'value1'}); - return waitForPromisesToResolve(); + return waitForBatchedUpdates(); }) .then(() => { expect(logAlertSpy).toHaveBeenCalled(); @@ -292,7 +292,7 @@ describe('NetworkTests', () => { // When network calls with are made Network.post('mock command', {param1: 'value1'}).then(onResolved); - return waitForPromisesToResolve(); + return waitForBatchedUpdates(); }) .then(() => { const response = onResolved.mock.calls[0][0]; @@ -315,7 +315,7 @@ describe('NetworkTests', () => { Network.post('MockCommandThree'); // WHEN we wait for the requests to all cancel - return waitForPromisesToResolve(); + return waitForBatchedUpdates(); }) .then(() => { // THEN expect our queue to be empty and for no requests to have been retried diff --git a/tests/unit/OptionsListUtilsTest.js b/tests/unit/OptionsListUtilsTest.js index 7dc47619ffed..a6fd100803d4 100644 --- a/tests/unit/OptionsListUtilsTest.js +++ b/tests/unit/OptionsListUtilsTest.js @@ -3,7 +3,7 @@ import Onyx from 'react-native-onyx'; import * as OptionsListUtils from '../../src/libs/OptionsListUtils'; import * as ReportUtils from '../../src/libs/ReportUtils'; import ONYXKEYS from '../../src/ONYXKEYS'; -import waitForPromisesToResolve from '../utils/waitForPromisesToResolve'; +import waitForBatchedUpdates from '../utils/waitForBatchedUpdates'; import CONST from '../../src/CONST'; describe('OptionsListUtils', () => { @@ -280,7 +280,7 @@ describe('OptionsListUtils', () => { }, }); Onyx.registerLogger(() => {}); - return waitForPromisesToResolve().then(() => Onyx.set(ONYXKEYS.PERSONAL_DETAILS_LIST, PERSONAL_DETAILS)); + return waitForBatchedUpdates().then(() => Onyx.set(ONYXKEYS.PERSONAL_DETAILS_LIST, PERSONAL_DETAILS)); }); it('getSearchOptions()', () => { @@ -308,7 +308,7 @@ describe('OptionsListUtils', () => { expect(results.recentReports[0].text).toBe('Mister Fantastic'); expect(results.recentReports[1].text).toBe('Mister Fantastic'); - return waitForPromisesToResolve() + return waitForBatchedUpdates() .then(() => Onyx.set(ONYXKEYS.PERSONAL_DETAILS_LIST, PERSONAL_DETAILS_WITH_PERIODS)) .then(() => { // When we filter again but provide a searchValue that should match with periods diff --git a/tests/unit/ReportUtilsTest.js b/tests/unit/ReportUtilsTest.js index e97e9147c328..eeef96bf2102 100644 --- a/tests/unit/ReportUtilsTest.js +++ b/tests/unit/ReportUtilsTest.js @@ -3,7 +3,7 @@ import _ from 'underscore'; import CONST from '../../src/CONST'; import ONYXKEYS from '../../src/ONYXKEYS'; import * as ReportUtils from '../../src/libs/ReportUtils'; -import waitForPromisesToResolve from '../utils/waitForPromisesToResolve'; +import waitForBatchedUpdates from '../utils/waitForBatchedUpdates'; import * as LHNTestUtils from '../utils/LHNTestUtils'; // Be sure to include the mocked permissions library or else the beta tests won't work @@ -51,9 +51,9 @@ describe('ReportUtils', () => { [ONYXKEYS.COUNTRY_CODE]: 1, [`${ONYXKEYS.COLLECTION.POLICY}${policy.policyID}`]: policy, }); - return waitForPromisesToResolve(); + return waitForBatchedUpdates(); }); - beforeEach(() => Onyx.set(ONYXKEYS.NVP_PREFERRED_LOCALE, CONST.LOCALES.DEFAULT).then(waitForPromisesToResolve)); + beforeEach(() => Onyx.set(ONYXKEYS.NVP_PREFERRED_LOCALE, CONST.LOCALES.DEFAULT).then(waitForBatchedUpdates)); describe('getDisplayNamesWithTooltips', () => { test('withSingleParticipantReport', () => { diff --git a/tests/unit/RequestTest.js b/tests/unit/RequestTest.js index 07943732030d..fb1032e70cfe 100644 --- a/tests/unit/RequestTest.js +++ b/tests/unit/RequestTest.js @@ -1,5 +1,5 @@ import * as Request from '../../src/libs/Request'; -import waitForPromisesToResolve from '../utils/waitForPromisesToResolve'; +import waitForBatchedUpdates from '../utils/waitForBatchedUpdates'; import * as TestHelper from '../utils/TestHelper'; beforeAll(() => { @@ -19,7 +19,7 @@ test('Request.use() can register a middleware and it will run', () => { }; Request.processWithMiddleware(request, true); - return waitForPromisesToResolve().then(() => { + return waitForBatchedUpdates().then(() => { const [promise, returnedRequest, isFromSequentialQueue] = testMiddleware.mock.calls[0]; expect(testMiddleware).toHaveBeenCalled(); expect(returnedRequest).toEqual(request); @@ -57,7 +57,7 @@ test('Request.use() can register two middlewares. They can pass a response to th const catchHandler = jest.fn(); Request.processWithMiddleware(request).catch(catchHandler); - return waitForPromisesToResolve().then(() => { + return waitForBatchedUpdates().then(() => { expect(catchHandler).toHaveBeenCalled(); expect(catchHandler).toHaveBeenCalledWith(new Error('Oops')); }); diff --git a/tests/unit/SidebarFilterTest.js b/tests/unit/SidebarFilterTest.js index 37fae51e48c9..18e499d89293 100644 --- a/tests/unit/SidebarFilterTest.js +++ b/tests/unit/SidebarFilterTest.js @@ -2,8 +2,8 @@ import {cleanup, screen} from '@testing-library/react-native'; import Onyx from 'react-native-onyx'; import lodashGet from 'lodash/get'; import * as LHNTestUtils from '../utils/LHNTestUtils'; -import waitForPromisesToResolve from '../utils/waitForPromisesToResolve'; -import wrapOnyxWithWaitForPromisesToResolve from '../utils/wrapOnyxWithWaitForPromisesToResolve'; +import waitForBatchedUpdates from '../utils/waitForBatchedUpdates'; +import wrapOnyxWithWaitForBatchedUpdates from '../utils/wrapOnyxWithWaitForBatchedUpdates'; import CONST from '../../src/CONST'; import DateUtils from '../../src/libs/DateUtils'; import * as Localize from '../../src/libs/Localize'; @@ -35,8 +35,8 @@ describe('Sidebar', () => { ); beforeEach(() => { - // Wrap Onyx each onyx action with waitForPromiseToResolve - wrapOnyxWithWaitForPromisesToResolve(Onyx); + // Wrap Onyx each onyx action with waitForBatchedUpdates + wrapOnyxWithWaitForBatchedUpdates(Onyx); // Initialize the network key for OfflineWithFeedback return Onyx.merge(ONYXKEYS.NETWORK, {isOffline: false}); }); @@ -55,7 +55,7 @@ describe('Sidebar', () => { const report = LHNTestUtils.getFakeReport([]); return ( - waitForPromisesToResolve() + waitForBatchedUpdates() // When Onyx is updated to contain that report .then(() => Onyx.multiSet({ @@ -79,7 +79,7 @@ describe('Sidebar', () => { const report = LHNTestUtils.getFakeReport(['emptychat+1@test.com', 'emptychat+2@test.com'], 0); return ( - waitForPromisesToResolve() + waitForBatchedUpdates() // When Onyx is updated to contain that report .then(() => Onyx.multiSet({ @@ -107,7 +107,7 @@ describe('Sidebar', () => { }; return ( - waitForPromisesToResolve() + waitForBatchedUpdates() // When Onyx is updated to contain that report .then(() => Onyx.multiSet({ @@ -137,7 +137,7 @@ describe('Sidebar', () => { }; return ( - waitForPromisesToResolve() + waitForBatchedUpdates() // When Onyx is updated to contain that data and the sidebar re-renders .then(() => Onyx.multiSet({ @@ -190,7 +190,7 @@ describe('Sidebar', () => { }; return ( - waitForPromisesToResolve() + waitForBatchedUpdates() // When Onyx is updated to contain that data and the sidebar re-renders .then(() => Onyx.multiSet({ @@ -242,7 +242,7 @@ describe('Sidebar', () => { }; return ( - waitForPromisesToResolve() + waitForBatchedUpdates() // When Onyx is updated to contain that data and the sidebar re-renders .then(() => Onyx.multiSet({ @@ -330,7 +330,7 @@ describe('Sidebar', () => { LHNTestUtils.getDefaultRenderedSidebarLinks(report1.reportID); return ( - waitForPromisesToResolve() + waitForBatchedUpdates() // When Onyx is updated to contain that data and the sidebar re-renders .then(() => Onyx.multiSet({ @@ -375,7 +375,7 @@ describe('Sidebar', () => { LHNTestUtils.getDefaultRenderedSidebarLinks(report1.reportID); return ( - waitForPromisesToResolve() + waitForBatchedUpdates() // When Onyx is updated to contain that data and the sidebar re-renders .then(() => Onyx.multiSet({ @@ -421,7 +421,7 @@ describe('Sidebar', () => { // When report 2 becomes the active report .then(() => { LHNTestUtils.getDefaultRenderedSidebarLinks(report2.reportID); - return waitForPromisesToResolve(); + return waitForBatchedUpdates(); }) // Then report 1 should now disappear @@ -446,7 +446,7 @@ describe('Sidebar', () => { LHNTestUtils.getDefaultRenderedSidebarLinks(draftReport.reportID); return ( - waitForPromisesToResolve() + waitForBatchedUpdates() // When Onyx is updated to contain that data and the sidebar re-renders .then(() => Onyx.multiSet({ @@ -493,7 +493,7 @@ describe('Sidebar', () => { const betas = [CONST.BETAS.DEFAULT_ROOMS, CONST.BETAS.POLICY_ROOMS]; return ( - waitForPromisesToResolve() + waitForBatchedUpdates() // When Onyx is updated to contain that data and the sidebar re-renders .then(() => Onyx.multiSet({ @@ -556,7 +556,7 @@ describe('Sidebar', () => { const betas = [CONST.BETAS.DEFAULT_ROOMS, CONST.BETAS.POLICY_ROOMS]; return ( - waitForPromisesToResolve() + waitForBatchedUpdates() // When Onyx is updated to contain that data and the sidebar re-renders .then(() => Onyx.multiSet({ @@ -655,7 +655,7 @@ describe('Sidebar', () => { LHNTestUtils.getDefaultRenderedSidebarLinks(report1.reportID); return ( - waitForPromisesToResolve() + waitForBatchedUpdates() // When Onyx is updated to contain that data and the sidebar re-renders .then(() => Onyx.multiSet({ @@ -707,7 +707,7 @@ describe('Sidebar', () => { const betas = [CONST.BETAS.DEFAULT_ROOMS, CONST.BETAS.POLICY_ROOMS]; return ( - waitForPromisesToResolve() + waitForBatchedUpdates() // When Onyx is updated to contain that data and the sidebar re-renders .then(() => Onyx.multiSet({ @@ -758,7 +758,7 @@ describe('Sidebar', () => { const betas = [CONST.BETAS.DEFAULT_ROOMS, CONST.BETAS.POLICY_ROOMS]; return ( - waitForPromisesToResolve() + waitForBatchedUpdates() // When Onyx is updated to contain that data and the sidebar re-renders .then(() => Onyx.multiSet({ @@ -807,7 +807,7 @@ describe('Sidebar', () => { const betas = [CONST.BETAS.DEFAULT_ROOMS, CONST.BETAS.POLICY_ROOMS]; return ( - waitForPromisesToResolve() + waitForBatchedUpdates() // When Onyx is updated to contain that data and the sidebar re-renders .then(() => Onyx.multiSet({ @@ -852,7 +852,7 @@ describe('Sidebar', () => { const betas = [CONST.BETAS.DEFAULT_ROOMS, CONST.BETAS.POLICY_ROOMS]; return ( - waitForPromisesToResolve() + waitForBatchedUpdates() // When Onyx is updated to contain that data and the sidebar re-renders .then(() => Onyx.multiSet({ @@ -874,7 +874,7 @@ describe('Sidebar', () => { // When sidebar is rendered with the active report ID matching the archived report in Onyx .then(() => { LHNTestUtils.getDefaultRenderedSidebarLinks(report.reportID); - return waitForPromisesToResolve(); + return waitForBatchedUpdates(); }) // Then the report is rendered in the LHN diff --git a/tests/unit/SidebarOrderTest.js b/tests/unit/SidebarOrderTest.js index c3942f24e626..4a693d679b86 100644 --- a/tests/unit/SidebarOrderTest.js +++ b/tests/unit/SidebarOrderTest.js @@ -1,8 +1,8 @@ import Onyx from 'react-native-onyx'; import {cleanup, screen} from '@testing-library/react-native'; import lodashGet from 'lodash/get'; -import waitForPromisesToResolve from '../utils/waitForPromisesToResolve'; -import wrapOnyxWithWaitForPromisesToResolve from '../utils/wrapOnyxWithWaitForPromisesToResolve'; +import waitForBatchedUpdates from '../utils/waitForBatchedUpdates'; +import wrapOnyxWithWaitForBatchedUpdates from '../utils/wrapOnyxWithWaitForBatchedUpdates'; import * as LHNTestUtils from '../utils/LHNTestUtils'; import CONST from '../../src/CONST'; import DateUtils from '../../src/libs/DateUtils'; @@ -36,8 +36,8 @@ describe('Sidebar', () => { ); beforeEach(() => { - // Wrap Onyx each onyx action with waitForPromiseToResolve - wrapOnyxWithWaitForPromisesToResolve(Onyx); + // Wrap Onyx each onyx action with waitForBatchedUpdates + wrapOnyxWithWaitForBatchedUpdates(Onyx); // Initialize the network key for OfflineWithFeedback return Onyx.merge(ONYXKEYS.NETWORK, {isOffline: false}); }); @@ -64,7 +64,7 @@ describe('Sidebar', () => { LHNTestUtils.getDefaultRenderedSidebarLinks(); return ( - waitForPromisesToResolve() + waitForBatchedUpdates() // When Onyx is updated with some personal details .then(() => Onyx.multiSet({ @@ -88,7 +88,7 @@ describe('Sidebar', () => { LHNTestUtils.getDefaultRenderedSidebarLinks(report.reportID); return ( - waitForPromisesToResolve() + waitForBatchedUpdates() // When Onyx is updated with the data and the sidebar re-renders .then(() => Onyx.multiSet({ @@ -120,7 +120,7 @@ describe('Sidebar', () => { Report.addComment(report3.reportID, 'Hi, this is a comment'); return ( - waitForPromisesToResolve() + waitForBatchedUpdates() // When Onyx is updated with the data and the sidebar re-renders .then(() => Onyx.multiSet({ @@ -166,7 +166,7 @@ describe('Sidebar', () => { LHNTestUtils.getDefaultRenderedSidebarLinks(currentReportId); return ( - waitForPromisesToResolve() + waitForBatchedUpdates() // When Onyx is updated with the data and the sidebar re-renders .then(() => Onyx.multiSet({ @@ -209,7 +209,7 @@ describe('Sidebar', () => { Report.addComment(report3.reportID, 'Hi, this is a comment'); return ( - waitForPromisesToResolve() + waitForBatchedUpdates() // When Onyx is updated with the data and the sidebar re-renders .then(() => Onyx.multiSet({ @@ -262,7 +262,7 @@ describe('Sidebar', () => { LHNTestUtils.getDefaultRenderedSidebarLinks(currentReportId); return ( - waitForPromisesToResolve() + waitForBatchedUpdates() // When Onyx is updated with the data and the sidebar re-renders .then(() => Onyx.multiSet({ @@ -280,7 +280,7 @@ describe('Sidebar', () => { // The changing of a route itself will re-render the component in the App, but since we are not performing this test // inside the navigator and it has no access to the routes we need to trigger an update to the SidebarLinks manually. LHNTestUtils.getDefaultRenderedSidebarLinks('1'); - return waitForPromisesToResolve(); + return waitForBatchedUpdates(); }) // Then the order of the reports should be 2 > 3 > 1 @@ -307,7 +307,7 @@ describe('Sidebar', () => { }; return ( - waitForPromisesToResolve() + waitForBatchedUpdates() // When Onyx is updated with the data and the sidebar re-renders .then(() => Onyx.multiSet({ @@ -344,7 +344,7 @@ describe('Sidebar', () => { }; return ( - waitForPromisesToResolve() + waitForBatchedUpdates() // When Onyx is updated with the data and the sidebar re-renders .then(() => Onyx.multiSet({ @@ -406,7 +406,7 @@ describe('Sidebar', () => { LHNTestUtils.getDefaultRenderedSidebarLinks(currentReportId); return ( - waitForPromisesToResolve() + waitForBatchedUpdates() // When Onyx is updated with the data and the sidebar re-renders .then(() => Onyx.multiSet({ @@ -458,7 +458,7 @@ describe('Sidebar', () => { }; LHNTestUtils.getDefaultRenderedSidebarLinks('0'); return ( - waitForPromisesToResolve() + waitForBatchedUpdates() // When Onyx is updated with the data and the sidebar re-renders .then(() => Onyx.multiSet({ @@ -518,7 +518,7 @@ describe('Sidebar', () => { }; LHNTestUtils.getDefaultRenderedSidebarLinks('0'); return ( - waitForPromisesToResolve() + waitForBatchedUpdates() // When Onyx is updated with the data and the sidebar re-renders .then(() => Onyx.multiSet({ @@ -577,7 +577,7 @@ describe('Sidebar', () => { const betas = [CONST.BETAS.DEFAULT_ROOMS, CONST.BETAS.POLICY_ROOMS]; LHNTestUtils.getDefaultRenderedSidebarLinks('0'); return ( - waitForPromisesToResolve() + waitForBatchedUpdates() // When Onyx is updated with the data and the sidebar re-renders .then(() => Onyx.multiSet({ @@ -614,7 +614,7 @@ describe('Sidebar', () => { const report4 = LHNTestUtils.getFakeReport([7, 8], 0, true); return ( - waitForPromisesToResolve() + waitForBatchedUpdates() // Given the sidebar is rendered in #focus mode (hides read chats) // with all reports having unread comments .then(() => @@ -669,7 +669,7 @@ describe('Sidebar', () => { const betas = [CONST.BETAS.DEFAULT_ROOMS, CONST.BETAS.POLICY_ROOMS]; LHNTestUtils.getDefaultRenderedSidebarLinks('0'); return ( - waitForPromisesToResolve() + waitForBatchedUpdates() // When Onyx is updated with the data and the sidebar re-renders .then(() => Onyx.multiSet({ @@ -788,7 +788,7 @@ describe('Sidebar', () => { const currentlyLoggedInUserAccountID = 13; LHNTestUtils.getDefaultRenderedSidebarLinks('0'); return ( - waitForPromisesToResolve() + waitForBatchedUpdates() // When Onyx is updated with the data and the sidebar re-renders .then(() => Onyx.multiSet({ @@ -846,7 +846,7 @@ describe('Sidebar', () => { LHNTestUtils.getDefaultRenderedSidebarLinks('0'); return ( - waitForPromisesToResolve() + waitForBatchedUpdates() // When Onyx is updated with the data and the sidebar re-renders .then(() => Onyx.multiSet({ diff --git a/tests/unit/SidebarTest.js b/tests/unit/SidebarTest.js index 84403ce5fc11..1b5daa323da5 100644 --- a/tests/unit/SidebarTest.js +++ b/tests/unit/SidebarTest.js @@ -1,8 +1,8 @@ import Onyx from 'react-native-onyx'; import {cleanup, screen} from '@testing-library/react-native'; import lodashGet from 'lodash/get'; -import waitForPromisesToResolve from '../utils/waitForPromisesToResolve'; -import wrapOnyxWithWaitForPromisesToResolve from '../utils/wrapOnyxWithWaitForPromisesToResolve'; +import waitForBatchedUpdates from '../utils/waitForBatchedUpdates'; +import wrapOnyxWithWaitForBatchedUpdates from '../utils/wrapOnyxWithWaitForBatchedUpdates'; import * as LHNTestUtils from '../utils/LHNTestUtils'; import CONST from '../../src/CONST'; import * as Localize from '../../src/libs/Localize'; @@ -34,8 +34,8 @@ describe('Sidebar', () => { ); beforeEach(() => { - // Wrap Onyx each onyx action with waitForPromiseToResolve - wrapOnyxWithWaitForPromisesToResolve(Onyx); + // Wrap Onyx each onyx action with waitForBatchedUpdates + wrapOnyxWithWaitForBatchedUpdates(Onyx); // Initialize the network key for OfflineWithFeedback return Onyx.merge(ONYXKEYS.NETWORK, {isOffline: false}); }); @@ -59,7 +59,7 @@ describe('Sidebar', () => { const betas = [CONST.BETAS.DEFAULT_ROOMS, CONST.BETAS.POLICY_ROOMS]; LHNTestUtils.getDefaultRenderedSidebarLinks('0'); return ( - waitForPromisesToResolve() + waitForBatchedUpdates() // When Onyx is updated with the data and the sidebar re-renders .then(() => Onyx.multiSet({ @@ -102,7 +102,7 @@ describe('Sidebar', () => { const betas = [CONST.BETAS.DEFAULT_ROOMS, CONST.BETAS.POLICY_ROOMS]; LHNTestUtils.getDefaultRenderedSidebarLinks('0'); return ( - waitForPromisesToResolve() + waitForBatchedUpdates() // When Onyx is updated with the data and the sidebar re-renders .then(() => Onyx.multiSet({ diff --git a/tests/unit/enhanceParametersTest.js b/tests/unit/enhanceParametersTest.js index 8dc625ba6d23..fb2ccc86ad79 100644 --- a/tests/unit/enhanceParametersTest.js +++ b/tests/unit/enhanceParametersTest.js @@ -1,7 +1,7 @@ import Onyx from 'react-native-onyx'; import ONYXKEYS from '../../src/ONYXKEYS'; import enhanceParameters from '../../src/libs/Network/enhanceParameters'; -import waitForPromisesToResolve from '../utils/waitForPromisesToResolve'; +import waitForBatchedUpdates from '../utils/waitForBatchedUpdates'; import CONFIG from '../../src/CONFIG'; beforeEach(() => Onyx.clear()); @@ -12,7 +12,7 @@ test('Enhance parameters adds correct parameters for Log command with no authTok const email = 'test-user@test.com'; const authToken = 'test-token'; Onyx.merge(ONYXKEYS.SESSION, {email, authToken}); - return waitForPromisesToResolve().then(() => { + return waitForBatchedUpdates().then(() => { const finalParameters = enhanceParameters(command, parameters); expect(finalParameters).toEqual({ testParameter: 'test', @@ -30,7 +30,7 @@ test('Enhance parameters adds correct parameters for a command that requires aut const email = 'test-user@test.com'; const authToken = 'test-token'; Onyx.merge(ONYXKEYS.SESSION, {email, authToken}); - return waitForPromisesToResolve().then(() => { + return waitForBatchedUpdates().then(() => { const finalParameters = enhanceParameters(command, parameters); expect(finalParameters).toEqual({ testParameter: 'test', diff --git a/tests/utils/TestHelper.js b/tests/utils/TestHelper.js index a8424d14ed33..1d5a82c0df4c 100644 --- a/tests/utils/TestHelper.js +++ b/tests/utils/TestHelper.js @@ -5,7 +5,7 @@ import CONST from '../../src/CONST'; import * as Session from '../../src/libs/actions/Session'; import HttpUtils from '../../src/libs/HttpUtils'; import ONYXKEYS from '../../src/ONYXKEYS'; -import waitForPromisesToResolve from './waitForPromisesToResolve'; +import waitForBatchedUpdates from './waitForBatchedUpdates'; import * as NumberUtils from '../../src/libs/NumberUtils'; /** @@ -73,7 +73,7 @@ function signInWithTestUser(accountID = 1, login = 'test@user.com', password = ' // Simulate user entering their login and populating the credentials.login Session.beginSignIn(login); - return waitForPromisesToResolve() + return waitForBatchedUpdates() .then(() => { // Response is the same for calls to Authenticate and BeginSignIn HttpUtils.xhr.mockResolvedValue({ @@ -117,7 +117,7 @@ function signInWithTestUser(accountID = 1, login = 'test@user.com', password = ' jsonCode: 200, }); Session.signIn(password); - return waitForPromisesToResolve(); + return waitForBatchedUpdates(); }) .then(() => { HttpUtils.xhr = originalXhr; @@ -129,7 +129,7 @@ function signOutTestUser() { HttpUtils.xhr = jest.fn(); HttpUtils.xhr.mockResolvedValue({jsonCode: 200}); Session.signOutAndRedirectToSignIn(); - return waitForPromisesToResolve().then(() => (HttpUtils.xhr = originalXhr)); + return waitForBatchedUpdates().then(() => (HttpUtils.xhr = originalXhr)); } /** @@ -175,7 +175,7 @@ function getGlobalFetchMock() { mockFetch.resume = () => { isPaused = false; _.each(queue, (resolve) => resolve(getResponse())); - return waitForPromisesToResolve(); + return waitForBatchedUpdates(); }; mockFetch.fail = () => (shouldFail = true); mockFetch.succeed = () => (shouldFail = false); @@ -192,7 +192,7 @@ function setPersonalDetails(login, accountID) { Onyx.merge(ONYXKEYS.PERSONAL_DETAILS_LIST, { [accountID]: buildPersonalDetails(login, accountID), }); - return waitForPromisesToResolve(); + return waitForBatchedUpdates(); } /** diff --git a/tests/utils/waitForPromisesToResolve.js b/tests/utils/waitForBatchedUpdates.js similarity index 93% rename from tests/utils/waitForPromisesToResolve.js rename to tests/utils/waitForBatchedUpdates.js index f42ac73477bd..2c4dbec250bc 100644 --- a/tests/utils/waitForPromisesToResolve.js +++ b/tests/utils/waitForBatchedUpdates.js @@ -8,7 +8,7 @@ import getIsUsingFakeTimers from './getIsUsingFakeTimers'; * ✅ Onyx.merge(...).then(...) * than to do * ❌ Onyx.merge(...) - * waitForPromisesToResolve().then(...) + * waitForBatchedUpdates().then(...) * * @returns {Promise} */ @@ -20,7 +20,7 @@ export default () => // E.g. this makes the following code work for tests: // // Onyx.merge(...) - // return waitForPromiseToResolve().then(...); + // return waitForBatchedUpdates().then(...); // // Note: Ideally, you'd just await the Onyx.merge promise. diff --git a/tests/utils/waitForPromisesToResolveWithAct.js b/tests/utils/waitForBatchedUpdatesWithAct.js similarity index 84% rename from tests/utils/waitForPromisesToResolveWithAct.js rename to tests/utils/waitForBatchedUpdatesWithAct.js index eaef0f3b1a9d..125cf74159b3 100644 --- a/tests/utils/waitForPromisesToResolveWithAct.js +++ b/tests/utils/waitForBatchedUpdatesWithAct.js @@ -1,5 +1,5 @@ import {act} from '@testing-library/react-native'; -import waitForPromisesToResolve from './waitForPromisesToResolve'; +import waitForBatchedUpdates from './waitForBatchedUpdates'; /** * This method is necessary because react-navigation's NavigationContainer makes an internal state update when parsing the @@ -18,16 +18,16 @@ import waitForPromisesToResolve from './waitForPromisesToResolve'; * * When not to use this: * - * - You're not rendering any react components at all in your tests, but have some async logic you need to wait for e.g. Onyx.merge(). Use waitForPromisesToResolve(). - * - You're writing UI tests but don't see any errors or warnings related to using act(). You probably don't need this in that case and should use waitForPromisesToResolve(). + * - You're not rendering any react components at all in your tests, but have some async logic you need to wait for e.g. Onyx.merge(). Use waitForBatchedUpdates(). + * - You're writing UI tests but don't see any errors or warnings related to using act(). You probably don't need this in that case and should use waitForBatchedUpdates(). * - You're writing UI test and do see a warning about using act(), but there's no asynchronous code that needs to run inside act(). * * @returns {Promise} */ // eslint-disable-next-line @lwc/lwc/no-async-await -export default async function waitForPromisesToResolveWithAct() { +export default async function waitForBatchedUpdatesWithAct() { // eslint-disable-next-line @lwc/lwc/no-async-await await act(async () => { - await waitForPromisesToResolve(); + await waitForBatchedUpdates(); }); } diff --git a/tests/utils/fastForwardTwoMicrotasksCycles.js b/tests/utils/waitForNetworkPromises.js similarity index 66% rename from tests/utils/fastForwardTwoMicrotasksCycles.js rename to tests/utils/waitForNetworkPromises.js index 4a9cbce41887..1289c520d679 100644 --- a/tests/utils/fastForwardTwoMicrotasksCycles.js +++ b/tests/utils/waitForNetworkPromises.js @@ -1,4 +1,4 @@ -import waitForPromisesToResolve from './waitForPromisesToResolve'; +import waitForBatchedUpdates from './waitForBatchedUpdates'; /** * Method flushes microtasks and pending timers twice. Because we batch onyx updates @@ -7,8 +7,8 @@ import waitForPromisesToResolve from './waitForPromisesToResolve'; * ✅ Onyx.merge(...).then(...) * than to do * ❌ Onyx.merge(...) - * waitForPromisesToResolve().then(...) + * waitForBatchedUpdates().then(...) * * @returns {Promise} */ -export default () => waitForPromisesToResolve().then(waitForPromisesToResolve); +export default () => waitForBatchedUpdates().then(waitForBatchedUpdates); diff --git a/tests/utils/wrapOnyxWithWaitForPromisesToResolve.js b/tests/utils/wrapOnyxWithWaitForBatchedUpdates.js similarity index 73% rename from tests/utils/wrapOnyxWithWaitForPromisesToResolve.js rename to tests/utils/wrapOnyxWithWaitForBatchedUpdates.js index c560c50538bd..e5b6e6bfdfcf 100644 --- a/tests/utils/wrapOnyxWithWaitForPromisesToResolve.js +++ b/tests/utils/wrapOnyxWithWaitForBatchedUpdates.js @@ -1,4 +1,4 @@ -import waitForPromisesToResolve from './waitForPromisesToResolve'; +import waitForBatchedUpdates from './waitForBatchedUpdates'; /** * When we change data in onyx, the listeners (components) will be notified @@ -10,11 +10,11 @@ import waitForPromisesToResolve from './waitForPromisesToResolve'; * * @param {Object} onyxInstance */ -export default function wrapOnyxWithWaitForPromisesToResolve(onyxInstance) { +export default function wrapOnyxWithWaitForBatchedUpdates(onyxInstance) { const multiSetImpl = onyxInstance.multiSet; // eslint-disable-next-line no-param-reassign - onyxInstance.multiSet = (...args) => multiSetImpl(...args).then((result) => waitForPromisesToResolve().then(() => result)); + onyxInstance.multiSet = (...args) => multiSetImpl(...args).then((result) => waitForBatchedUpdates().then(() => result)); const mergeImpl = onyxInstance.merge; // eslint-disable-next-line no-param-reassign - onyxInstance.merge = (...args) => mergeImpl(...args).then((result) => waitForPromisesToResolve().then(() => result)); + onyxInstance.merge = (...args) => mergeImpl(...args).then((result) => waitForBatchedUpdates().then(() => result)); } From 58f4bf5f180efe024718c14daa38d35a960841f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szymon=20Kapa=C5=82a?= Date: Thu, 14 Sep 2023 22:07:00 +0200 Subject: [PATCH 20/23] cleanup --- tests/utils/waitForNetworkPromises.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/utils/waitForNetworkPromises.js b/tests/utils/waitForNetworkPromises.js index 1289c520d679..a60061d597e3 100644 --- a/tests/utils/waitForNetworkPromises.js +++ b/tests/utils/waitForNetworkPromises.js @@ -2,7 +2,7 @@ import waitForBatchedUpdates from './waitForBatchedUpdates'; /** * Method flushes microtasks and pending timers twice. Because we batch onyx updates - * Some operations like for instance network requests takes 2 microtask cycles to resolve + * Network requests takes 2 microtask cycles to resolve * **Note:** It is recommended to wait for the Onyx operations, so in your tests its preferred to do: * ✅ Onyx.merge(...).then(...) * than to do From dd5e6aa12376c374e3eb157102fdefad8bc6f8fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szymon=20Kapa=C5=82a?= Date: Fri, 15 Sep 2023 09:55:52 +0200 Subject: [PATCH 21/23] bump onyx version --- package-lock.json | 28 ++++++++++++++++------------ package.json | 4 ++-- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1ae63b31fd0c..93708aeec601 100644 --- a/package-lock.json +++ b/package-lock.json @@ -85,10 +85,10 @@ "react-native-linear-gradient": "^2.8.1", "react-native-localize": "^2.2.6", "react-native-modal": "^13.0.0", - "react-native-onyx": "1.0.72", + "react-native-onyx": "1.0.78", "react-native-pager-view": "^6.2.0", "react-native-pdf": "^6.7.1", - "react-native-performance": "^4.0.0", + "react-native-performance": "^5.1.0", "react-native-permissions": "^3.0.1", "react-native-picker-select": "git+https://github.com/Expensify/react-native-picker-select.git#eae05855286dc699954415cc1d629bfd8e8e47e2", "react-native-plaid-link-sdk": "^10.0.0", @@ -40311,9 +40311,9 @@ } }, "node_modules/react-native-onyx": { - "version": "1.0.72", - "resolved": "https://registry.npmjs.org/react-native-onyx/-/react-native-onyx-1.0.72.tgz", - "integrity": "sha512-roJuA92qZH2PLYSqBhSPCse+Ra2EJu4FBpVqguwJRp6oaLNHR1CtPTgU1xMh/kj2nWmdpcqKoOc3nS35asb80g==", + "version": "1.0.78", + "resolved": "https://registry.npmjs.org/react-native-onyx/-/react-native-onyx-1.0.78.tgz", + "integrity": "sha512-SxXr0AvFyXiZ4HYW4wBJA5YQgQzU4bSpLZ9ZvFhJ7Usmf65wYrVrmrJvQnMSeWJnMdyfoVGO1rLhoZHDwgqDIw==", "dependencies": { "ascii-table": "0.0.9", "fast-equals": "^4.0.3", @@ -40326,8 +40326,9 @@ "peerDependencies": { "idb-keyval": "^6.2.1", "react": ">=18.1.0", + "react-dom": ">=18.1.0", "react-native-device-info": "^10.3.0", - "react-native-performance": "^4.0.0", + "react-native-performance": "^5.1.0", "react-native-quick-sqlite": "^8.0.0-beta.2" }, "peerDependenciesMeta": { @@ -40369,8 +40370,9 @@ } }, "node_modules/react-native-performance": { - "version": "4.0.0", - "license": "MIT", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/react-native-performance/-/react-native-performance-5.1.0.tgz", + "integrity": "sha512-rq/YBf0/GptSOM/Lj64/1yRq8uN2YE0psFB16wFbYBbTcIEp/0rrgN2HyS5lhvfBOFgKoDRWQ53jHSCb+QJ5eA==", "peerDependencies": { "react-native": "*" } @@ -75636,9 +75638,9 @@ } }, "react-native-onyx": { - "version": "1.0.72", - "resolved": "https://registry.npmjs.org/react-native-onyx/-/react-native-onyx-1.0.72.tgz", - "integrity": "sha512-roJuA92qZH2PLYSqBhSPCse+Ra2EJu4FBpVqguwJRp6oaLNHR1CtPTgU1xMh/kj2nWmdpcqKoOc3nS35asb80g==", + "version": "1.0.78", + "resolved": "https://registry.npmjs.org/react-native-onyx/-/react-native-onyx-1.0.78.tgz", + "integrity": "sha512-SxXr0AvFyXiZ4HYW4wBJA5YQgQzU4bSpLZ9ZvFhJ7Usmf65wYrVrmrJvQnMSeWJnMdyfoVGO1rLhoZHDwgqDIw==", "requires": { "ascii-table": "0.0.9", "fast-equals": "^4.0.3", @@ -75661,7 +75663,9 @@ } }, "react-native-performance": { - "version": "4.0.0", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/react-native-performance/-/react-native-performance-5.1.0.tgz", + "integrity": "sha512-rq/YBf0/GptSOM/Lj64/1yRq8uN2YE0psFB16wFbYBbTcIEp/0rrgN2HyS5lhvfBOFgKoDRWQ53jHSCb+QJ5eA==", "requires": {} }, "react-native-performance-flipper-reporter": { diff --git a/package.json b/package.json index 340a1c8d0880..cf56770ea89c 100644 --- a/package.json +++ b/package.json @@ -125,10 +125,10 @@ "react-native-linear-gradient": "^2.8.1", "react-native-localize": "^2.2.6", "react-native-modal": "^13.0.0", - "react-native-onyx": "1.0.72", + "react-native-onyx": "1.0.78", "react-native-pager-view": "^6.2.0", "react-native-pdf": "^6.7.1", - "react-native-performance": "^4.0.0", + "react-native-performance": "^5.1.0", "react-native-permissions": "^3.0.1", "react-native-picker-select": "git+https://github.com/Expensify/react-native-picker-select.git#eae05855286dc699954415cc1d629bfd8e8e47e2", "react-native-plaid-link-sdk": "^10.0.0", From 225ffe1656607de6eadbc829ae4e9bfb12009c78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szymon=20Kapa=C5=82a?= Date: Tue, 19 Sep 2023 10:32:29 +0200 Subject: [PATCH 22/23] Update src/libs/actions/PersistedRequests.js Co-authored-by: Marc Glasser --- src/libs/actions/PersistedRequests.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/actions/PersistedRequests.js b/src/libs/actions/PersistedRequests.js index e7cbfc18efcd..46df9a410da8 100644 --- a/src/libs/actions/PersistedRequests.js +++ b/src/libs/actions/PersistedRequests.js @@ -11,7 +11,7 @@ Onyx.connect({ /** * This promise is only used by tests. DO NOT USE THIS PROMISE IN THE APPLICATION CODE - * @returns {void} + * @returns {Promise} */ function clear() { return Onyx.set(ONYXKEYS.PERSISTED_REQUESTS, []); From 7869c5abac5c1a9396286b05dcdf8e7c2229ac32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szymon=20Kapa=C5=82a?= Date: Wed, 20 Sep 2023 09:43:52 +0200 Subject: [PATCH 23/23] fix: return types are not allowe isssue --- src/libs/actions/PersistedRequests.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libs/actions/PersistedRequests.ts b/src/libs/actions/PersistedRequests.ts index e1579a850953..040c7d3d87a8 100644 --- a/src/libs/actions/PersistedRequests.ts +++ b/src/libs/actions/PersistedRequests.ts @@ -12,7 +12,6 @@ Onyx.connect({ /** * This promise is only used by tests. DO NOT USE THIS PROMISE IN THE APPLICATION CODE - * @returns {Promise} */ function clear() { return Onyx.set(ONYXKEYS.PERSISTED_REQUESTS, []);