Skip to content

Commit 00b3787

Browse files
authored
Merge c829d99 into 4e6a5c6
2 parents 4e6a5c6 + c829d99 commit 00b3787

File tree

3 files changed

+74
-9
lines changed

3 files changed

+74
-9
lines changed

.changeset/lemon-candles-vanish.md

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
'@firebase/auth': patch
3+
'firebase': patch
4+
---
5+
6+
Fixed: invoking `connectAuthEmulator` multiple times with the same parameters will no longer cause
7+
an error. Fixes [GitHub Issue #6824](https://github.com/firebase/firebase-js-sdk/issues/6824).
8+

packages/auth/src/core/auth/emulator.test.ts

+35
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,41 @@ describe('core/auth/emulator', () => {
7676
);
7777
});
7878

79+
it('passes with same config if a network request has already been made', async () => {
80+
expect(() => connectAuthEmulator(auth, 'http://127.0.0.1:2020')).to.not
81+
.throw;
82+
await user.delete();
83+
expect(() => connectAuthEmulator(auth, 'http://127.0.0.1:2020')).to.not
84+
.throw;
85+
});
86+
87+
it('fails with alternate config if a network request has already been made', async () => {
88+
expect(() => connectAuthEmulator(auth, 'http://127.0.0.1:2020')).to.not
89+
.throw;
90+
await user.delete();
91+
expect(() => connectAuthEmulator(auth, 'http://127.0.0.1:2021')).to.throw(
92+
FirebaseError,
93+
'auth/emulator-config-failed'
94+
);
95+
});
96+
97+
it('subsequent calls update the endpoint appropriately', async () => {
98+
connectAuthEmulator(auth, 'http://127.0.0.1:2021');
99+
expect(auth.emulatorConfig).to.eql({
100+
protocol: 'http',
101+
host: '127.0.0.1',
102+
port: 2021,
103+
options: { disableWarnings: false }
104+
});
105+
connectAuthEmulator(auth, 'http://127.0.0.1:2020');
106+
expect(auth.emulatorConfig).to.eql({
107+
protocol: 'http',
108+
host: '127.0.0.1',
109+
port: 2020,
110+
options: { disableWarnings: false }
111+
});
112+
});
113+
79114
it('updates the endpoint appropriately', async () => {
80115
connectAuthEmulator(auth, 'http://127.0.0.1:2020');
81116
await user.delete();

packages/auth/src/core/auth/emulator.ts

+31-9
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import { Auth } from '../../model/public_types';
1818
import { AuthErrorCode } from '../errors';
1919
import { _assert } from '../util/assert';
2020
import { _castAuth } from './auth_impl';
21+
import { deepEqual } from '@firebase/util';
2122

2223
/**
2324
* Changes the {@link Auth} instance to communicate with the Firebase Auth Emulator, instead of production
@@ -47,12 +48,6 @@ export function connectAuthEmulator(
4748
options?: { disableWarnings: boolean }
4849
): void {
4950
const authInternal = _castAuth(auth);
50-
_assert(
51-
authInternal._canInitEmulator,
52-
authInternal,
53-
AuthErrorCode.EMULATOR_CONFIG_FAILED
54-
);
55-
5651
_assert(
5752
/^https?:\/\//.test(url),
5853
authInternal,
@@ -66,15 +61,42 @@ export function connectAuthEmulator(
6661
const portStr = port === null ? '' : `:${port}`;
6762

6863
// Always replace path with "/" (even if input url had no path at all, or had a different one).
69-
authInternal.config.emulator = { url: `${protocol}//${host}${portStr}/` };
70-
authInternal.settings.appVerificationDisabledForTesting = true;
71-
authInternal.emulatorConfig = Object.freeze({
64+
const emulator = { url: `${protocol}//${host}${portStr}/` };
65+
const emulatorConfig = Object.freeze({
7266
host,
7367
port,
7468
protocol: protocol.replace(':', ''),
7569
options: Object.freeze({ disableWarnings })
7670
});
7771

72+
// There are a few scenarios to guard against if the Auth instance has already started:
73+
if (!authInternal._canInitEmulator) {
74+
// Applications may not initialize the emulator for the first time if Auth has already started
75+
// to make network requests.
76+
_assert(
77+
authInternal.config.emulator && authInternal.emulatorConfig,
78+
authInternal,
79+
AuthErrorCode.EMULATOR_CONFIG_FAILED
80+
);
81+
82+
// Applications may not alter the configuration of the emulator (aka pass a different config)
83+
// once Auth has started to make network requests.
84+
_assert(
85+
deepEqual(emulator, authInternal.config.emulator) &&
86+
deepEqual(emulatorConfig, authInternal.emulatorConfig),
87+
authInternal,
88+
AuthErrorCode.EMULATOR_CONFIG_FAILED
89+
);
90+
91+
// It's valid, however, to invoke connectAuthEmulator() after Auth has started making
92+
// connections, so long as the config matches the existing config. This results in a no-op.
93+
return;
94+
}
95+
96+
authInternal.config.emulator = emulator;
97+
authInternal.emulatorConfig = emulatorConfig;
98+
authInternal.settings.appVerificationDisabledForTesting = true;
99+
78100
if (!disableWarnings) {
79101
emitEmulatorWarning();
80102
}

0 commit comments

Comments
 (0)