Repository: parse-community/Parse-SDK-JS
Pull request #1569 (2022-10-08 01:39:44)

fix: initialization fails in non-browser environment that doesn't support `indexedDB`
### New Pull Request Checklist
<!--
    Check every following box [x] before submitting your PR.
    Click the "Preview" tab for better readability.
    Thanks for contributing to Parse Platform!
-->

- [x] I am not disclosing a [vulnerability](https://github.com/parse-community/parse-server/blob/master/SECURITY.md).
- [x] I am creating this PR in reference to an [issue](https://github.com/parse-community/Parse-SDK-JS/issues?q=is%3Aissue).

### Issue Description
<!-- Add a brief description of the issue this PR solves. -->

IndexedDB is only available in the browser. `createStore` is a promise that runs in the background. If indexedDB isn't supported, the promise rejects with `Unhandled promise rejection`.

Closes: https://github.com/parse-community/Parse-SDK-JS/issues/1552, https://github.com/parse-community/Parse-SDK-JS/issues/1440, https://github.com/parse-community/Parse-SDK-JS/issues/1505, https://github.com/parse-community/Parse-SDK-JS/issues/1441

### Approach
<!-- Add a description of the approach in this PR. -->

* Add indexedDBStorageController for `process.env.PARSE_BUILD === 'browser'`
* Check if indexedDB exists

### TODOs before merging
<!--
    Add TODOs that need to be completed before merging this PR.
    Delete TODOs that do not apply to this PR.
-->

- [x] Add tests

parse-github-assistant[bot]: I will reformat the title to use the proper commit message syntax.
parse-github-assistant[bot]: 
### Thanks for opening this pull request!

- ❌ Please check all required checkboxes at the top, otherwise your pull request will be closed.

- ⚠️ Remember that a security vulnerability must only be reported confidentially, see our [Security Policy](https://github.com/parse-community/parse-server/blob/master/SECURITY.md). If you are not sure whether the issue is a security vulnerability, the safest way is to treat it as such and submit it confidentially to us for evaluation.

<!-- parse-issue-bot-meta-tag-id {"requireTopCheckboxes":true} -->


codecov[bot]: # [Codecov](https://codecov.io/gh/parse-community/Parse-SDK-JS/pull/1569?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=parse-community) Report
Base: **99.94**% // Head: **99.94**% // Increases project coverage by **`+0.00%`** :tada:
> Coverage data is based on head [(`f4a61de`)](https://codecov.io/gh/parse-community/Parse-SDK-JS/pull/1569?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=parse-community) compared to base [(`4864d54`)](https://codecov.io/gh/parse-community/Parse-SDK-JS/commit/4864d54e342e379d2d17a07f935966be7e19fa1b?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=parse-community).
> Patch coverage: 100.00% of modified lines in pull request are covered.

<details><summary>Additional details and impacted files</summary>


```diff
@@           Coverage Diff           @@
##            alpha    #1569   +/-   ##
=======================================
  Coverage   99.94%   99.94%           
=======================================
  Files          61       61           
  Lines        5955     5957    +2     
  Branches     1360     1362    +2     
=======================================
+ Hits         5952     5954    +2     
  Misses          3        3           
```


| [Impacted Files](https://codecov.io/gh/parse-community/Parse-SDK-JS/pull/1569?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=parse-community) | Coverage Δ | |
|---|---|---|
| [src/IndexedDBStorageController.js](https://codecov.io/gh/parse-community/Parse-SDK-JS/pull/1569/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=parse-community#diff-c3JjL0luZGV4ZWREQlN0b3JhZ2VDb250cm9sbGVyLmpz) | `100.00% <100.00%> (ø)` | |
| [src/Parse.js](https://codecov.io/gh/parse-community/Parse-SDK-JS/pull/1569/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=parse-community#diff-c3JjL1BhcnNlLmpz) | `100.00% <100.00%> (ø)` | |

Help us with your feedback. Take ten seconds to tell us [how you rate us](https://about.codecov.io/nps?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=parse-community). Have a feature suggestion? [Share it here.](https://app.codecov.io/gh/feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=parse-community)

</details>

[:umbrella: View full report at Codecov](https://codecov.io/gh/parse-community/Parse-SDK-JS/pull/1569?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=parse-community).   
:loudspeaker: Do you have feedback about the report comment? [Let us know in this issue](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=parse-community).

mtrezza: @dplewis please request review from `@parse-community/js-sdk-review` instead of individual members.
mtrezza: Is the PR title accurate?
dplewis: Thats right

Patch:
diff --git a/src/IndexedDBStorageController.js b/src/IndexedDBStorageController.js
index 9c963d6..a223000 100644
--- a/src/IndexedDBStorageController.js
+++ b/src/IndexedDBStorageController.js
@@ -1,10 +1,11 @@
 /**
  * @flow
  */
+/* global window */
 
 import { createStore, del, set, get, clear, keys } from 'idb-keyval';
 
-try {
+if (typeof window !== 'undefined' && window.indexedDB) {
   const ParseStore = createStore('parseDB', 'parseStore');
 
   const IndexedDBStorageController = {
@@ -27,6 +28,7 @@ try {
   };
 
   module.exports = IndexedDBStorageController;
-} catch (e) {
+} else {
   // IndexedDB not supported
+  module.exports = undefined;
 }
diff --git a/src/Parse.js b/src/Parse.js
index 7554b3c..548fbfd 100644
--- a/src/Parse.js
+++ b/src/Parse.js
@@ -246,8 +246,9 @@ Parse.Storage = require('./Storage');
 Parse.User = require('./ParseUser').default;
 Parse.LiveQuery = require('./ParseLiveQuery').default;
 Parse.LiveQueryClient = require('./LiveQueryClient').default;
-Parse.IndexedDB = require('./IndexedDBStorageController');
-
+if (process.env.PARSE_BUILD === 'browser') {
+  Parse.IndexedDB = require('./IndexedDBStorageController');
+}
 Parse._request = function (...args) {
   return CoreManager.getRESTController().request.apply(null, args);
 };


Test patch:
diff --git a/src/__tests__/Parse-test.js b/src/__tests__/Parse-test.js
index 965668b..c335028 100644
--- a/src/__tests__/Parse-test.js
+++ b/src/__tests__/Parse-test.js
@@ -16,11 +16,18 @@ jest.dontMock('../LocalDatastore');
 jest.dontMock('crypto-js/aes');
 jest.setMock('../EventuallyQueue', { poll: jest.fn() });
 
+global.indexedDB = require('./test_helpers/mockIndexedDB');
 const CoreManager = require('../CoreManager');
 const EventuallyQueue = require('../EventuallyQueue');
-const Parse = require('../Parse');
 
 describe('Parse module', () => {
+  let Parse;
+  beforeEach(() => {
+    jest.isolateModules(() => {
+      Parse = require('../Parse');
+    });
+  });
+
   it('can be initialized with keys', () => {
     Parse.initialize('A', 'B');
     expect(CoreManager.get('APPLICATION_ID')).toBe('A');
@@ -165,6 +172,7 @@ describe('Parse module', () => {
     Parse.enableEncryptedUser();
     expect(Parse.encryptedUser).toBe(true);
     expect(Parse.isEncryptedUserEnabled()).toBe(true);
+    process.env.PARSE_BUILD = 'node';
   });
 
   it('can set an encrypt token as String', () => {
@@ -240,10 +248,13 @@ describe('Parse module', () => {
   });
 
   it('can get IndexedDB storage', () => {
-    console.log(Parse.IndexedDB);
-    expect(Parse.IndexedDB).toBeDefined();
-    CoreManager.setStorageController(Parse.IndexedDB);
+    expect(Parse.IndexedDB).toBeUndefined();
+    process.env.PARSE_BUILD = 'browser';
+    const ParseInstance = require('../Parse');
+    expect(ParseInstance.IndexedDB).toBeDefined();
+    CoreManager.setStorageController(ParseInstance.IndexedDB);
     const currentStorage = CoreManager.getStorageController();
-    expect(currentStorage).toEqual(Parse.IndexedDB);
+    expect(currentStorage).toEqual(ParseInstance.IndexedDB);
+    process.env.PARSE_BUILD = 'node';
   });
 });
diff --git a/src/__tests__/Storage-test.js b/src/__tests__/Storage-test.js
index 356956e..4fd8bb3 100644
--- a/src/__tests__/Storage-test.js
+++ b/src/__tests__/Storage-test.js
@@ -17,6 +17,7 @@ const CoreManager = require('../CoreManager');
 
 global.wx = mockWeChat;
 global.localStorage = mockStorageInterface;
+global.indexedDB = mockIndexedDB;
 jest.mock('idb-keyval', () => {
   return mockIndexedDB;
 });
@@ -165,10 +166,12 @@ describe('React Native StorageController', () => {
   });
 });
 
-const IndexedDBStorageController = require('../IndexedDBStorageController');
-
-describe('React Native StorageController', () => {
+describe('IndexDB StorageController', () => {
+  let IndexedDBStorageController;
   beforeEach(() => {
+    jest.isolateModules(() => {
+      IndexedDBStorageController = require('../IndexedDBStorageController');
+    });
     IndexedDBStorageController.clear();
   });
 
@@ -203,6 +206,13 @@ describe('React Native StorageController', () => {
     const keys = await IndexedDBStorageController.getAllKeysAsync();
     expect(keys[0]).toBe('myKey');
   });
+
+  it('handle indexedDB is not defined', async () => {
+    global.indexedDB = undefined;
+    const dbController = require('../IndexedDBStorageController');
+    expect(dbController).toBeUndefined();
+    global.indexedDB = mockIndexedDB;
+  });
 });
 
 const DefaultStorageController = require('../StorageController.default');