From 1da55754141df37fbe0d311906a4711bfcad0fe7 Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Tue, 19 Sep 2023 17:41:16 +0200 Subject: [PATCH 1/2] [TS migration] Migrate 'MoveToIndexedDB.js' lib to TypeScript --- src/libs/migrateOnyx.js | 2 - src/libs/migrations/MoveToIndexedDB.js | 75 -------------------------- tests/unit/MigrationTest.js | 68 ----------------------- 3 files changed, 145 deletions(-) delete mode 100644 src/libs/migrations/MoveToIndexedDB.js diff --git a/src/libs/migrateOnyx.js b/src/libs/migrateOnyx.js index 9389a9b66fbc..c1129817ef0a 100644 --- a/src/libs/migrateOnyx.js +++ b/src/libs/migrateOnyx.js @@ -3,7 +3,6 @@ import Log from './Log'; import AddEncryptedAuthToken from './migrations/AddEncryptedAuthToken'; import RenameActiveClientsKey from './migrations/RenameActiveClientsKey'; import RenamePriorityModeKey from './migrations/RenamePriorityModeKey'; -import MoveToIndexedDB from './migrations/MoveToIndexedDB'; import RenameExpensifyNewsStatus from './migrations/RenameExpensifyNewsStatus'; import AddLastVisibleActionCreated from './migrations/AddLastVisibleActionCreated'; import KeyReportActionsByReportActionID from './migrations/KeyReportActionsByReportActionID'; @@ -16,7 +15,6 @@ export default function () { return new Promise((resolve) => { // Add all migrations to an array so they are executed in order const migrationPromises = [ - MoveToIndexedDB, RenameActiveClientsKey, RenamePriorityModeKey, AddEncryptedAuthToken, diff --git a/src/libs/migrations/MoveToIndexedDB.js b/src/libs/migrations/MoveToIndexedDB.js deleted file mode 100644 index 1f62985ed7bf..000000000000 --- a/src/libs/migrations/MoveToIndexedDB.js +++ /dev/null @@ -1,75 +0,0 @@ -import _ from 'underscore'; -import Onyx from 'react-native-onyx'; - -import Log from '../Log'; -import ONYXKEYS from '../../ONYXKEYS'; -import getPlatform from '../getPlatform'; -import CONST from '../../CONST'; - -/** - * Test whether the current platform is eligible for migration - * This migration is only applicable for desktop/web - * We're also skipping logged-out users as there would be nothing to migrate - * - * @returns {Boolean} - */ -function shouldMigrate() { - const isTargetPlatform = _.contains([CONST.PLATFORM.WEB, CONST.PLATFORM.DESKTOP], getPlatform()); - if (!isTargetPlatform) { - Log.info('[Migrate Onyx] Skipped migration MoveToIndexedDB (Not applicable to current platform)'); - return false; - } - - const session = window.localStorage.getItem(ONYXKEYS.SESSION); - if (!session || !session.includes('authToken')) { - Log.info('[Migrate Onyx] Skipped migration MoveToIndexedDB (Not applicable to logged out users)'); - return false; - } - - return true; -} - -/** - * Find Onyx data and move it from local storage to IndexedDB - * - * @returns {Promise} - */ -function applyMigration() { - const onyxKeys = new Set(_.values(ONYXKEYS)); - const onyxCollections = _.values(ONYXKEYS.COLLECTION); - - // Prepare a key-value dictionary of keys eligible for migration - // Targeting existing Onyx keys in local storage or any key prefixed by a collection name - const dataToMigrate = _.chain(window.localStorage) - .keys() - .filter((key) => onyxKeys.has(key) || _.some(onyxCollections, (collectionKey) => key.startsWith(collectionKey))) - .map((key) => [key, JSON.parse(window.localStorage.getItem(key))]) - .object() - .value(); - - // Move the data in Onyx and only then delete it from local storage - return Onyx.multiSet(dataToMigrate).then(() => _.each(dataToMigrate, (value, key) => window.localStorage.removeItem(key))); -} - -/** - * Migrate Web/Desktop storage to IndexedDB - * - * @returns {Promise} - */ -export default function () { - if (!shouldMigrate()) { - return Promise.resolve(); - } - - return new Promise((resolve, reject) => { - applyMigration() - .then(() => { - Log.info('[Migrate Onyx] Ran migration MoveToIndexedDB'); - resolve(); - }) - .catch((e) => { - Log.alert('[Migrate Onyx] MoveToIndexedDB failed', {error: e.message, stack: e.stack}, false); - reject(e); - }); - }); -} diff --git a/tests/unit/MigrationTest.js b/tests/unit/MigrationTest.js index 0171ee640226..71f7d57fce36 100644 --- a/tests/unit/MigrationTest.js +++ b/tests/unit/MigrationTest.js @@ -1,11 +1,8 @@ import Onyx from 'react-native-onyx'; import _ from 'underscore'; import waitForPromisesToResolve from '../utils/waitForPromisesToResolve'; -import CONST from '../../src/CONST'; import Log from '../../src/libs/Log'; -import getPlatform from '../../src/libs/getPlatform'; import AddLastVisibleActionCreated from '../../src/libs/migrations/AddLastVisibleActionCreated'; -import MoveToIndexedDB from '../../src/libs/migrations/MoveToIndexedDB'; import KeyReportActionsByReportActionID from '../../src/libs/migrations/KeyReportActionsByReportActionID'; import PersonalDetailsByAccountID from '../../src/libs/migrations/PersonalDetailsByAccountID'; import CheckForPreviousReportActionID from '../../src/libs/migrations/CheckForPreviousReportActionID'; @@ -29,71 +26,6 @@ describe('Migrations', () => { return waitForPromisesToResolve(); }); - describe('MoveToIndexedDb', () => { - let mockMultiSet; - beforeEach(() => { - getPlatform.mockImplementation(() => CONST.PLATFORM.WEB); - mockMultiSet = jest.spyOn(Onyx, 'multiSet').mockImplementation(() => Promise.resolve()); - localStorage.clear(); - }); - - afterAll(() => { - mockMultiSet.mockRestore(Onyx, 'multiSet'); - localStorage.clear(); - }); - - it('Should do nothing for non web/desktop platforms', () => { - // Given the migration is not running on web or desktop - getPlatform.mockImplementation(() => CONST.PLATFORM.ANDROID); - - // When the migration runs - return MoveToIndexedDB().then(() => { - // Then we don't expect any storage calls - expect(Onyx.multiSet).not.toHaveBeenCalled(); - }); - }); - - it('Should do nothing when there is no old session data', () => { - // Given no session in old storage medium (localStorage) - localStorage.removeItem(ONYXKEYS.SESSION); - - // When the migration runs - return MoveToIndexedDB().then(() => { - // Then we don't expect any storage calls - expect(Onyx.multiSet).not.toHaveBeenCalled(); - }); - }); - - it('Should migrate Onyx keys in localStorage to (new) Onyx', () => { - // Given some old data exists in storage - const data = { - [ONYXKEYS.SESSION]: {authToken: 'mock-token', loading: false}, - [ONYXKEYS.ACCOUNT]: {email: 'test@mock.com'}, - [ONYXKEYS.NETWORK]: {isOffline: true}, - }; - - _.forEach(data, (value, key) => localStorage.setItem(key, JSON.stringify(value))); - - // When the migration runs - return MoveToIndexedDB().then(() => { - // Then multiset should be called with all the data available in localStorage - expect(Onyx.multiSet).toHaveBeenCalledWith(data); - }); - }); - - it('Should not clear non Onyx keys from localStorage', () => { - // Given some Onyx and non-Onyx data exists in localStorage - localStorage.setItem(ONYXKEYS.SESSION, JSON.stringify({authToken: 'mock-token'})); - localStorage.setItem('non-onyx-item', 'MOCK'); - - // When the migration runs - return MoveToIndexedDB().then(() => { - // Then non-Onyx data should remain in localStorage - expect(localStorage.getItem('non-onyx-item')).toEqual('MOCK'); - }); - }); - }); - describe('AddLastVisibleActionCreated', () => { it('Should add lastVisibleActionCreated wherever lastActionCreated currently is', () => Onyx.multiSet({ From bd716a534ba9a5a1eb3446b44c619899449ec1a8 Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Wed, 20 Sep 2023 15:52:29 +0200 Subject: [PATCH 2/2] Fix prettier --- src/libs/migrateOnyx.js | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/libs/migrateOnyx.js b/src/libs/migrateOnyx.js index 3e92bb17c842..8ade54c0b5d2 100644 --- a/src/libs/migrateOnyx.js +++ b/src/libs/migrateOnyx.js @@ -13,14 +13,7 @@ export default function () { return new Promise((resolve) => { // Add all migrations to an array so they are executed in order - const migrationPromises = [ - RenameActiveClientsKey, - RenamePriorityModeKey, - AddEncryptedAuthToken, - RenameExpensifyNewsStatus, - AddLastVisibleActionCreated, - PersonalDetailsByAccountID, - ]; + const migrationPromises = [RenameActiveClientsKey, RenamePriorityModeKey, AddEncryptedAuthToken, RenameExpensifyNewsStatus, AddLastVisibleActionCreated, PersonalDetailsByAccountID]; // Reduce all promises down to a single promise. All promises run in a linear fashion, waiting for the // previous promise to finish before moving onto the next one.