diff --git a/src/libs/actions/App.ts b/src/libs/actions/App.ts index d69bcf0e5761..71cb5f97e00e 100644 --- a/src/libs/actions/App.ts +++ b/src/libs/actions/App.ts @@ -27,6 +27,7 @@ import type {OnyxData} from '@src/types/onyx/Request'; import {setShouldForceOffline} from './Network'; import * as PersistedRequests from './PersistedRequests'; import * as Policy from './Policy/Policy'; +import resolveDuplicationConflictAction from './RequestConflictUtils'; import * as Session from './Session'; import Timing from './Timing'; @@ -255,7 +256,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), + }); }); } @@ -284,23 +287,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..68c0860389b9 --- /dev/null +++ b/src/libs/actions/RequestConflictUtils.ts @@ -0,0 +1,30 @@ +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) { + return { + conflictAction: { + type: 'push', + }, + }; + } + + return { + conflictAction: { + type: 'replace', + index, + }, + }; +} + +export default resolveDuplicationConflictAction; diff --git a/tests/actions/SessionTest.ts b/tests/actions/SessionTest.ts index 51dc775da359..0f23cef757da 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('OpenApp 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..d2d003192456 --- /dev/null +++ b/tests/unit/RequestConflictUtilsTest.ts @@ -0,0 +1,21 @@ +import resolveDuplicationConflictAction from '@libs/actions/RequestConflictUtils'; +import type {WriteCommand} from '@libs/API/types'; + +describe('RequestConflictUtils', () => { + 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); + 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}}); + }); +});