Skip to content

Commit 92a7f43

Browse files
authored
Expose emulator config for the Auth SDK (#4280)
* Add emulator config export to the auth package * Formatting * Add changeset * Update externs * Formatting
1 parent 204fbcf commit 92a7f43

File tree

6 files changed

+204
-71
lines changed

6 files changed

+204
-71
lines changed

.changeset/wet-badgers-nail.md

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"@firebase/auth": patch
3+
"firebase": patch
4+
---
5+
6+
Add the `useEmulator()` function and `emulatorConfig` to the `firebase` package externs

packages/auth/src/auth.js

+28-3
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@ fireauth.Auth.prototype.useEmulator = function(url, options) {
309309
const disableBanner = options ? !!options['disableWarnings'] : false;
310310
this.emitEmulatorWarning_(disableBanner);
311311
// Persist the config.
312-
this.emulatorConfig_ = { url };
312+
this.emulatorConfig_ = {url, disableWarnings: disableBanner};
313313
// Disable app verification.
314314
this.settings_().setAppVerificationDisabledForTesting(true);
315315
// Update RPC handler endpoints.
@@ -353,10 +353,22 @@ fireauth.Auth.prototype.emitEmulatorWarning_ = function(disableBanner) {
353353

354354

355355
/**
356-
* @return {?fireauth.constants.EmulatorSettings}
356+
* @return {?fireauth.constants.EmulatorConfig}
357357
*/
358358
fireauth.Auth.prototype.getEmulatorConfig = function() {
359-
return this.emulatorConfig_;
359+
if (!this.emulatorConfig_) {
360+
return null;
361+
}
362+
const uri = goog.Uri.parse(this.emulatorConfig_.url);
363+
return /** @type {!fireauth.constants.EmulatorConfig} */ (
364+
fireauth.object.makeReadonlyCopy({
365+
'protocol': uri.getScheme(),
366+
'host': uri.getDomain(),
367+
'port': uri.getPort(),
368+
'options': fireauth.object.makeReadonlyCopy({
369+
'disableWarnings': this.emulatorConfig_.disableWarnings,
370+
}),
371+
}));
360372
}
361373

362374

@@ -470,6 +482,19 @@ fireauth.Auth.prototype.initializeReadableWritableProps_ = function() {
470482
// Initialize to null.
471483
/** @private {?string} The current Auth instance's tenant ID. */
472484
this.tenantId_ = null;
485+
486+
// Add the emulator configuration property (readonly).
487+
Object.defineProperty(/** @type {!Object} */ (this), 'emulatorConfig', {
488+
/**
489+
* @this {!Object}
490+
* @return {?fireauth.constants.EmulatorConfig} The emulator config if
491+
* enabled.
492+
*/
493+
get: function() {
494+
return this.getEmulatorConfig();
495+
},
496+
enumerable: false
497+
});
473498
};
474499

475500

packages/auth/src/defines.js

+25-1
Original file line numberDiff line numberDiff line change
@@ -173,9 +173,33 @@ fireauth.constants.OIDC_PREFIX = 'oidc.';
173173
* The settings of an Auth emulator. The fields are:
174174
* <ul>
175175
* <li>url: defines the URL where the emulator is running.</li>
176+
* <li>disableWarnings: if true, banner is not shown on the page.</li>
176177
* </ul>
177178
* @typedef {{
178179
* url: string,
180+
* disableWarnings: boolean,
179181
* }}
180182
*/
181-
fireauth.constants.EmulatorSettings;
183+
fireauth.constants.EmulatorSettings;
184+
185+
186+
/**
187+
* The (externally visible) emulator configuration, used for
188+
* getEmulatorConfig(). The fields are:
189+
* <ul>
190+
* <li>protocol: the protocol used by the emulator (http or https).</li>
191+
* <li>host: the host used to reach the emulator.</li>
192+
* <li>port: the port used to reach the emulator.</li>
193+
* <li>options: a list of options used to configure the SDK's interaction with
194+
* the emulator.</li>
195+
* </ul>
196+
* @typedef {{
197+
* protocol: string,
198+
* host: string,
199+
* port: (number|null),
200+
* options: {
201+
* disableWarnings: boolean,
202+
* }
203+
* }}
204+
*/
205+
fireauth.constants.EmulatorConfig;

packages/auth/src/exports_auth.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,9 @@ fireauth.exportlib.exportPrototypeProperties(
225225
fireauth.args.string(),
226226
fireauth.args.null(),
227227
'tenantId')
228-
}
228+
},
229+
// emulatorConfig is omitted here as it is readonly and therefore does not
230+
// need argument validation.
229231
});
230232

