From ee7f37f69e5a6f01e6e9db54af24508820c68f0f Mon Sep 17 00:00:00 2001 From: Edu Date: Fri, 4 Oct 2024 16:37:58 +0200 Subject: [PATCH 1/5] conflict resolution for OpenApp --- src/libs/actions/App.ts | 23 ++++----------- src/libs/actions/RequestConflictUtils.ts | 24 +++++++++++++++ tests/actions/SessionTest.ts | 37 ++++++++++++++++++++++++ tests/unit/RequestConflictUtilsTest.ts | 24 +++++++++++++++ 4 files changed, 90 insertions(+), 18 deletions(-) create mode 100644 src/libs/actions/RequestConflictUtils.ts create mode 100644 tests/unit/RequestConflictUtilsTest.ts diff --git a/src/libs/actions/App.ts b/src/libs/actions/App.ts index 8a66a9702acb..b8c6550c5bd7 100644 --- a/src/libs/actions/App.ts +++ b/src/libs/actions/App.ts @@ -6,6 +6,7 @@ import type {OnyxCollection, OnyxEntry, OnyxUpdate} from 'react-native-onyx'; import Onyx from 'react-native-onyx'; import type {ValueOf} from 'type-fest'; import {importEmojiLocale} from '@assets/emojis'; +import {resolveDuplicationConflictAction} from '@libs/actions/RequestConflictUtils'; import * as API from '@libs/API'; import type {GetMissingOnyxMessagesParams, HandleRestrictedEventParams, OpenAppParams, OpenOldDotLinkParams, ReconnectAppParams, UpdatePreferredLocaleParams} from '@libs/API/parameters'; import {SIDE_EFFECT_REQUEST_COMMANDS, WRITE_COMMANDS} from '@libs/API/types'; @@ -245,7 +246,9 @@ function getOnyxDataForOpenOrReconnect(isOpenApp = false): OnyxData { function openApp() { return getPolicyParamsForOpenOrReconnect().then((policyParams: PolicyParamsForOpenOrReconnect) => { const params: OpenAppParams = {enablePriorityModeFilter: true, ...policyParams}; - return API.write(WRITE_COMMANDS.OPEN_APP, params, getOnyxDataForOpenOrReconnect(true)); + return API.write(WRITE_COMMANDS.OPEN_APP, params, getOnyxDataForOpenOrReconnect(true), { + checkAndFixConflictingRequest: (persistedRequests) => resolveDuplicationConflictAction(persistedRequests, WRITE_COMMANDS.OPEN_APP), + }); }); } @@ -274,23 +277,7 @@ function reconnectApp(updateIDFrom: OnyxEntry = 0) { } API.write(WRITE_COMMANDS.RECONNECT_APP, params, getOnyxDataForOpenOrReconnect(), { - checkAndFixConflictingRequest: (persistedRequests) => { - const index = persistedRequests.findIndex((request) => request.command === WRITE_COMMANDS.RECONNECT_APP); - if (index === -1) { - return { - conflictAction: { - type: 'push', - }, - }; - } - - return { - conflictAction: { - type: 'replace', - index, - }, - }; - }, + checkAndFixConflictingRequest: (persistedRequests) => resolveDuplicationConflictAction(persistedRequests, WRITE_COMMANDS.RECONNECT_APP), }); }); } diff --git a/src/libs/actions/RequestConflictUtils.ts b/src/libs/actions/RequestConflictUtils.ts new file mode 100644 index 000000000000..158efead61bf --- /dev/null +++ b/src/libs/actions/RequestConflictUtils.ts @@ -0,0 +1,24 @@ +import type {WriteCommand} from '@libs/API/types'; +import type OnyxRequest from '@src/types/onyx/Request'; +import type {ConflictActionData} from '@src/types/onyx/Request'; + +function resolveDuplicationConflictAction(persistedRequests: OnyxRequest[], commandToFind: WriteCommand): ConflictActionData { + console.log('resolveDuplicationConflictAction -> ', commandToFind); + const index = persistedRequests.findIndex((request) => request.command === commandToFind); + if (index === -1) { + return { + conflictAction: { + type: 'push', + }, + }; + } + + return { + conflictAction: { + type: 'replace', + index, + }, + }; +} + +export {resolveDuplicationConflictAction}; diff --git a/tests/actions/SessionTest.ts b/tests/actions/SessionTest.ts index 51dc775da359..ac2d6a3454ca 100644 --- a/tests/actions/SessionTest.ts +++ b/tests/actions/SessionTest.ts @@ -146,4 +146,41 @@ describe('Session', () => { expect(PersistedRequests.getAll().length).toBe(0); }); + + test('OpenApp should push request to the queue', async () => { + await TestHelper.signInWithTestUser(); + await Onyx.set(ONYXKEYS.NETWORK, {isOffline: true}); + + App.openApp(); + + await waitForBatchedUpdates(); + + expect(PersistedRequests.getAll().length).toBe(1); + expect(PersistedRequests.getAll().at(0)?.command).toBe(WRITE_COMMANDS.OPEN_APP); + + await Onyx.set(ONYXKEYS.NETWORK, {isOffline: false}); + + await waitForBatchedUpdates(); + + expect(PersistedRequests.getAll().length).toBe(0); + }); + + test('ReconnectApp should replace same requests from the queue', async () => { + await TestHelper.signInWithTestUser(); + await Onyx.set(ONYXKEYS.NETWORK, {isOffline: true}); + + App.openApp(); + App.openApp(); + App.openApp(); + App.openApp(); + + await waitForBatchedUpdates(); + + expect(PersistedRequests.getAll().length).toBe(1); + expect(PersistedRequests.getAll().at(0)?.command).toBe(WRITE_COMMANDS.OPEN_APP); + + await Onyx.set(ONYXKEYS.NETWORK, {isOffline: false}); + + expect(PersistedRequests.getAll().length).toBe(0); + }); }); diff --git a/tests/unit/RequestConflictUtilsTest.ts b/tests/unit/RequestConflictUtilsTest.ts new file mode 100644 index 000000000000..97d81eec221f --- /dev/null +++ b/tests/unit/RequestConflictUtilsTest.ts @@ -0,0 +1,24 @@ +import {resolveDuplicationConflictAction} from '@libs/actions/RequestConflictUtils'; +import type {WriteCommand} from '@libs/API/types'; + +describe('RequestConflictUtils', () => { + it.each([ + ['OpenApp', 0], + ['ReconnectApp', 0], + ])('resolveDuplicationConflictAction when %s do not exist in the queue should push %i', (command, index) => { + const persistedRequests = [{command: 'OpenReport'}, {command: 'AddComment'}, {command: 'CloseAccount'}]; + const commandToFind = command as WriteCommand; + const result = resolveDuplicationConflictAction(persistedRequests, commandToFind); + expect(result).toEqual({conflictAction: {type: 'push'}}); + }); + + it.each([ + ['OpenApp', 0], + ['ReconnectApp', 2], + ])('resolveDuplicationConflictAction when %s exist in the queue should replace at index %i', (command, index) => { + const persistedRequests = [{command: 'OpenApp'}, {command: 'AddComment'}, {command: 'ReconnectApp'}]; + const commandToFind = command as WriteCommand; + const result = resolveDuplicationConflictAction(persistedRequests, commandToFind); + expect(result).toEqual({conflictAction: {type: 'replace', index}}); + }); +}); From 6a9cc0175b9855ce27ce396920e65df0adafae62 Mon Sep 17 00:00:00 2001 From: Edu Date: Mon, 7 Oct 2024 10:08:42 +0200 Subject: [PATCH 2/5] fixed eslint issues --- src/libs/actions/App.ts | 2 +- src/libs/actions/RequestConflictUtils.ts | 3 +-- tests/unit/RequestConflictUtilsTest.ts | 7 ++----- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/libs/actions/App.ts b/src/libs/actions/App.ts index b8c6550c5bd7..6eca8143c077 100644 --- a/src/libs/actions/App.ts +++ b/src/libs/actions/App.ts @@ -6,7 +6,7 @@ import type {OnyxCollection, OnyxEntry, OnyxUpdate} from 'react-native-onyx'; import Onyx from 'react-native-onyx'; import type {ValueOf} from 'type-fest'; import {importEmojiLocale} from '@assets/emojis'; -import {resolveDuplicationConflictAction} from '@libs/actions/RequestConflictUtils'; +import resolveDuplicationConflictAction from '@libs/actions/RequestConflictUtils'; import * as API from '@libs/API'; import type {GetMissingOnyxMessagesParams, HandleRestrictedEventParams, OpenAppParams, OpenOldDotLinkParams, ReconnectAppParams, UpdatePreferredLocaleParams} from '@libs/API/parameters'; import {SIDE_EFFECT_REQUEST_COMMANDS, WRITE_COMMANDS} from '@libs/API/types'; diff --git a/src/libs/actions/RequestConflictUtils.ts b/src/libs/actions/RequestConflictUtils.ts index 158efead61bf..5f34dd40d6bb 100644 --- a/src/libs/actions/RequestConflictUtils.ts +++ b/src/libs/actions/RequestConflictUtils.ts @@ -3,7 +3,6 @@ import type OnyxRequest from '@src/types/onyx/Request'; import type {ConflictActionData} from '@src/types/onyx/Request'; function resolveDuplicationConflictAction(persistedRequests: OnyxRequest[], commandToFind: WriteCommand): ConflictActionData { - console.log('resolveDuplicationConflictAction -> ', commandToFind); const index = persistedRequests.findIndex((request) => request.command === commandToFind); if (index === -1) { return { @@ -21,4 +20,4 @@ function resolveDuplicationConflictAction(persistedRequests: OnyxRequest[], comm }; } -export {resolveDuplicationConflictAction}; +export default resolveDuplicationConflictAction; diff --git a/tests/unit/RequestConflictUtilsTest.ts b/tests/unit/RequestConflictUtilsTest.ts index 97d81eec221f..d2d003192456 100644 --- a/tests/unit/RequestConflictUtilsTest.ts +++ b/tests/unit/RequestConflictUtilsTest.ts @@ -1,11 +1,8 @@ -import {resolveDuplicationConflictAction} from '@libs/actions/RequestConflictUtils'; +import resolveDuplicationConflictAction from '@libs/actions/RequestConflictUtils'; import type {WriteCommand} from '@libs/API/types'; describe('RequestConflictUtils', () => { - it.each([ - ['OpenApp', 0], - ['ReconnectApp', 0], - ])('resolveDuplicationConflictAction when %s do not exist in the queue should push %i', (command, index) => { + it.each([['OpenApp'], ['ReconnectApp']])('resolveDuplicationConflictAction when %s do not exist in the queue should push %i', (command) => { const persistedRequests = [{command: 'OpenReport'}, {command: 'AddComment'}, {command: 'CloseAccount'}]; const commandToFind = command as WriteCommand; const result = resolveDuplicationConflictAction(persistedRequests, commandToFind); From ebfa4832422c530aa510ca92a854b547178f77a6 Mon Sep 17 00:00:00 2001 From: Edu Date: Mon, 7 Oct 2024 10:17:01 +0200 Subject: [PATCH 3/5] fixed import path --- src/libs/actions/App.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/actions/App.ts b/src/libs/actions/App.ts index 6eca8143c077..41c1c1e17a6c 100644 --- a/src/libs/actions/App.ts +++ b/src/libs/actions/App.ts @@ -6,7 +6,6 @@ import type {OnyxCollection, OnyxEntry, OnyxUpdate} from 'react-native-onyx'; import Onyx from 'react-native-onyx'; import type {ValueOf} from 'type-fest'; import {importEmojiLocale} from '@assets/emojis'; -import resolveDuplicationConflictAction from '@libs/actions/RequestConflictUtils'; import * as API from '@libs/API'; import type {GetMissingOnyxMessagesParams, HandleRestrictedEventParams, OpenAppParams, OpenOldDotLinkParams, ReconnectAppParams, UpdatePreferredLocaleParams} from '@libs/API/parameters'; import {SIDE_EFFECT_REQUEST_COMMANDS, WRITE_COMMANDS} from '@libs/API/types'; @@ -26,6 +25,7 @@ import ROUTES from '@src/ROUTES'; import type * as OnyxTypes from '@src/types/onyx'; import type {OnyxData} from '@src/types/onyx/Request'; import * as Policy from './Policy/Policy'; +import resolveDuplicationConflictAction from './RequestConflictUtils'; import * as Session from './Session'; import Timing from './Timing'; From 6c119dc82fb4c05c07a1a092d9805bb3abb076ec Mon Sep 17 00:00:00 2001 From: Edu Date: Mon, 7 Oct 2024 16:33:09 +0200 Subject: [PATCH 4/5] Fixed comments --- src/libs/actions/RequestConflictUtils.ts | 7 +++++++ tests/actions/SessionTest.ts | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/libs/actions/RequestConflictUtils.ts b/src/libs/actions/RequestConflictUtils.ts index 5f34dd40d6bb..406114baacb3 100644 --- a/src/libs/actions/RequestConflictUtils.ts +++ b/src/libs/actions/RequestConflictUtils.ts @@ -2,6 +2,13 @@ import type {WriteCommand} from '@libs/API/types'; import type OnyxRequest from '@src/types/onyx/Request'; import type {ConflictActionData} from '@src/types/onyx/Request'; +/** + * Resolves duplication conflicts between persisted requests and a given command. + * + * This method checks if a specific command exists within a list of persisted requests. + * - If the command is not found, it suggests adding the command to the list, indicating a 'push' action. + * - If the command is found, it suggests updating the existing entry, indicating a 'replace' action at the found index. + **/ function resolveDuplicationConflictAction(persistedRequests: OnyxRequest[], commandToFind: WriteCommand): ConflictActionData { const index = persistedRequests.findIndex((request) => request.command === commandToFind); if (index === -1) { diff --git a/tests/actions/SessionTest.ts b/tests/actions/SessionTest.ts index ac2d6a3454ca..0f23cef757da 100644 --- a/tests/actions/SessionTest.ts +++ b/tests/actions/SessionTest.ts @@ -165,7 +165,7 @@ describe('Session', () => { expect(PersistedRequests.getAll().length).toBe(0); }); - test('ReconnectApp should replace same requests from the queue', async () => { + test('OpenApp should replace same requests from the queue', async () => { await TestHelper.signInWithTestUser(); await Onyx.set(ONYXKEYS.NETWORK, {isOffline: true}); From 4fd3707b65380083b7b14518a97f52cc990ee054 Mon Sep 17 00:00:00 2001 From: Edu Date: Mon, 7 Oct 2024 17:48:16 +0200 Subject: [PATCH 5/5] fixed lint error --- src/libs/actions/RequestConflictUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/actions/RequestConflictUtils.ts b/src/libs/actions/RequestConflictUtils.ts index 406114baacb3..68c0860389b9 100644 --- a/src/libs/actions/RequestConflictUtils.ts +++ b/src/libs/actions/RequestConflictUtils.ts @@ -8,7 +8,7 @@ import type {ConflictActionData} from '@src/types/onyx/Request'; * This method checks if a specific command exists within a list of persisted requests. * - If the command is not found, it suggests adding the command to the list, indicating a 'push' action. * - If the command is found, it suggests updating the existing entry, indicating a 'replace' action at the found index. - **/ + */ function resolveDuplicationConflictAction(persistedRequests: OnyxRequest[], commandToFind: WriteCommand): ConflictActionData { const index = persistedRequests.findIndex((request) => request.command === commandToFind); if (index === -1) {