Skip to content

Commit c0d0abd

Browse files
committed
Implement useEmulator for Firestore
1 parent f5d122a commit c0d0abd

File tree

7 files changed

+93
-1
lines changed

7 files changed

+93
-1
lines changed

.changeset/clever-eyes-glow.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@firebase/firestore': minor
3+
'@firebase/firestore-types': minor
4+
---
5+
6+
Add a useEmulator(host, port) method

packages/firebase/index.d.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8043,6 +8043,16 @@ declare namespace firebase.firestore {
80438043
*/
80448044
settings(settings: Settings): void;
80458045

8046+
/**
8047+
* Modify this instance to communicate with the Cloud Firestore emulator.
8048+
*
8049+
* <p>Note: this must be called before this instance has been used to do any operations.
8050+
*
8051+
* @param host the emulator host (ex: localhost).
8052+
* @param port the emulator port (ex: 9000).
8053+
*/
8054+
useEmulator(host: string, port: number): void;
8055+
80468056
/**
80478057
* Attempts to enable persistent storage, if possible.
80488058
*

packages/firestore-types/index.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ export class FirebaseFirestore {
6161

6262
settings(settings: Settings): void;
6363

64+
useEmulator(host: string, port: number): void;
65+
6466
enablePersistence(settings?: PersistenceSettings): Promise<void>;
6567

6668
collection(collectionPath: string): CollectionReference<DocumentData>;

packages/firestore/exp/test/shim.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,10 @@ export class FirebaseFirestore
9999
initializeFirestore(this.app._delegate, settings);
100100
}
101101

102+
useEmulator(host: string, port: number) {
103+
this.settings({ host: `${host}:${port}`, ssl: false, merge: true });
104+
}
105+
102106
enablePersistence(settings?: legacy.PersistenceSettings): Promise<void> {
103107
return settings?.synchronizeTabs
104108
? enableMultiTabIndexedDbPersistence(this._delegate)

packages/firestore/src/api/database.ts

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,13 @@ import {
108108
validateStringEnum,
109109
valueDescription
110110
} from '../util/input_validation';
111-
import { getLogLevel, logError, LogLevel, setLogLevel } from '../util/log';
111+
import {
112+
getLogLevel,
113+
logError,
114+
LogLevel,
115+
setLogLevel,
116+
logWarn
117+
} from '../util/log';
112118
import { AutoId } from '../util/misc';
113119
import { Deferred } from '../util/promise';
114120
import { FieldPath as ExternalFieldPath } from './field_path';
@@ -413,6 +419,32 @@ export class Firestore implements PublicFirestore, FirebaseService {
413419
}
414420
}
415421

422+
useEmulator(host: string, port: number) {
423+
validateExactNumberOfArgs('Firestore.useEmulator', arguments, 2);
424+
validateArgType('Firestore.useEmulator', 'string', 1, host);
425+
validateArgType('Firestore.useEmulator', 'number', 2, port);
426+
427+
if (this._firestoreClient) {
428+
throw new FirestoreError(
429+
Code.FAILED_PRECONDITION,
430+
'Firestore hass already been started and its settings can no longer be changed. ' +
431+
'You can only call useEmulator() before calling any other methods on a Firestore object.'
432+
);
433+
}
434+
435+
if (this._settings.host !== DEFAULT_HOST) {
436+
logWarn(
437+
'Host has been set in both settings() and useEmulator(), emulator host will be used'
438+
);
439+
}
440+
441+
this.settings({
442+
host: `${host}:${port}`,
443+
ssl: false,
444+
merge: true
445+
});
446+
}
447+
416448
enableNetwork(): Promise<void> {
417449
this.ensureClientConfigured();
418450
return this._firestoreClient!.enableNetwork();

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

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,25 @@ apiDescribe('Validation:', (persistence: boolean) => {
182182
// Verify that this doesn't throw.
183183
db.settings({ cacheSizeBytes: /* CACHE_SIZE_UNLIMITED= */ -1 });
184184
});
185+
186+
validationIt(persistence, 'useEmulator can set host and port', () => {
187+
const db = newTestFirestore('test-project');
188+
// Verify that this doesn't throw.
189+
db.useEmulator('localhost', 9000);
190+
});
191+
192+
validationIt(
193+
persistence,
194+
'disallows calling useEmulator after use',
195+
async db => {
196+
const errorMsg =
197+
'Firestore hass already been started and its settings can no longer be changed. ' +
198+
'You can only call useEmulator() before calling any other methods on a Firestore object.';
199+
200+
await db.doc('foo/bar').set({});
201+
expect(() => db.useEmulator('localhost', 9000)).to.throw(errorMsg);
202+
}
203+
);
185204
});
186205

187206
describe('Firestore', () => {

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

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,4 +182,23 @@ describe('Settings', () => {
182182
expect(firestoreClient._getSettings().ignoreUndefinedProperties).to.be.true;
183183
expect(firestoreClient._getSettings().host).to.equal('other.host');
184184
});
185+
186+
it('gets settings from useEmulator', () => {
187+
// Use a new instance of Firestore in order to configure settings.
188+
const firestoreClient = newTestFirestore();
189+
firestoreClient.useEmulator('localhost', 9000);
190+
191+
expect(firestoreClient._getSettings().host).to.equal('localhost:9000');
192+
expect(firestoreClient._getSettings().ssl).to.be.false;
193+
});
194+
195+
it('prefers host from useEmulator to host from settings', () => {
196+
// Use a new instance of Firestore in order to configure settings.
197+
const firestoreClient = newTestFirestore();
198+
firestoreClient.settings({ host: 'other.host' });
199+
firestoreClient.useEmulator('localhost', 9000);
200+
201+
expect(firestoreClient._getSettings().host).to.equal('localhost:9000');
202+
expect(firestoreClient._getSettings().ssl).to.be.false;
203+
});
185204
});

0 commit comments

Comments
 (0)