231233
// Exports firebase.auth.Auth.Persistence.

packages/auth/test/auth_test.js

+101-66
Original file line numberDiff line numberDiff line change
@@ -952,15 +952,19 @@ function testUseEmulator() {
952952
auth1.useEmulator('http://emulator.test.domain:1234');
953953
assertObjectEquals(
954954
{
955-
url: 'http://emulator.test.domain:1234',
955+
protocol: 'http',
956+
host: 'emulator.test.domain',
957+
port: 1234,
958+
options: {disableWarnings: false},
956959
},
957-
auth1.getEmulatorConfig());
960+
auth1.emulatorConfig);
958961
// Should notify the RPC handler.
959962
assertEquals(
960963
1, fireauth.RpcHandler.prototype.updateEmulatorConfig.getCallCount());
961964
assertObjectEquals(
962965
{
963966
url: 'http://emulator.test.domain:1234',
967+
disableWarnings: false,
964968
},
965969
fireauth.RpcHandler.prototype.updateEmulatorConfig.getLastCall()
966970
.getArgument(0)
@@ -986,9 +990,12 @@ function testUseEmulator() {
986990
auth1.useEmulator('http://emulator.test.domain:1234');
987991
assertObjectEquals(
988992
{
989-
url: 'http://emulator.test.domain:1234',
993+
protocol: 'http',
994+
host: 'emulator.test.domain',
995+
port: 1234,
996+
options: {disableWarnings: false},
990997
},
991-
auth1.getEmulatorConfig());
998+
auth1.emulatorConfig);
992999
assertEquals(
9931000
1, fireauth.RpcHandler.prototype.updateEmulatorConfig.getCallCount());
9941001
assertEquals(1, fireauth.util.consoleInfo.getCallCount());
@@ -997,9 +1004,12 @@ function testUseEmulator() {
9971004
auth1.useEmulator('http://emulator.other.domain:9876');
9981005
assertObjectEquals(
9991006
{
1000-
url: 'http://emulator.test.domain:1234',
1007+
protocol: 'http',
1008+
host: 'emulator.test.domain',
1009+
port: 1234,
1010+
options: {disableWarnings: false},
10011011
},
1002-
auth1.getEmulatorConfig());
1012+
auth1.emulatorConfig);
10031013
assertEquals(
10041014
1, fireauth.RpcHandler.prototype.updateEmulatorConfig.getCallCount());
10051015
}
@@ -1030,16 +1040,20 @@ function testUseEmulator_withDisableWarnings() {
10301040
auth1.useEmulator(
10311041
'http://emulator.test.domain:1234', {disableWarnings: true});
10321042
assertObjectEquals(
1033-
{
1034-
url: 'http://emulator.test.domain:1234',
1035-
},
1036-
auth1.getEmulatorConfig());
1043+
{
1044+
protocol: 'http',
1045+
host: 'emulator.test.domain',
1046+
port: 1234,
1047+
options: {disableWarnings: true},
1048+
},
1049+
auth1.emulatorConfig);
10371050
// Should notify the RPC handler.
10381051
assertEquals(
10391052
1, fireauth.RpcHandler.prototype.updateEmulatorConfig.getCallCount());
10401053
assertObjectEquals(
10411054
{
10421055
url: 'http://emulator.test.domain:1234',
1056+
disableWarnings: true,
10431057
},
10441058
fireauth.RpcHandler.prototype.updateEmulatorConfig.getLastCall()
10451059
.getArgument(0));
@@ -1057,6 +1071,76 @@ function testUseEmulator_withDisableWarnings() {
10571071
}
10581072

