Skip to content

Commit 243afc0

Browse files
authored
Merge f0c797c into 4e6a5c6
2 parents 4e6a5c6 + f0c797c commit 243afc0

File tree

6 files changed

+87
-14
lines changed

6 files changed

+87
-14
lines changed

common/api-review/firestore-lite.api.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -494,4 +494,5 @@ export class WriteBatch {
494494
// @public
495495
export function writeBatch(firestore: Firestore): WriteBatch;
496496

497+
497498
```

packages/firestore/src/lite-api/database.ts

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import {
2424
} from '@firebase/app';
2525
import {
2626
createMockUserToken,
27+
deepEqual,
2728
EmulatorMockTokenOptions,
2829
getDefaultEmulatorHostnameAndPort
2930
} from '@firebase/util';
@@ -71,6 +72,9 @@ export class Firestore implements FirestoreService {
7172

7273
private _settings = new FirestoreSettingsImpl({});
7374
private _settingsFrozen = false;
75+
private _emulatorOptions: {
76+
mockUserToken?: EmulatorMockTokenOptions | string;
77+
} = {};
7478

7579
// A task that is assigned when the terminate() is invoked and resolved when
7680
// all components have shut down. Otherwise, Firestore is not terminated,
@@ -119,6 +123,8 @@ export class Firestore implements FirestoreService {
119123
);
120124
}
121125
this._settings = new FirestoreSettingsImpl(settings);
126+
this._emulatorOptions = settings.emulatorOptions || {};
127+
122128
if (settings.credentials !== undefined) {
123129
this._authCredentials = makeAuthCredentialsProvider(settings.credentials);
124130
}
@@ -128,6 +134,10 @@ export class Firestore implements FirestoreService {
128134
return this._settings;
129135
}
130136

137+
_getEmulatorOptions(): { mockUserToken?: EmulatorMockTokenOptions | string } {
138+
return this._emulatorOptions;
139+
}
140+
131141
_freezeSettings(): FirestoreSettingsImpl {
132142
this._settingsFrozen = true;
133143
return this._settings;
@@ -316,20 +326,30 @@ export function connectFirestoreEmulator(
316326
): void {
317327
firestore = cast(firestore, Firestore);
318328
const settings = firestore._getSettings();
329+
const existingConfig = {
330+
...settings,
331+
emulatorOptions: firestore._getEmulatorOptions()
332+
};
319333
const newHostSetting = `${host}:${port}`;
320-
321334
if (settings.host !== DEFAULT_HOST && settings.host !== newHostSetting) {
322335
logWarn(
323336
'Host has been set in both settings() and connectFirestoreEmulator(), emulator host ' +
324337
'will be used.'
325338
);
326339
}
327-
328-
firestore._setSettings({
340+
const newConfig = {
329341
...settings,
330342
host: newHostSetting,
331-
ssl: false
332-
});
343+
ssl: false,
344+
emulatorOptions: options
345+
};
346+
// No-op if the new configuration matches the current configuration. This supports SSR
347+
// enviornments which might call `connectFirestoreEmulator` multiple times as a standard practice.
348+
if (deepEqual(newConfig, existingConfig)) {
349+
return;
350+
}
351+
352+
firestore._setSettings(newConfig);
333353

334354
if (options.mockUserToken) {
335355
let token: string;

packages/firestore/src/lite-api/settings.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
* limitations under the License.
1616
*/
1717

18+
import { EmulatorMockTokenOptions } from '@firebase/util';
19+
1820
import { FirestoreLocalCache } from '../api/cache_config';
1921
import { CredentialsSettings } from '../api/credentials';
2022
import {
@@ -80,6 +82,7 @@ export interface PrivateSettings extends FirestoreSettings {
8082
experimentalAutoDetectLongPolling?: boolean;
8183
experimentalLongPollingOptions?: ExperimentalLongPollingOptions;
8284
useFetchStreams?: boolean;
85+
emulatorOptions?: { mockUserToken?: EmulatorMockTokenOptions | string };
8386

8487
localCache?: FirestoreLocalCache;
8588
}

packages/firestore/test/integration/api/validation.test.ts

Lines changed: 43 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,9 @@ import {
6464
import {
6565
ALT_PROJECT_ID,
6666
DEFAULT_PROJECT_ID,
67-
TARGET_DB_ID
67+
TARGET_DB_ID,
68+
USE_EMULATOR,
69+
getEmulatorPort
6870
} from '../util/settings';
6971

7072
// We're using 'as any' to pass invalid values to APIs for testing purposes.
@@ -179,7 +181,19 @@ apiDescribe('Validation:', persistence => {
179181

180182
validationIt(
181183
persistence,
182-
'disallows calling connectFirestoreEmulator() after use',
184+
'connectFirestoreEmulator() can set mockUserToken object',
185+
() => {
186+
const db = newTestFirestore(newTestApp('test-project'));
187+
// Verify that this doesn't throw.
188+
connectFirestoreEmulator(db, '127.0.0.1', 9000, {
189+
mockUserToken: { sub: 'foo' }
190+
});
191+
}
192+
);
193+
194+
validationIt(
195+
persistence,
196+
'disallows calling connectFirestoreEmulator() for first time after use',
183197
async db => {
184198
const errorMsg =
185199
'Firestore has already been started and its settings can no longer be changed.';
@@ -193,13 +207,33 @@ apiDescribe('Validation:', persistence => {
193207

194208
validationIt(
195209
persistence,
196-
'connectFirestoreEmulator() can set mockUserToken object',
197-
() => {
198-
const db = newTestFirestore(newTestApp('test-project'));
199-
// Verify that this doesn't throw.
200-
connectFirestoreEmulator(db, '127.0.0.1', 9000, {
201-
mockUserToken: { sub: 'foo' }
202-
});
210+
'allows calling connectFirestoreEmulator() after use with same config',
211+
async db => {
212+
if (USE_EMULATOR) {
213+
const port = getEmulatorPort();
214+
connectFirestoreEmulator(db, '127.0.0.1', port);
215+
await setDoc(doc(db, 'foo/bar'), {});
216+
expect(() =>
217+
connectFirestoreEmulator(db, '127.0.0.1', port)
218+
).to.not.throw();
219+
}
220+
}
221+
);
222+
223+
validationIt(
224+
persistence,
225+
'disallows calling connectFirestoreEmulator() after use with different config',
226+
async db => {
227+
if (USE_EMULATOR) {
228+
const errorMsg =
229+
'Firestore has already been started and its settings can no longer be changed.';
230+
const port = getEmulatorPort();
231+
connectFirestoreEmulator(db, '127.0.0.1', port);
232+
await setDoc(doc(db, 'foo/bar'), {});
233+
expect(() =>
234+
connectFirestoreEmulator(db, '127.0.0.1', port + 1)
235+
).to.throw(errorMsg);
236+
}
203237
}
204238
);
205239

packages/firestore/test/integration/util/settings.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,10 @@ function getFirestoreHost(targetBackend: TargetBackend): string {
110110
}
111111
}
112112

113+
export function getEmulatorPort(): number {
114+
return parseInt(process.env.FIRESTORE_EMULATOR_PORT || '8080', 10);
115+
}
116+
113117
function getSslEnabled(targetBackend: TargetBackend): boolean {
114118
return targetBackend !== TargetBackend.EMULATOR;
115119
}

packages/firestore/test/unit/api/database.test.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -553,6 +553,17 @@ describe('Settings', () => {
553553
expect(db._getSettings().ssl).to.be.false;
554554
});
555555

556+
it('gets privateSettings from useEmulator', () => {
557+
// Use a new instance of Firestore in order to configure settings.
558+
const db = newTestFirestore();
559+
const emulatorOptions = { mockUserToken: 'test' };
560+
connectFirestoreEmulator(db, '127.0.0.1', 9000, emulatorOptions);
561+
562+
expect(db._getSettings().host).to.exist.and.to.equal('127.0.0.1:9000');
563+
expect(db._getSettings().ssl).to.exist.and.to.be.false;
564+
expect(db._getEmulatorOptions()).to.equal(emulatorOptions);
565+
});
566+
556567
it('prefers host from useEmulator to host from settings', () => {
557568
// Use a new instance of Firestore in order to configure settings.
558569
const db = newTestFirestore();

0 commit comments

Comments
 (0)