Skip to content

Commit 807f06a

Browse files
authored
Catch getDefaults() errors and do not throw (#6686)
1 parent 8a6e9e6 commit 807f06a

File tree

3 files changed

+90
-15
lines changed

3 files changed

+90
-15
lines changed

.changeset/grumpy-suits-pump.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@firebase/util': patch
3+
---
4+
5+
Catch errors when the SDK checks for `__FIREBASE_DEFAULTS__` and do not block other app functionality.

packages/util/src/defaults.ts

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,14 @@ const getDefaultsFromCookie = (): FirebaseDefaults | undefined => {
7070
if (typeof document === 'undefined') {
7171
return;
7272
}
73-
const match = document.cookie.match(/__FIREBASE_DEFAULTS__=([^;]+)/);
73+
let match;
74+
try {
75+
match = document.cookie.match(/__FIREBASE_DEFAULTS__=([^;]+)/);
76+
} catch (e) {
77+
// Some environments such as Angular Universal SSR have a
78+
// `document` object but error on accessing `document.cookie`.
79+
return;
80+
}
7481
const decoded = match && base64Decode(match[1]);
7582
return decoded && JSON.parse(decoded);
7683
};
@@ -81,10 +88,24 @@ const getDefaultsFromCookie = (): FirebaseDefaults | undefined => {
8188
* (2) if such an object was provided on a shell environment variable
8289
* (3) if such an object exists in a cookie
8390
*/
84-
const getDefaults = (): FirebaseDefaults | undefined =>
85-
getDefaultsFromGlobal() ||
86-
getDefaultsFromEnvVariable() ||
87-
getDefaultsFromCookie();
91+
const getDefaults = (): FirebaseDefaults | undefined => {
92+
try {
93+
return (
94+
getDefaultsFromGlobal() ||
95+
getDefaultsFromEnvVariable() ||
96+
getDefaultsFromCookie()
97+
);
98+
} catch (e) {
99+
/**
100+
* Catch-all for being unable to get __FIREBASE_DEFAULTS__ due
101+
* to any environment case we have not accounted for. Log to
102+
* info instead of swallowing so we can find these unknown cases
103+
* and add paths for them if needed.
104+
*/
105+
console.info(`Unable to get __FIREBASE_DEFAULTS__ due to: ${e}`);
106+
return;
107+
}
108+
};
88109

89110
/**
90111
* Returns emulator host stored in the __FIREBASE_DEFAULTS__ object

packages/util/test/defaults.test.ts

Lines changed: 59 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,20 @@
1414
* See the License for the specific language governing permissions and
1515
* limitations under the License.
1616
*/
17-
import { expect } from 'chai';
17+
import { expect, use } from 'chai';
18+
import { match, restore, SinonStub, stub } from 'sinon';
19+
import sinonChai from 'sinon-chai';
1820
import {
1921
getDefaultEmulatorHost,
2022
getDefaultEmulatorHostnameAndPort
2123
} from '../src/defaults';
22-
import { getGlobal } from '../src/environment';
24+
import * as environment from '../src/environment';
25+
26+
use(sinonChai);
2327

2428
describe('getDefaultEmulatorHost', () => {
2529
after(() => {
26-
delete getGlobal().__FIREBASE_DEFAULTS__;
30+
delete environment.getGlobal().__FIREBASE_DEFAULTS__;
2731
});
2832

2933
context('with no config', () => {
@@ -32,9 +36,54 @@ describe('getDefaultEmulatorHost', () => {
3236
});
3337
});
3438

39+
context('with no config and process.env undefined', () => {
40+
before(() => {
41+
stub(process, 'env').value(undefined);
42+
});
43+
after(() => {
44+
restore();
45+
});
46+
it('returns undefined and does not throw', () => {
47+
expect(getDefaultEmulatorHost('firestore')).to.be.undefined;
48+
expect(getDefaultEmulatorHost('firestore')).to.not.throw;
49+
});
50+
});
51+
52+
context('with no config and no document or document.cookie throws', () => {
53+
before(() => {
54+
// In Node tests document will not exist
55+
if (typeof document !== 'undefined') {
56+
stub(document, 'cookie').get(() => new Error('aaaah'));
57+
}
58+
});
59+
after(() => {
60+
restore();
61+
});
62+
it('returns undefined and does not throw', () => {
63+
expect(getDefaultEmulatorHost('firestore')).to.be.undefined;
64+
expect(getDefaultEmulatorHost('firestore')).to.not.throw;
65+
});
66+
});
67+
68+
context('with no config and something unexpected throws', () => {
69+
let consoleInfoStub: SinonStub;
70+
before(() => {
71+
stub(environment, 'getGlobal').throws(new Error('getGlobal threw!'));
72+
consoleInfoStub = stub(console, 'info');
73+
});
74+
after(() => {
75+
delete process.env.__FIREBASE_DEFAULTS__;
76+
restore();
77+
});
78+
it('returns undefined and calls console.info with the error', () => {
79+
expect(getDefaultEmulatorHost('firestore')).to.be.undefined;
80+
expect(consoleInfoStub).to.be.calledWith(match('getGlobal threw!'));
81+
});
82+
});
83+
3584
context('with global config not listing the emulator', () => {
3685
before(() => {
37-
getGlobal().__FIREBASE_DEFAULTS__ = {
86+
environment.getGlobal().__FIREBASE_DEFAULTS__ = {
3887
emulatorHosts: {
3988
/* no firestore */
4089
database: '127.0.0.1:8080'
@@ -49,7 +98,7 @@ describe('getDefaultEmulatorHost', () => {
4998

5099
context('with IPv4 hostname in global config', () => {
51100
before(() => {
52-
getGlobal().__FIREBASE_DEFAULTS__ = {
101+
environment.getGlobal().__FIREBASE_DEFAULTS__ = {
53102
emulatorHosts: {
54103
firestore: '127.0.0.1:8080'
55104
}
@@ -63,7 +112,7 @@ describe('getDefaultEmulatorHost', () => {
63112

64113
context('with quoted IPv6 hostname in global config', () => {
65114
before(() => {
66-
getGlobal().__FIREBASE_DEFAULTS__ = {
115+
environment.getGlobal().__FIREBASE_DEFAULTS__ = {
67116
emulatorHosts: {
68117
firestore: '[::1]:8080'
69118
}
@@ -78,7 +127,7 @@ describe('getDefaultEmulatorHost', () => {
78127

79128
describe('getDefaultEmulatorHostnameAndPort', () => {
80129
after(() => {
81-
delete getGlobal().__FIREBASE_DEFAULTS__;
130+
delete environment.getGlobal().__FIREBASE_DEFAULTS__;
82131
});
83132

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

90139
context('with global config not listing the emulator', () => {
91140
before(() => {
92-
getGlobal().__FIREBASE_DEFAULTS__ = {
141+
environment.getGlobal().__FIREBASE_DEFAULTS__ = {
93142
emulatorHosts: {
94143
/* no firestore */
95144
database: '127.0.0.1:8080'
@@ -104,7 +153,7 @@ describe('getDefaultEmulatorHostnameAndPort', () => {
104153

105154
context('with IPv4 hostname in global config', () => {
106155
before(() => {
107-
getGlobal().__FIREBASE_DEFAULTS__ = {
156+
environment.getGlobal().__FIREBASE_DEFAULTS__ = {
108157
emulatorHosts: {
109158
firestore: '127.0.0.1:8080'
110159
}
@@ -121,7 +170,7 @@ describe('getDefaultEmulatorHostnameAndPort', () => {
121170

122171
context('with quoted IPv6 hostname in global config', () => {
123172
before(() => {
124-
getGlobal().__FIREBASE_DEFAULTS__ = {
173+
environment.getGlobal().__FIREBASE_DEFAULTS__ = {
125174
emulatorHosts: {
126175
firestore: '[::1]:8080'
127176
}

0 commit comments

Comments
 (0)