10591073

1074+
function testEmulatorConfig() {
1075+
app1 = firebase.initializeApp(config1, appId1);
1076+
auth1 = app1.auth();
1077+
1078+
// Update the emulator config.
1079+
auth1.useEmulator(
1080+
'http://emulator.test.domain:1234', {disableWarnings: true});
1081+
assertObjectEquals(
1082+
{
1083+
protocol: 'http',
1084+
host: 'emulator.test.domain',
1085+
port: 1234,
1086+
options: {disableWarnings: true},
1087+
},
1088+
auth1.emulatorConfig);
1089+
}
1090+
1091+
1092+
/**
1093+
* Asserts that the port is correctly set to null if no port supplied.
1094+
*/
1095+
function testEmulatorConfig_noPortSpecified() {
1096+
app1 = firebase.initializeApp(config1, appId1);
1097+
auth1 = app1.auth();
1098+
1099+
// Update the emulator config.
1100+
auth1.useEmulator('http://emulator.test.domain');
1101+
assertObjectEquals(
1102+
{
1103+
protocol: 'http',
1104+
host: 'emulator.test.domain',
1105+
port: null,
1106+
options: {disableWarnings: false},
1107+
},
1108+
auth1.emulatorConfig);
1109+
}
1110+
1111+
1112+
/**
1113+
* Asserts that the port is correctly assigned 0 if specifically set to 0 for
1114+
* some reason. Also checks https protocol.
1115+
*/
1116+
function testEmulatorConfig_portZeroAndHttpsSpecified() {
1117+
app1 = firebase.initializeApp(config1, appId1);
1118+
auth1 = app1.auth();
1119+
1120+
// Update the emulator config.
1121+
auth1.useEmulator('https://emulator.test.domain:0');
1122+
assertObjectEquals(
1123+
{
1124+
protocol: 'https',
1125+
host: 'emulator.test.domain',
1126+
port: 0,
1127+
options: {disableWarnings: false},
1128+
},
1129+
auth1.emulatorConfig);
1130+
}
1131+
1132+
1133+
/**
1134+
* Asserts that the function returns null if useEmulator is not called.
1135+
*/
1136+
function testEmulatorConfig_nullIfNoEmulatorConfig() {
1137+
app1 = firebase.initializeApp(config1, appId1);
1138+
auth1 = app1.auth();
1139+
1140+
assertNull(auth1.emulatorConfig);
1141+
}
1142+
1143+
10601144
function testGetSetTenantId() {
10611145
app1 = firebase.initializeApp(config1, appId1);
10621146
auth1 = app1.auth();
@@ -2317,59 +2401,6 @@ function testAuth_authEventManager() {
23172401
}
23182402

23192403

2320-
function testAuth_authEventManager_withEmulator() {
2321-
// Test Auth event manager.
2322-
fireauth.AuthEventManager.ENABLED = true;
2323-
stubs.reset();
2324-
initializeMockStorage();
2325-
var expectedManager = {
2326-
'subscribe': goog.testing.recordFunction(),
2327-
'unsubscribe': goog.testing.recordFunction(),
2328-
'clearRedirectResult': goog.testing.recordFunction()
2329-
};
2330-
// Return stub manager.
2331-
stubs.replace(
2332-
fireauth.AuthEventManager,
2333-
'getManager',
2334-
function (authDomain, apiKey, appName, emulatorConfig) {
2335-
assertEquals('subdomain.firebaseapp.com', authDomain);
2336-
assertEquals('API_KEY', apiKey);
2337-
assertEquals(appId1, appName);
2338-
assertObjectEquals(emulatorConfig, {
2339-
url: 'http://emulator.test.domain:1234'
2340-
});
2341-
return expectedManager;
2342-
});
2343-
asyncTestCase.waitForSignals(1);
2344-
app1 = firebase.initializeApp(config3, appId1);
2345-
auth1 = app1.auth();
2346-
auth1.useEmulator('http://emulator.test.domain:1234');
2347-
// Test manager initialized and Auth subscribed.
2348-
auth1.onIdTokenChanged(function (user) {
2349-
var manager = fireauth.AuthEventManager.getManager(
2350-
config3['authDomain'], config3['apiKey'], app1.name, {
2351-
url: 'http://emulator.test.domain:1234',
2352-
});
2353-
assertEquals(expectedManager, manager);
2354-
assertEquals(0, expectedManager.unsubscribe.getCallCount());
2355-
assertEquals(1, expectedManager.subscribe.getCallCount());
2356-
assertEquals(
2357-
auth1, expectedManager.subscribe.getLastCall().getArgument(0));
2358-
assertEquals(0, expectedManager.clearRedirectResult.getCallCount());
2359-
// Delete should trigger unsubscribe and redirect result clearing.
2360-
auth1.delete();
2361-
// After destroy, Auth should be unsubscribed.
2362-
assertEquals(1, expectedManager.subscribe.getCallCount());
2363-
assertEquals(1, expectedManager.unsubscribe.getCallCount());
2364-
// Redirect result should also be cleared.
2365-
assertEquals(1, expectedManager.clearRedirectResult.getCallCount());
2366-
assertEquals(
2367-
auth1, expectedManager.unsubscribe.getLastCall().getArgument(0));
2368-
asyncTestCase.signal();
2369-
});
2370-
}
2371-
2372-
23732404
/** Asserts that AuthEventManager can pass through emulator settings. */
23742405
function testAuth_authEventManager_withEmulator() {
23752406
// Test Auth event manager.
@@ -2390,7 +2421,8 @@ function testAuth_authEventManager_withEmulator() {
23902421
assertEquals('API_KEY', apiKey);
23912422
assertEquals(appId1, appName);
23922423
assertObjectEquals(emulatorConfig, {
2393-
url: 'http://emulator.host:1234'
2424+
url: 'http://emulator.host:1234',
2425+
disableWarnings: false,
23942426
});
23952427
return expectedManager;
23962428
});
@@ -2402,7 +2434,8 @@ function testAuth_authEventManager_withEmulator() {
24022434
auth1.onIdTokenChanged(function (user) {
24032435
var manager = fireauth.AuthEventManager.getManager(
24042436
config3['authDomain'], config3['apiKey'], app1.name, {
2405-
url: 'http://emulator.host:1234'
2437+
url: 'http://emulator.host:1234',
2438+
disableWarnings: false,
24062439
});
24072440
assertEquals(expectedManager, manager);
24082441
assertEquals(0, expectedManager.unsubscribe.getCallCount());
@@ -2667,7 +2700,8 @@ function testAuth_initState_signedInStatus_withEmulator() {
26672700
.getThis());
26682701
assertObjectEquals(
26692702
{
2670-
url: 'http://emulator.test.domain:1234'
2703+
url: 'http://emulator.test.domain:1234',
2704+
disableWarnings: false,
26712705
},
26722706
fireauth.RpcHandler.prototype.updateEmulatorConfig.getLastCall()
26732707
.getArgument(0));
@@ -4526,6 +4560,7 @@ function testAuth_signInWithIdTokenResponse_withEmulator() {
45264560
var expectedOptions = Object.assign({}, config3);
45274561
expectedOptions['emulatorConfig'] = {
45284562
url: 'http://emulator.test.domain:1234',
4563+
disableWarnings: false,
45294564
};
45304565
// The newly signed in user.
45314566
var user1 = new fireauth.AuthUser(

0 commit comments

Comments
 (0)