Skip to content

Commit

Permalink
Merge pull request #43056 from Expensify/arosiclair-push-notif-onyx-u…
Browse files Browse the repository at this point in the history
…pdates

Fix applying onyx updates from push notifications
  • Loading branch information
aldo-expensify authored Jun 17, 2024
2 parents af0eea1 + 45243f8 commit eb59c33
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ function applyOnyxData({reportID, reportActionID, onyxData, lastUpdateID, previo
previousUpdateID,
updates: [
{
eventType: 'eventType',
eventType: '', // This is only needed for Pusher events
data: onyxData,
},
],
Expand Down
1 change: 1 addition & 0 deletions src/libs/PusherUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ function subscribeToMultiEvent(eventType: string, callback: Callback) {

function triggerMultiEventHandler(eventType: string, data: OnyxUpdate[]): Promise<void> {
if (!multiEventCallbackMapping[eventType]) {
Log.warn('[PusherUtils] Received unexpected multi-event', {eventType});
return Promise.resolve();
}
return multiEventCallbackMapping[eventType](data);
Expand Down
21 changes: 20 additions & 1 deletion src/libs/actions/OnyxUpdates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ Onyx.connect({
// even when such events are received over multiple separate pusher updates.
let pusherEventsPromise = Promise.resolve();

let airshipEventsPromise = Promise.resolve();

function applyHTTPSOnyxUpdates(request: Request, response: Response) {
console.debug('[OnyxUpdateManager] Applying https update');
// For most requests we can immediately update Onyx. For write requests we queue the updates and apply them after the sequential queue has flushed to prevent a replay effect in
Expand Down Expand Up @@ -71,6 +73,20 @@ function applyPusherOnyxUpdates(updates: OnyxUpdateEvent[]) {
return pusherEventsPromise;
}

function applyAirshipOnyxUpdates(updates: OnyxUpdateEvent[]) {
airshipEventsPromise = airshipEventsPromise.then(() => {
console.debug('[OnyxUpdateManager] Applying Airship updates');
});

airshipEventsPromise = updates
.reduce((promise, update) => promise.then(() => Onyx.update(update.data)), airshipEventsPromise)
.then(() => {
console.debug('[OnyxUpdateManager] Done applying Airship updates');
});

return airshipEventsPromise;
}

/**
* @param [updateParams.request] Exists if updateParams.type === 'https'
* @param [updateParams.response] Exists if updateParams.type === 'https'
Expand Down Expand Up @@ -108,9 +124,12 @@ function apply({lastUpdateID, type, request, response, updates}: OnyxUpdatesFrom
if (type === CONST.ONYX_UPDATE_TYPES.HTTPS && request && response) {
return applyHTTPSOnyxUpdates(request, response);
}
if ((type === CONST.ONYX_UPDATE_TYPES.PUSHER || type === CONST.ONYX_UPDATE_TYPES.AIRSHIP) && updates) {
if (type === CONST.ONYX_UPDATE_TYPES.PUSHER && updates) {
return applyPusherOnyxUpdates(updates);
}
if (type === CONST.ONYX_UPDATE_TYPES.AIRSHIP && updates) {
return applyAirshipOnyxUpdates(updates);
}
}

/**
Expand Down
79 changes: 79 additions & 0 deletions tests/unit/OnyxUpdatesTest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import type {KeyValueMapping, OnyxEntry, OnyxKey} from 'react-native-onyx';
import Onyx from 'react-native-onyx';
import CONST from '@src/CONST';
import * as OnyxUpdates from '@src/libs/actions/OnyxUpdates';
import DateUtils from '@src/libs/DateUtils';
import * as NumberUtils from '@src/libs/NumberUtils';
import ONYXKEYS from '@src/ONYXKEYS';
import type {OnyxUpdatesFromServer} from '@src/types/onyx';
import waitForBatchedUpdates from '../utils/waitForBatchedUpdates';

describe('OnyxUpdatesTest', () => {
beforeAll(() => {
Onyx.init({
keys: ONYXKEYS,
});
});

beforeEach(() => Onyx.clear().then(waitForBatchedUpdates));

it('applies Airship Onyx updates correctly', () => {
const reportID = NumberUtils.rand64();
const reportActionID = NumberUtils.rand64();
const created = DateUtils.getDBTime();

const reportValue = {reportID};
const reportActionValue = {
[reportActionID]: {
reportActionID,
created,
},
};

// Given an onyx update from an Airship push notification
const airshipUpdates: OnyxUpdatesFromServer = {
type: CONST.ONYX_UPDATE_TYPES.AIRSHIP,
previousUpdateID: 0,
lastUpdateID: 1,
updates: [
{
eventType: '',
data: [
{
onyxMethod: 'merge',
key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`,
value: reportValue,
},
{
onyxMethod: 'merge',
key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`,
value: reportActionValue,
shouldShowPushNotification: true,
},
],
},
],
};

// When we apply the updates, then their values are updated correctly
return OnyxUpdates.apply(airshipUpdates)
.then(() => getOnyxValues(`${ONYXKEYS.COLLECTION.REPORT}${reportID}`, `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`))
.then(([report, reportAction]) => {
expect(report).toStrictEqual(reportValue);
expect(reportAction).toStrictEqual(reportActionValue);
});
});
});

function getOnyxValues<TKey extends OnyxKey>(...keys: TKey[]) {
return Promise.all(keys.map((key) => getOnyxValue(key)));
}

function getOnyxValue<TKey extends OnyxKey>(key: TKey): Promise<OnyxEntry<KeyValueMapping[TKey]>> {
return new Promise((resolve) => {
Onyx.connect({
key,
callback: (value) => resolve(value),
});
});
}

0 comments on commit eb59c33

Please sign in to comment.