Skip to content

Commit

Permalink
Catch getDefaults() errors and do not throw (#6686)
Browse files Browse the repository at this point in the history
  • Loading branch information
hsubox76 authored Oct 12, 2022
1 parent 8a6e9e6 commit 807f06a
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 15 deletions.
5 changes: 5 additions & 0 deletions .changeset/grumpy-suits-pump.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@firebase/util': patch
---

Catch errors when the SDK checks for `__FIREBASE_DEFAULTS__` and do not block other app functionality.
31 changes: 26 additions & 5 deletions packages/util/src/defaults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,14 @@ const getDefaultsFromCookie = (): FirebaseDefaults | undefined => {
if (typeof document === 'undefined') {
return;
}
const match = document.cookie.match(/__FIREBASE_DEFAULTS__=([^;]+)/);
let match;
try {
match = document.cookie.match(/__FIREBASE_DEFAULTS__=([^;]+)/);
} catch (e) {
// Some environments such as Angular Universal SSR have a
// `document` object but error on accessing `document.cookie`.
return;
}
const decoded = match && base64Decode(match[1]);
return decoded && JSON.parse(decoded);
};
Expand All @@ -81,10 +88,24 @@ const getDefaultsFromCookie = (): FirebaseDefaults | undefined => {
* (2) if such an object was provided on a shell environment variable
* (3) if such an object exists in a cookie
*/
const getDefaults = (): FirebaseDefaults | undefined =>
getDefaultsFromGlobal() ||
getDefaultsFromEnvVariable() ||
getDefaultsFromCookie();
const getDefaults = (): FirebaseDefaults | undefined => {
try {
return (
getDefaultsFromGlobal() ||
getDefaultsFromEnvVariable() ||
getDefaultsFromCookie()
);
} catch (e) {
/**
* Catch-all for being unable to get __FIREBASE_DEFAULTS__ due
* to any environment case we have not accounted for. Log to
* info instead of swallowing so we can find these unknown cases
* and add paths for them if needed.
*/
console.info(`Unable to get __FIREBASE_DEFAULTS__ due to: ${e}`);
return;
}
};

/**
* Returns emulator host stored in the __FIREBASE_DEFAULTS__ object
Expand Down
69 changes: 59 additions & 10 deletions packages/util/test/defaults.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,20 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { expect } from 'chai';
import { expect, use } from 'chai';
import { match, restore, SinonStub, stub } from 'sinon';
import sinonChai from 'sinon-chai';
import {
getDefaultEmulatorHost,
getDefaultEmulatorHostnameAndPort
} from '../src/defaults';
import { getGlobal } from '../src/environment';
import * as environment from '../src/environment';

use(sinonChai);

describe('getDefaultEmulatorHost', () => {
after(() => {
delete getGlobal().__FIREBASE_DEFAULTS__;
delete environment.getGlobal().__FIREBASE_DEFAULTS__;
});

context('with no config', () => {
Expand All @@ -32,9 +36,54 @@ describe('getDefaultEmulatorHost', () => {
});
});

context('with no config and process.env undefined', () => {
before(() => {
stub(process, 'env').value(undefined);
});
after(() => {
restore();
});
it('returns undefined and does not throw', () => {
expect(getDefaultEmulatorHost('firestore')).to.be.undefined;
expect(getDefaultEmulatorHost('firestore')).to.not.throw;
});
});

context('with no config and no document or document.cookie throws', () => {
before(() => {
// In Node tests document will not exist
if (typeof document !== 'undefined') {
stub(document, 'cookie').get(() => new Error('aaaah'));
}
});
after(() => {
restore();
});
it('returns undefined and does not throw', () => {
expect(getDefaultEmulatorHost('firestore')).to.be.undefined;
expect(getDefaultEmulatorHost('firestore')).to.not.throw;
});
});

context('with no config and something unexpected throws', () => {
let consoleInfoStub: SinonStub;
before(() => {
stub(environment, 'getGlobal').throws(new Error('getGlobal threw!'));
consoleInfoStub = stub(console, 'info');
});
after(() => {
delete process.env.__FIREBASE_DEFAULTS__;
restore();
});
it('returns undefined and calls console.info with the error', () => {
expect(getDefaultEmulatorHost('firestore')).to.be.undefined;
expect(consoleInfoStub).to.be.calledWith(match('getGlobal threw!'));
});
});

context('with global config not listing the emulator', () => {
before(() => {
getGlobal().__FIREBASE_DEFAULTS__ = {
environment.getGlobal().__FIREBASE_DEFAULTS__ = {
emulatorHosts: {
/* no firestore */
database: '127.0.0.1:8080'
Expand All @@ -49,7 +98,7 @@ describe('getDefaultEmulatorHost', () => {

context('with IPv4 hostname in global config', () => {
before(() => {
getGlobal().__FIREBASE_DEFAULTS__ = {
environment.getGlobal().__FIREBASE_DEFAULTS__ = {
emulatorHosts: {
firestore: '127.0.0.1:8080'
}
Expand All @@ -63,7 +112,7 @@ describe('getDefaultEmulatorHost', () => {

context('with quoted IPv6 hostname in global config', () => {
before(() => {
getGlobal().__FIREBASE_DEFAULTS__ = {
environment.getGlobal().__FIREBASE_DEFAULTS__ = {
emulatorHosts: {
firestore: '[::1]:8080'
}
Expand All @@ -78,7 +127,7 @@ describe('getDefaultEmulatorHost', () => {

describe('getDefaultEmulatorHostnameAndPort', () => {
after(() => {
delete getGlobal().__FIREBASE_DEFAULTS__;
delete environment.getGlobal().__FIREBASE_DEFAULTS__;
});

context('with no config', () => {
Expand All @@ -89,7 +138,7 @@ describe('getDefaultEmulatorHostnameAndPort', () => {

context('with global config not listing the emulator', () => {
before(() => {
getGlobal().__FIREBASE_DEFAULTS__ = {
environment.getGlobal().__FIREBASE_DEFAULTS__ = {
emulatorHosts: {
/* no firestore */
database: '127.0.0.1:8080'
Expand All @@ -104,7 +153,7 @@ describe('getDefaultEmulatorHostnameAndPort', () => {

context('with IPv4 hostname in global config', () => {
before(() => {
getGlobal().__FIREBASE_DEFAULTS__ = {
environment.getGlobal().__FIREBASE_DEFAULTS__ = {
emulatorHosts: {
firestore: '127.0.0.1:8080'
}
Expand All @@ -121,7 +170,7 @@ describe('getDefaultEmulatorHostnameAndPort', () => {

context('with quoted IPv6 hostname in global config', () => {
before(() => {
getGlobal().__FIREBASE_DEFAULTS__ = {
environment.getGlobal().__FIREBASE_DEFAULTS__ = {
emulatorHosts: {
firestore: '[::1]:8080'
}
Expand Down

0 comments on commit 807f06a

Please sign in to comment.