diff --git a/lib/Onyx.ts b/lib/Onyx.ts index da3d12b1..f927f353 100644 --- a/lib/Onyx.ts +++ b/lib/Onyx.ts @@ -554,22 +554,27 @@ function mergeCollection(collectionKey: TK * @param keysToPreserve is a list of ONYXKEYS that should not be cleared with the rest of the data */ function clear(keysToPreserve: OnyxKey[] = []): Promise { + const defaultKeyStates = OnyxUtils.getDefaultKeyStates(); + const initialKeys = Object.keys(defaultKeyStates); + return OnyxUtils.getAllKeys() - .then((keys) => { + .then((cachedKeys) => { cache.clearNullishStorageKeys(); const keysToBeClearedFromStorage: OnyxKey[] = []; const keyValuesToResetAsCollection: Record> = {}; const keyValuesToResetIndividually: KeyValueMapping = {}; + const allKeys = new Set([...cachedKeys, ...initialKeys]); + // The only keys that should not be cleared are: // 1. Anything specifically passed in keysToPreserve (because some keys like language preferences, offline // status, or activeClients need to remain in Onyx even when signed out) // 2. Any keys with a default state (because they need to remain in Onyx as their default, and setting them // to null would cause unknown behavior) - keys.forEach((key) => { + // 2.1 However, if a default key was explicitly set to null, we need to reset it to the default value + allKeys.forEach((key) => { const isKeyToPreserve = keysToPreserve.includes(key); - const defaultKeyStates = OnyxUtils.getDefaultKeyStates(); const isDefaultKey = key in defaultKeyStates; // If the key is being removed or reset to default: @@ -611,7 +616,6 @@ function clear(keysToPreserve: OnyxKey[] = []): Promise { updatePromises.push(OnyxUtils.scheduleNotifyCollectionSubscribers(key, value)); }); - const defaultKeyStates = OnyxUtils.getDefaultKeyStates(); const defaultKeyValuePairs = Object.entries( Object.keys(defaultKeyStates) .filter((key) => !keysToPreserve.includes(key)) diff --git a/tests/unit/onyxTest.ts b/tests/unit/onyxTest.ts index d4879ee9..cc13beca 100644 --- a/tests/unit/onyxTest.ts +++ b/tests/unit/onyxTest.ts @@ -51,17 +51,23 @@ describe('Onyx', () => { expect(keys.has(ONYX_KEYS.OTHER_TEST)).toBe(true); return Onyx.set(ONYX_KEYS.OTHER_TEST, null); }) + // Checks if cache value is removed. .then(() => { - // Checks if cache value is removed. - expect(cache.getAllKeys().size).toBe(0); - - // When cache keys length is 0, we fetch the keys from storage. + expect(cache.get(ONYX_KEYS.OTHER_TEST)).toBeUndefined(); return OnyxUtils.getAllKeys(); }) .then((keys) => { expect(keys.has(ONYX_KEYS.OTHER_TEST)).toBe(false); })); + it('should restore a key with initial state if the key was set to null and Onyx.clear() is called', () => + Onyx.set(ONYX_KEYS.OTHER_TEST, 42) + .then(() => Onyx.set(ONYX_KEYS.OTHER_TEST, null)) + .then(() => Onyx.clear()) + .then(() => { + expect(cache.get(ONYX_KEYS.OTHER_TEST)).toBe(42); + })); + it('should set a simple key', () => { let testKeyValue: unknown; @@ -167,32 +173,31 @@ describe('Onyx', () => { }, }); - let otherTestValue: unknown; - const mockCallback = jest.fn((value) => { - otherTestValue = value; - }); + const mockCallback = jest.fn(); const otherTestConnectionID = Onyx.connect({ key: ONYX_KEYS.OTHER_TEST, callback: mockCallback, }); return waitForPromisesToResolve() + .then(() => { + expect(mockCallback).toHaveBeenCalledTimes(1); + expect(mockCallback).toHaveBeenCalledWith(42, ONYX_KEYS.OTHER_TEST); + mockCallback.mockClear(); + }) .then(() => Onyx.set(ONYX_KEYS.TEST_KEY, 'test')) .then(() => { expect(testKeyValue).toBe('test'); - mockCallback.mockReset(); - return Onyx.clear().then(waitForPromisesToResolve); + return Onyx.clear(); }) + .then(() => waitForPromisesToResolve()) .then(() => { // Test key should be cleared expect(testKeyValue).toBeUndefined(); - // Expect that the connection to a key with a default value wasn't cleared + // Expect that the connection to a key with a default value that wasn't changed is not called on clear expect(mockCallback).toHaveBeenCalledTimes(0); - // Other test key should be returned to its default state - expect(otherTestValue).toBe(42); - return Onyx.disconnect(otherTestConnectionID); }); });