diff --git a/lib/OnyxUtils.ts b/lib/OnyxUtils.ts index 4dc1ba2ce..6cbd61d7d 100644 --- a/lib/OnyxUtils.ts +++ b/lib/OnyxUtils.ts @@ -1211,6 +1211,11 @@ function updateSnapshots(data: Array>, me let updatedData: Record = {}; for (const {key, value} of data) { + if (typeof key !== 'string') { + Logger.logInfo(`Invalid ${typeof key} key provided in Onyx update. Key must be of type string. Skipping snapshot update for this entry.`); + continue; + } + // snapshots are normal keys so we want to skip update if they are written to Onyx if (OnyxKeys.isCollectionMemberKey(snapshotCollectionKey, key)) { continue; diff --git a/tests/unit/onyxTest.ts b/tests/unit/onyxTest.ts index 0021fcd8e..a606e6a83 100644 --- a/tests/unit/onyxTest.ts +++ b/tests/unit/onyxTest.ts @@ -1535,6 +1535,33 @@ describe('Onyx', () => { expect(callback.mock.calls[1][1]).toBe(ONYX_KEYS.COLLECTION.SNAPSHOT); }); + it('should skip update entries without a key when updating Snapshots instead of rejecting', async () => { + const cat = `${ONYX_KEYS.COLLECTION.ANIMALS}cat`; + const snapshot1 = `${ONYX_KEYS.COLLECTION.SNAPSHOT}1`; + + const initialValue = {name: 'Fluffy'}; + const finalValue = {name: 'Kitty'}; + + await Onyx.set(cat, initialValue); + await Onyx.set(snapshot1, {data: {[cat]: initialValue}}); + + const callback = jest.fn(); + + Onyx.connect({ + key: ONYX_KEYS.COLLECTION.SNAPSHOT, + callback, + }); + + await waitForPromisesToResolve(); + + const keylessUpdate = {onyxMethod: Onyx.METHOD.MERGE, value: {name: 'Ghost'}} as unknown as OnyxUpdate; + + await expect(Onyx.update([keylessUpdate, {key: cat, value: finalValue, onyxMethod: Onyx.METHOD.MERGE}])).resolves.not.toThrow(); + + // The valid update still lands in the snapshot. + expect(callback.mock.calls.at(-1)?.[0]).toEqual({[snapshot1]: {data: {[cat]: finalValue}}}); + }); + describe('update', () => { let logInfoFn = jest.fn();