@firebase/rules-unit-testing 1.3.15-canary.cdada6c68 → 1.3.16-2022028193537

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs.js CHANGED
@@ -2,16 +2,39 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- var fetch = require('node-fetch');
6
- var firebase = require('firebase/compat/app');
7
- require('firebase/firestore/compat');
8
- require('firebase/database/compat');
9
- require('firebase/storage/compat');
5
+ var firebase = require('firebase');
6
+ require('firebase/database');
7
+ require('firebase/firestore');
8
+ require('firebase/storage');
9
+ var request = require('request');
10
+ var logger = require('@firebase/logger');
11
+ var component = require('@firebase/component');
12
+ var util = require('@firebase/util');
10
13
 
11
14
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
12
15
 
13
- var fetch__default = /*#__PURE__*/_interopDefaultLegacy(fetch);
16
+ function _interopNamespace(e) {
17
+ if (e && e.__esModule) return e;
18
+ var n = Object.create(null);
19
+ if (e) {
20
+ Object.keys(e).forEach(function (k) {
21
+ if (k !== 'default') {
22
+ var d = Object.getOwnPropertyDescriptor(e, k);
23
+ Object.defineProperty(n, k, d.get ? d : {
24
+ enumerable: true,
25
+ get: function () {
26
+ return e[k];
27
+ }
28
+ });
29
+ }
30
+ });
31
+ }
32
+ n['default'] = e;
33
+ return Object.freeze(n);
34
+ }
35
+
14
36
  var firebase__default = /*#__PURE__*/_interopDefaultLegacy(firebase);
37
+ var request__namespace = /*#__PURE__*/_interopNamespace(request);
15
38
 
16
39
  /*! *****************************************************************************
17
40
  Copyright (c) Microsoft Corporation.
@@ -79,7 +102,7 @@ function __generator(thisArg, body) {
79
102
 
80
103
  /**
81
104
  * @license
82
- * Copyright 2021 Google LLC
105
+ * Copyright 2018 Google LLC
83
106
  *
84
107
  * Licensed under the Apache License, Version 2.0 (the "License");
85
108
  * you may not use this file except in compliance with the License.
@@ -93,643 +116,461 @@ function __generator(thisArg, body) {
93
116
  * See the License for the specific language governing permissions and
94
117
  * limitations under the License.
95
118
  */
96
- /**
97
- * Return a connectable hostname, replacing wildcard 0.0.0.0 or :: with loopback
98
- * addresses 127.0.0.1 / ::1 correspondingly. See below for why this is needed:
99
- * https://github.com/firebase/firebase-tools-ui/issues/286
100
- *
101
- * This assumes emulators are running on the same device as fallbackHost (e.g.
102
- * hub), which should hold if both are started from the same CLI command.
103
- * @private
104
- */
105
- function fixHostname(host, fallbackHost) {
106
- host = host.replace('[', '').replace(']', ''); // Remove IPv6 brackets
107
- if (host === '0.0.0.0') {
108
- host = fallbackHost || '127.0.0.1';
119
+ var firestore = firebase__default['default'].firestore, database = firebase__default['default'].database; firebase__default['default'].storage;
120
+ /** If this environment variable is set, use it for the database emulator's address. */
121
+ var DATABASE_ADDRESS_ENV = 'FIREBASE_DATABASE_EMULATOR_HOST';
122
+ /** The default address for the local database emulator. */
123
+ var DATABASE_ADDRESS_DEFAULT = 'localhost:9000';
124
+ /** If this environment variable is set, use it for the Firestore emulator. */
125
+ var FIRESTORE_ADDRESS_ENV = 'FIRESTORE_EMULATOR_HOST';
126
+ /** The default address for the local Firestore emulator. */
127
+ var FIRESTORE_ADDRESS_DEFAULT = 'localhost:8080';
128
+ /** If this environment variable is set, use it for the Storage emulator. */
129
+ var FIREBASE_STORAGE_ADDRESS_ENV = 'FIREBASE_STORAGE_EMULATOR_HOST';
130
+ var CLOUD_STORAGE_ADDRESS_ENV = 'STORAGE_EMULATOR_HOST';
131
+ /** The default address for the local Firestore emulator. */
132
+ var STORAGE_ADDRESS_DEFAULT = 'localhost:9199';
133
+ /** Environment variable to locate the Emulator Hub */
134
+ var HUB_HOST_ENV = 'FIREBASE_EMULATOR_HUB';
135
+ /** The default address for the Emulator Hub */
136
+ var HUB_HOST_DEFAULT = 'localhost:4400';
137
+ /** The actual address for the database emulator */
138
+ var _databaseHost = undefined;
139
+ /** The actual address for the Firestore emulator */
140
+ var _firestoreHost = undefined;
141
+ /** The actual address for the Storage emulator */
142
+ var _storageHost = undefined;
143
+ /** The actual address for the Emulator Hub */
144
+ var _hubHost = undefined;
145
+ function trimmedBase64Encode(val) {
146
+ // Use base64url encoding and remove padding in the end (dot characters).
147
+ return util.base64Encode(val).replace(/\./g, "");
148
+ }
149
+ function createUnsecuredJwt(token, projectId) {
150
+ // Unsecured JWTs use "none" as the algorithm.
151
+ var header = {
152
+ alg: 'none',
153
+ kid: 'fakekid',
154
+ type: 'JWT'
155
+ };
156
+ var project = projectId || 'fake-project';
157
+ var iat = token.iat || 0;
158
+ var uid = token.sub || token.uid || token.user_id;
159
+ if (!uid) {
160
+ throw new Error("Auth must contain 'sub', 'uid', or 'user_id' field!");
109
161
  }
110
- else if (host === '::') {
111
- host = fallbackHost || '::1';
162
+ var payload = __assign({
163
+ // Set all required fields to decent defaults
164
+ iss: "https://securetoken.google.com/" + project, aud: project, iat: iat, exp: iat + 3600, auth_time: iat, sub: uid, user_id: uid, firebase: {
165
+ sign_in_provider: 'custom',
166
+ identities: {}
167
+ } }, token);
168
+ // Remove the uid option since it's not actually part of the token spec.
169
+ if (payload.uid) {
170
+ delete payload.uid;
112
171
  }
113
- return host;
172
+ // Unsecured JWTs use the empty string as a signature.
173
+ var signature = '';
174
+ return [
175
+ trimmedBase64Encode(JSON.stringify(header)),
176
+ trimmedBase64Encode(JSON.stringify(payload)),
177
+ signature
178
+ ].join('.');
114
179
  }
115
- /**
116
- * Create a URL with host, port, and path. Handles IPv6 bracketing correctly.
117
- * @private
118
- */
119
- function makeUrl(hostAndPort, path) {
120
- if (typeof hostAndPort === 'object') {
121
- var host = hostAndPort.host, port = hostAndPort.port;
122
- if (host.includes(':')) {
123
- hostAndPort = "[" + host + "]:" + port;
124
- }
125
- else {
126
- hostAndPort = host + ":" + port;
127
- }
180
+ function apps() {
181
+ return firebase__default['default'].apps;
182
+ }
183
+ /** Construct an App authenticated with options.auth. */
184
+ function initializeTestApp(options) {
185
+ var jwt = options.auth
186
+ ? createUnsecuredJwt(options.auth, options.projectId)
187
+ : undefined;
188
+ return initializeApp(jwt, options.databaseName, options.projectId, options.storageBucket);
189
+ }
190
+ /** Construct an App authenticated as an admin user. */
191
+ function initializeAdminApp(options) {
192
+ var admin = require('firebase-admin');
193
+ var app = admin.initializeApp(getAppOptions(options.databaseName, options.projectId, options.storageBucket), getRandomAppName());
194
+ if (options.projectId) {
195
+ app.firestore().settings({
196
+ host: getFirestoreHost(),
197
+ ssl: false
198
+ });
128
199
  }
129
- var url = new URL("http://" + hostAndPort + "/");
130
- url.pathname = path;
131
- return url;
132
- }
133
-
200
+ return app;
201
+ }
134
202
  /**
135
- * @license
136
- * Copyright 2021 Google LLC
137
- *
138
- * Licensed under the Apache License, Version 2.0 (the "License");
139
- * you may not use this file except in compliance with the License.
140
- * You may obtain a copy of the License at
141
- *
142
- * http://www.apache.org/licenses/LICENSE-2.0
203
+ * Set the host and port configuration for applicable emulators. This will override any values
204
+ * found in environment variables. Must be called before initializeAdminApp or initializeTestApp.
143
205
  *
144
- * Unless required by applicable law or agreed to in writing, software
145
- * distributed under the License is distributed on an "AS IS" BASIS,
146
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
147
- * See the License for the specific language governing permissions and
148
- * limitations under the License.
206
+ * @param options options object.
149
207
  */
208
+ function useEmulators(options) {
209
+ if (!(options.database || options.firestore || options.storage || options.hub)) {
210
+ throw new Error("Argument to useEmulators must contain at least one of 'database', 'firestore', 'storage', or 'hub'.");
211
+ }
212
+ if (options.database) {
213
+ _databaseHost = getAddress(options.database.host, options.database.port);
214
+ }
215
+ if (options.firestore) {
216
+ _firestoreHost = getAddress(options.firestore.host, options.firestore.port);
217
+ }
218
+ if (options.storage) {
219
+ _storageHost = getAddress(options.storage.host, options.storage.port);
220
+ }
221
+ if (options.hub) {
222
+ _hubHost = getAddress(options.hub.host, options.hub.port);
223
+ }
224
+ }
150
225
  /**
151
- * Use the Firebase Emulator hub to discover other running emulators.
226
+ * Use the Firebase Emulator hub to discover other running emulators. Call useEmulators() with
227
+ * the result to configure the library to use the discovered emulators.
152
228
  *
153
- * @param hub the host and port where the Emulator Hub is running
154
- * @private
229
+ * @param hubHost the host where the Emulator Hub is running (ex: 'localhost')
230
+ * @param hubPort the port where the Emulator Hub is running (ex: 4400)
155
231
  */
156
- function discoverEmulators(hub, fetch) {
157
- if (fetch === void 0) { fetch = fetch__default['default']; }
232
+ function discoverEmulators(hubHost, hubPort) {
158
233
  return __awaiter(this, void 0, void 0, function () {
159
- var res, emulators, data;
234
+ var hubAddress, res, options, data;
160
235
  return __generator(this, function (_a) {
161
236
  switch (_a.label) {
162
- case 0: return [4 /*yield*/, fetch(makeUrl(hub, '/emulators'))];
237
+ case 0:
238
+ if ((hubHost && !hubPort) || (!hubHost && hubPort)) {
239
+ throw new Error("Invalid configuration hubHost=" + hubHost + " and hubPort=" + hubPort + ". If either parameter is supplied, both must be defined.");
240
+ }
241
+ hubAddress = hubHost && hubPort ? getAddress(hubHost, hubPort) : getHubHost();
242
+ return [4 /*yield*/, requestPromise(request__namespace.get, {
243
+ method: 'GET',
244
+ uri: "http://" + hubAddress + "/emulators"
245
+ })];
163
246
  case 1:
164
247
  res = _a.sent();
165
- if (!res.ok) {
166
- throw new Error("HTTP Error " + res.status + " when attempting to reach Emulator Hub at " + res.url + ", are you sure it is running?");
248
+ if (res.statusCode !== 200) {
249
+ throw new Error("HTTP Error " + res.statusCode + " when attempting to reach Emulator Hub at " + hubAddress + ", are you sure it is running?");
167
250
  }
168
- emulators = {};
169
- return [4 /*yield*/, res.json()];
170
- case 2:
171
- data = _a.sent();
251
+ options = {};
252
+ data = JSON.parse(res.body);
172
253
  if (data.database) {
173
- emulators.database = {
254
+ options.database = {
174
255
  host: data.database.host,
175
256
  port: data.database.port
176
257
  };
177
258
  }
178
259
  if (data.firestore) {
179
- emulators.firestore = {
260
+ options.firestore = {
180
261
  host: data.firestore.host,
181
262
  port: data.firestore.port
182
263
  };
183
264
  }
184
265
  if (data.storage) {
185
- emulators.storage = {
266
+ options.storage = {
186
267
  host: data.storage.host,
187
268
  port: data.storage.port
188
269
  };
189
270
  }
190
271
  if (data.hub) {
191
- emulators.hub = {
272
+ options.hub = {
192
273
  host: data.hub.host,
193
274
  port: data.hub.port
194
275
  };
195
276
  }
196
- return [2 /*return*/, emulators];
277
+ return [2 /*return*/, options];
197
278
  }
198
279
  });
199
280
  });
200
281
  }
201
- /**
202
- * @private
203
- */
204
- function getEmulatorHostAndPort(emulator, conf, discovered) {
205
- var _a, _b;
206
- if (conf && ('host' in conf || 'port' in conf)) {
207
- var host = conf.host, port = conf.port;
208
- if (host || port) {
209
- if (!host || !port) {
210
- throw new Error("Invalid configuration " + emulator + ".host=" + host + " and " + emulator + ".port=" + port + ". " +
211
- 'If either parameter is supplied, both must be defined.');
212
- }
213
- if (discovered && !discovered[emulator]) {
214
- console.warn("Warning: config for the " + emulator + " emulator is specified, but the Emulator hub " +
215
- 'reports it as not running. This may lead to errors such as connection refused.');
216
- }
217
- return {
218
- host: fixHostname(conf.host, (_a = discovered === null || discovered === void 0 ? void 0 : discovered.hub) === null || _a === void 0 ? void 0 : _a.host),
219
- port: conf.port
220
- };
221
- }
282
+ function getAddress(host, port) {
283
+ if (host.includes('::')) {
284
+ return "[" + host + "]:" + port;
222
285
  }
223
- var envVar = EMULATOR_HOST_ENV_VARS[emulator];
224
- var fallback = (discovered === null || discovered === void 0 ? void 0 : discovered[emulator]) || emulatorFromEnvVar(envVar);
225
- if (fallback) {
226
- if (discovered && !discovered[emulator]) {
227
- console.warn("Warning: the environment variable " + envVar + " is set, but the Emulator hub reports the " +
228
- (emulator + " emulator as not running. This may lead to errors such as connection refused."));
229
- }
230
- return {
231
- host: fixHostname(fallback.host, (_b = discovered === null || discovered === void 0 ? void 0 : discovered.hub) === null || _b === void 0 ? void 0 : _b.host),
232
- port: fallback.port
233
- };
286
+ else {
287
+ return host + ":" + port;
234
288
  }
235
289
  }
236
- // Visible for testing.
237
- var EMULATOR_HOST_ENV_VARS = {
238
- 'database': 'FIREBASE_DATABASE_EMULATOR_HOST',
239
- 'firestore': 'FIRESTORE_EMULATOR_HOST',
240
- 'hub': 'FIREBASE_EMULATOR_HUB',
241
- 'storage': 'FIREBASE_STORAGE_EMULATOR_HOST'
242
- };
243
- function emulatorFromEnvVar(envVar) {
244
- var hostAndPort = process.env[envVar];
245
- if (!hostAndPort) {
246
- return undefined;
247
- }
248
- var parsed;
249
- try {
250
- parsed = new URL("http://" + hostAndPort);
251
- }
252
- catch (_a) {
253
- throw new Error("Invalid format in environment variable " + envVar + "=" + hostAndPort + " (expected host:port)");
254
- }
255
- var host = parsed.hostname;
256
- var port = Number(parsed.port || '80');
257
- if (!Number.isInteger(port)) {
258
- throw new Error("Invalid port in environment variable " + envVar + "=" + hostAndPort);
259
- }
260
- return { host: host, port: port };
261
- }
262
-
263
- /**
264
- * @license
265
- * Copyright 2021 Google LLC
266
- *
267
- * Licensed under the Apache License, Version 2.0 (the "License");
268
- * you may not use this file except in compliance with the License.
269
- * You may obtain a copy of the License at
270
- *
271
- * http://www.apache.org/licenses/LICENSE-2.0
272
- *
273
- * Unless required by applicable law or agreed to in writing, software
274
- * distributed under the License is distributed on an "AS IS" BASIS,
275
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
276
- * See the License for the specific language governing permissions and
277
- * limitations under the License.
278
- */
279
- /**
280
- * An implementation of {@code RulesTestEnvironment}. This is private to hide the constructor,
281
- * which should never be directly called by the developer.
282
- * @private
283
- */
284
- var RulesTestEnvironmentImpl = /** @class */ (function () {
285
- function RulesTestEnvironmentImpl(projectId, emulators) {
286
- this.projectId = projectId;
287
- this.emulators = emulators;
288
- this.contexts = new Set();
289
- this.destroyed = false;
290
- }
291
- RulesTestEnvironmentImpl.prototype.authenticatedContext = function (user_id, tokenOptions) {
292
- this.checkNotDestroyed();
293
- return this.createContext(__assign(__assign({}, tokenOptions), { sub: user_id, user_id: user_id }));
294
- };
295
- RulesTestEnvironmentImpl.prototype.unauthenticatedContext = function () {
296
- this.checkNotDestroyed();
297
- return this.createContext(/* authToken = */ undefined);
298
- };
299
- RulesTestEnvironmentImpl.prototype.withSecurityRulesDisabled = function (callback) {
300
- return __awaiter(this, void 0, void 0, function () {
301
- var context;
302
- return __generator(this, function (_a) {
303
- switch (_a.label) {
304
- case 0:
305
- this.checkNotDestroyed();
306
- context = this.createContext('owner');
307
- _a.label = 1;
308
- case 1:
309
- _a.trys.push([1, , 3, 4]);
310
- return [4 /*yield*/, callback(context)];
311
- case 2:
312
- _a.sent();
313
- return [3 /*break*/, 4];
314
- case 3:
315
- // We eagarly clean up this context to actively prevent misuse outside of the callback, e.g.
316
- // storing the context in a variable.
317
- context.cleanup();
318
- this.contexts.delete(context);
319
- return [7 /*endfinally*/];
320
- case 4: return [2 /*return*/];
321
- }
322
- });
323
- });
324
- };
325
- RulesTestEnvironmentImpl.prototype.createContext = function (authToken) {
326
- var context = new RulesTestContextImpl(this.projectId, this.emulators, authToken);
327
- this.contexts.add(context);
328
- return context;
329
- };
330
- RulesTestEnvironmentImpl.prototype.clearDatabase = function () {
331
- this.checkNotDestroyed();
332
- return this.withSecurityRulesDisabled(function (context) {
333
- return context.database().ref('/').set(null);
334
- });
335
- };
336
- RulesTestEnvironmentImpl.prototype.clearFirestore = function () {
337
- return __awaiter(this, void 0, void 0, function () {
338
- var resp, _a;
339
- return __generator(this, function (_b) {
340
- switch (_b.label) {
341
- case 0:
342
- this.checkNotDestroyed();
343
- assertEmulatorRunning(this.emulators, 'firestore');
344
- return [4 /*yield*/, fetch__default['default'](makeUrl(this.emulators.firestore, "/emulator/v1/projects/" + this.projectId + "/databases/(default)/documents"), {
345
- method: 'DELETE'
346
- })];
347
- case 1:
348
- resp = _b.sent();
349
- if (!!resp.ok) return [3 /*break*/, 3];
350
- _a = Error.bind;
351
- return [4 /*yield*/, resp.text()];
352
- case 2: throw new (_a.apply(Error, [void 0, _b.sent()]))();
353
- case 3: return [2 /*return*/];
354
- }
355
- });
356
- });
357
- };
358
- RulesTestEnvironmentImpl.prototype.clearStorage = function () {
359
- var _this = this;
360
- this.checkNotDestroyed();
361
- return this.withSecurityRulesDisabled(function (context) { return __awaiter(_this, void 0, void 0, function () {
362
- var items;
363
- return __generator(this, function (_a) {
364
- switch (_a.label) {
365
- case 0: return [4 /*yield*/, context.storage().ref().listAll()];
366
- case 1:
367
- items = (_a.sent()).items;
368
- return [4 /*yield*/, Promise.all(items.map(function (item) {
369
- return item.delete();
370
- }))];
371
- case 2:
372
- _a.sent();
373
- return [2 /*return*/];
374
- }
375
- });
376
- }); });
377
- };
378
- RulesTestEnvironmentImpl.prototype.cleanup = function () {
379
- return __awaiter(this, void 0, void 0, function () {
380
- return __generator(this, function (_a) {
381
- this.destroyed = true;
382
- this.contexts.forEach(function (context) {
383
- context.envDestroyed = true;
384
- context.cleanup();
385
- });
386
- this.contexts.clear();
387
- return [2 /*return*/];
388
- });
389
- });
390
- };
391
- RulesTestEnvironmentImpl.prototype.checkNotDestroyed = function () {
392
- if (this.destroyed) {
393
- throw new Error('This RulesTestEnvironment has already been cleaned up. ' +
394
- '(This may indicate a leak or missing `await` in your test cases. If you do intend to ' +
395
- 'perform more tests, please call cleanup() later or create another RulesTestEnvironment.)');
290
+ function getDatabaseHost() {
291
+ if (!_databaseHost) {
292
+ var fromEnv = process.env[DATABASE_ADDRESS_ENV];
293
+ if (fromEnv) {
294
+ _databaseHost = fromEnv;
295
+ }
296
+ else {
297
+ console.warn("Warning: " + DATABASE_ADDRESS_ENV + " not set, using default value " + DATABASE_ADDRESS_DEFAULT);
298
+ _databaseHost = DATABASE_ADDRESS_DEFAULT;
396
299
  }
397
- };
398
- return RulesTestEnvironmentImpl;
399
- }());
400
- /**
401
- * An implementation of {@code RulesTestContext}. This is private to hide the constructor,
402
- * which should never be directly called by the developer.
403
- * @private
404
- */
405
- var RulesTestContextImpl = /** @class */ (function () {
406
- function RulesTestContextImpl(projectId, emulators, authToken) {
407
- this.projectId = projectId;
408
- this.emulators = emulators;
409
- this.authToken = authToken;
410
- this.destroyed = false;
411
- this.envDestroyed = false;
412
300
  }
413
- RulesTestContextImpl.prototype.cleanup = function () {
414
- var _a;
415
- this.destroyed = true;
416
- (_a = this.app) === null || _a === void 0 ? void 0 : _a.delete();
417
- this.app = undefined;
418
- };
419
- RulesTestContextImpl.prototype.firestore = function (settings) {
420
- assertEmulatorRunning(this.emulators, 'firestore');
421
- var firestore = this.getApp().firestore();
422
- if (settings) {
423
- firestore.settings(settings);
301
+ return _databaseHost;
302
+ }
303
+ function getFirestoreHost() {
304
+ if (!_firestoreHost) {
305
+ var fromEnv = process.env[FIRESTORE_ADDRESS_ENV];
306
+ if (fromEnv) {
307
+ _firestoreHost = fromEnv;
424
308
  }
425
- firestore.useEmulator(this.emulators.firestore.host, this.emulators.firestore.port, { mockUserToken: this.authToken });
426
- return firestore;
427
- };
428
- RulesTestContextImpl.prototype.database = function (databaseURL) {
429
- assertEmulatorRunning(this.emulators, 'database');
430
- var database = this.getApp().database(databaseURL);
431
- database.useEmulator(this.emulators.database.host, this.emulators.database.port, { mockUserToken: this.authToken });
432
- return database;
433
- };
434
- RulesTestContextImpl.prototype.storage = function (bucketUrl) {
435
- if (bucketUrl === void 0) { bucketUrl = "gs://" + this.projectId; }
436
- assertEmulatorRunning(this.emulators, 'storage');
437
- var storage = this.getApp().storage(bucketUrl);
438
- storage.useEmulator(this.emulators.storage.host, this.emulators.storage.port, { mockUserToken: this.authToken });
439
- return storage;
440
- };
441
- RulesTestContextImpl.prototype.getApp = function () {
442
- if (this.envDestroyed) {
443
- throw new Error('This RulesTestContext is no longer valid because its RulesTestEnvironment has been ' +
444
- 'cleaned up. (This may indicate a leak or missing `await` in your test cases.)');
309
+ else {
310
+ console.warn("Warning: " + FIRESTORE_ADDRESS_ENV + " not set, using default value " + FIRESTORE_ADDRESS_DEFAULT);
311
+ _firestoreHost = FIRESTORE_ADDRESS_DEFAULT;
445
312
  }
446
- if (this.destroyed) {
447
- throw new Error('This RulesTestContext is no longer valid. When using withSecurityRulesDisabled, ' +
448
- 'make sure to perform all operations on the context within the callback function and ' +
449
- 'return a Promise that resolves when the operations are done.');
313
+ }
314
+ return _firestoreHost;
315
+ }
316
+ function getStorageHost() {
317
+ if (!_storageHost) {
318
+ var fromEnv = process.env[FIREBASE_STORAGE_ADDRESS_ENV] ||
319
+ process.env[CLOUD_STORAGE_ADDRESS_ENV];
320
+ if (fromEnv) {
321
+ // The STORAGE_EMULATOR_HOST env var is an older Cloud Standard which includes http:// while
322
+ // the FIREBASE_STORAGE_EMULATOR_HOST is a newer variable supported beginning in the Admin
323
+ // SDK v9.7.0 which does not have the protocol.
324
+ _storageHost = fromEnv.replace('http://', '');
450
325
  }
451
- if (!this.app) {
452
- this.app = firebase__default['default'].initializeApp({ projectId: this.projectId }, "_Firebase_RulesUnitTesting_" + Date.now() + "_" + Math.random());
326
+ else {
327
+ console.warn("Warning: " + FIREBASE_STORAGE_ADDRESS_ENV + " not set, using default value " + STORAGE_ADDRESS_DEFAULT);
328
+ _storageHost = STORAGE_ADDRESS_DEFAULT;
453
329
  }
454
- return this.app;
455
- };
456
- return RulesTestContextImpl;
457
- }());
458
- function assertEmulatorRunning(emulators, emulator) {
459
- if (!emulators[emulator]) {
460
- if (emulators.hub) {
461
- throw new Error("The " + emulator + " emulator is not running (according to Emulator hub). To force " +
462
- 'connecting anyway, please specify its host and port in initializeTestEnvironment({...}).');
330
+ }
331
+ return _storageHost;
332
+ }
333
+ function getHubHost() {
334
+ if (!_hubHost) {
335
+ var fromEnv = process.env[HUB_HOST_ENV];
336
+ if (fromEnv) {
337
+ _hubHost = fromEnv;
463
338
  }
464
339
  else {
465
- throw new Error("The host and port of the " + emulator + " emulator must be specified. (You may wrap the test " +
466
- "script with `firebase emulators:exec './your-test-script'` to enable automatic " +
467
- ("discovery, or specify manually via initializeTestEnvironment({" + emulator + ": {host, port}})."));
340
+ console.warn("Warning: " + HUB_HOST_ENV + " not set, using default value " + HUB_HOST_DEFAULT);
341
+ _hubHost = HUB_HOST_DEFAULT;
468
342
  }
469
343
  }
470
- }
471
-
472
- /**
473
- * @license
474
- * Copyright 2021 Google LLC
475
- *
476
- * Licensed under the Apache License, Version 2.0 (the "License");
477
- * you may not use this file except in compliance with the License.
478
- * You may obtain a copy of the License at
479
- *
480
- * http://www.apache.org/licenses/LICENSE-2.0
481
- *
482
- * Unless required by applicable law or agreed to in writing, software
483
- * distributed under the License is distributed on an "AS IS" BASIS,
484
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
485
- * See the License for the specific language governing permissions and
486
- * limitations under the License.
487
- */
488
- /**
489
- * @private
490
- */
491
- function loadDatabaseRules(hostAndPort, databaseName, rules) {
344
+ return _hubHost;
345
+ }
346
+ function parseHost(host) {
347
+ var withProtocol = host.startsWith('http') ? host : "http://" + host;
348
+ var u = new URL(withProtocol);
349
+ return {
350
+ hostname: u.hostname,
351
+ port: Number.parseInt(u.port, 10)
352
+ };
353
+ }
354
+ function getRandomAppName() {
355
+ return 'app-' + new Date().getTime() + '-' + Math.random();
356
+ }
357
+ function getDatabaseUrl(databaseName) {
358
+ return "http://" + getDatabaseHost() + "?ns=" + databaseName;
359
+ }
360
+ function getAppOptions(databaseName, projectId, storageBucket) {
361
+ var appOptions = {};
362
+ if (databaseName) {
363
+ appOptions['databaseURL'] = getDatabaseUrl(databaseName);
364
+ }
365
+ if (projectId) {
366
+ appOptions['projectId'] = projectId;
367
+ }
368
+ if (storageBucket) {
369
+ appOptions['storageBucket'] = storageBucket;
370
+ }
371
+ return appOptions;
372
+ }
373
+ function initializeApp(accessToken, databaseName, projectId, storageBucket) {
374
+ var _this = this;
375
+ var appOptions = getAppOptions(databaseName, projectId, storageBucket);
376
+ var app = firebase__default['default'].initializeApp(appOptions, getRandomAppName());
377
+ if (accessToken) {
378
+ var mockAuthComponent = new component.Component('auth-internal', function () {
379
+ return ({
380
+ getToken: function () { return __awaiter(_this, void 0, void 0, function () { return __generator(this, function (_a) {
381
+ return [2 /*return*/, ({ accessToken: accessToken })];
382
+ }); }); },
383
+ getUid: function () { return null; },
384
+ addAuthTokenListener: function (listener) {
385
+ // Call listener once immediately with predefined accessToken.
386
+ listener(accessToken);
387
+ },
388
+ removeAuthTokenListener: function () { }
389
+ });
390
+ }, "PRIVATE" /* PRIVATE */);
391
+ app._addOrOverwriteComponent(mockAuthComponent);
392
+ }
393
+ if (databaseName) {
394
+ var _a = parseHost(getDatabaseHost()), hostname = _a.hostname, port = _a.port;
395
+ app.database().useEmulator(hostname, port);
396
+ // Toggle network connectivity to force a reauthentication attempt.
397
+ // This mitigates a minor race condition where the client can send the
398
+ // first database request before authenticating.
399
+ app.database().goOffline();
400
+ app.database().goOnline();
401
+ }
402
+ if (projectId) {
403
+ var _b = parseHost(getFirestoreHost()), hostname = _b.hostname, port = _b.port;
404
+ app.firestore().useEmulator(hostname, port);
405
+ }
406
+ if (storageBucket) {
407
+ var _c = parseHost(getStorageHost()), hostname = _c.hostname, port = _c.port;
408
+ app.storage().useEmulator(hostname, port);
409
+ }
410
+ /**
411
+ Mute warnings for the previously-created database and whatever other
412
+ objects were just created.
413
+ */
414
+ logger.setLogLevel(logger.LogLevel.ERROR);
415
+ return app;
416
+ }
417
+ function loadDatabaseRules(options) {
492
418
  return __awaiter(this, void 0, void 0, function () {
493
- var url, resp, _a;
494
- return __generator(this, function (_b) {
495
- switch (_b.label) {
419
+ var resp;
420
+ return __generator(this, function (_a) {
421
+ switch (_a.label) {
496
422
  case 0:
497
- url = makeUrl(hostAndPort, '/.settings/rules.json');
498
- url.searchParams.append('ns', databaseName);
499
- return [4 /*yield*/, fetch__default['default'](url, {
423
+ if (!options.databaseName) {
424
+ throw Error('databaseName not specified');
425
+ }
426
+ if (!options.rules) {
427
+ throw Error('must provide rules to loadDatabaseRules');
428
+ }
429
+ return [4 /*yield*/, requestPromise(request__namespace.put, {
500
430
  method: 'PUT',
431
+ uri: "http://" + getDatabaseHost() + "/.settings/rules.json?ns=" + options.databaseName,
501
432
  headers: { Authorization: 'Bearer owner' },
502
- body: rules
433
+ body: options.rules
503
434
  })];
504
435
  case 1:
505
- resp = _b.sent();
506
- if (!!resp.ok) return [3 /*break*/, 3];
507
- _a = Error.bind;
508
- return [4 /*yield*/, resp.text()];
509
- case 2: throw new (_a.apply(Error, [void 0, _b.sent()]))();
510
- case 3: return [2 /*return*/];
436
+ resp = _a.sent();
437
+ if (resp.statusCode !== 200) {
438
+ throw new Error(JSON.parse(resp.body.error));
439
+ }
440
+ return [2 /*return*/];
511
441
  }
512
442
  });
513
443
  });
514
444
  }
515
- /**
516
- * @private
517
- */
518
- function loadFirestoreRules(hostAndPort, projectId, rules) {
445
+ function loadFirestoreRules(options) {
519
446
  return __awaiter(this, void 0, void 0, function () {
520
- var resp, _a;
521
- return __generator(this, function (_b) {
522
- switch (_b.label) {
523
- case 0: return [4 /*yield*/, fetch__default['default'](makeUrl(hostAndPort, "/emulator/v1/projects/" + projectId + ":securityRules"), {
524
- method: 'PUT',
525
- body: JSON.stringify({
526
- rules: {
527
- files: [{ content: rules }]
528
- }
529
- })
530
- })];
447
+ var resp;
448
+ return __generator(this, function (_a) {
449
+ switch (_a.label) {
450
+ case 0:
451
+ if (!options.projectId) {
452
+ throw new Error('projectId not specified');
453
+ }
454
+ if (!options.rules) {
455
+ throw new Error('must provide rules to loadFirestoreRules');
456
+ }
457
+ return [4 /*yield*/, requestPromise(request__namespace.put, {
458
+ method: 'PUT',
459
+ uri: "http://" + getFirestoreHost() + "/emulator/v1/projects/" + options.projectId + ":securityRules",
460
+ body: JSON.stringify({
461
+ rules: {
462
+ files: [{ content: options.rules }]
463
+ }
464
+ })
465
+ })];
531
466
  case 1:
532
- resp = _b.sent();
533
- if (!!resp.ok) return [3 /*break*/, 3];
534
- _a = Error.bind;
535
- return [4 /*yield*/, resp.text()];
536
- case 2: throw new (_a.apply(Error, [void 0, _b.sent()]))();
537
- case 3: return [2 /*return*/];
467
+ resp = _a.sent();
468
+ if (resp.statusCode !== 200) {
469
+ throw new Error(JSON.parse(resp.body.error));
470
+ }
471
+ return [2 /*return*/];
538
472
  }
539
473
  });
540
474
  });
541
475
  }
542
- /**
543
- * @private
544
- */
545
- function loadStorageRules(hostAndPort, rules) {
476
+ function loadStorageRules(options) {
546
477
  return __awaiter(this, void 0, void 0, function () {
547
- var resp, _a;
548
- return __generator(this, function (_b) {
549
- switch (_b.label) {
550
- case 0: return [4 /*yield*/, fetch__default['default'](makeUrl(hostAndPort, '/internal/setRules'), {
551
- method: 'PUT',
552
- headers: {
553
- 'Content-Type': 'application/json'
554
- },
555
- body: JSON.stringify({
556
- rules: {
557
- files: [{ name: 'storage.rules', content: rules }]
558
- }
559
- })
560
- })];
478
+ var resp;
479
+ return __generator(this, function (_a) {
480
+ switch (_a.label) {
481
+ case 0:
482
+ if (!options.rules) {
483
+ throw new Error('must provide rules to loadStorageRules');
484
+ }
485
+ return [4 /*yield*/, requestPromise(request__namespace.put, {
486
+ method: 'PUT',
487
+ uri: "http://" + getStorageHost() + "/internal/setRules",
488
+ headers: {
489
+ 'Content-Type': 'application/json'
490
+ },
491
+ body: JSON.stringify({
492
+ rules: {
493
+ files: [{ name: 'storage.rules', content: options.rules }]
494
+ }
495
+ })
496
+ })];
561
497
  case 1:
562
- resp = _b.sent();
563
- if (!!resp.ok) return [3 /*break*/, 3];
564
- _a = Error.bind;
565
- return [4 /*yield*/, resp.text()];
566
- case 2: throw new (_a.apply(Error, [void 0, _b.sent()]))();
567
- case 3: return [2 /*return*/];
498
+ resp = _a.sent();
499
+ if (resp.statusCode !== 200) {
500
+ throw new Error(resp.body);
501
+ }
502
+ return [2 /*return*/];
568
503
  }
569
504
  });
570
505
  });
571
- }
572
-
573
- /**
574
- * @license
575
- * Copyright 2021 Google LLC
576
- *
577
- * Licensed under the Apache License, Version 2.0 (the "License");
578
- * you may not use this file except in compliance with the License.
579
- * You may obtain a copy of the License at
580
- *
581
- * http://www.apache.org/licenses/LICENSE-2.0
582
- *
583
- * Unless required by applicable law or agreed to in writing, software
584
- * distributed under the License is distributed on an "AS IS" BASIS,
585
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
586
- * See the License for the specific language governing permissions and
587
- * limitations under the License.
588
- */
589
- /**
590
- * Initializes a test environment for rules unit testing. Call this function first for test setup.
591
- *
592
- * Requires emulators to be running. This function tries to discover those emulators via environment
593
- * variables or through the Firebase Emulator hub if hosts and ports are unspecified. It is strongly
594
- * recommended to specify security rules for emulators used for testing. See minimal example below.
595
- *
596
- * @param config the configuration for emulators. most fields are optional if they can be discovered
597
- * @returns a promise that resolves with an environment ready for testing, or rejects on error.
598
- * @public
599
- * @example
600
- * ```javascript
601
- * const testEnv = await initializeTestEnvironment({
602
- * firestore: {
603
- * rules: fs.readFileSync("/path/to/firestore.rules", "utf8"), // Load rules from file
604
- * // host and port can be omitted if they can be discovered from the hub.
605
- * },
606
- * // ...
607
- * });
608
- * ```
609
- */
610
- function initializeTestEnvironment(config) {
611
- var _a, _b, _c;
506
+ }
507
+ function clearFirestoreData(options) {
612
508
  return __awaiter(this, void 0, void 0, function () {
613
- var projectId, hub, discovered, _d, _e, emulators, _i, SUPPORTED_EMULATORS_1, emulator, hostAndPort;
614
- return __generator(this, function (_f) {
615
- switch (_f.label) {
509
+ var resp;
510
+ return __generator(this, function (_a) {
511
+ switch (_a.label) {
616
512
  case 0:
617
- projectId = config.projectId || process.env.GCLOUD_PROJECT;
618
- if (!projectId) {
619
- throw new Error('Missing projectId option or env var GCLOUD_PROJECT! Please specify the projectId either ' +
620
- 'way.\n(A demo-* projectId is strongly recommended for unit tests, such as "demo-test".)');
513
+ if (!options.projectId) {
514
+ throw new Error('projectId not specified');
621
515
  }
622
- hub = getEmulatorHostAndPort('hub', config.hub);
623
- if (!hub) return [3 /*break*/, 2];
624
- _e = [{}];
625
- return [4 /*yield*/, discoverEmulators(hub)];
516
+ return [4 /*yield*/, requestPromise(request__namespace.delete, {
517
+ method: 'DELETE',
518
+ uri: "http://" + getFirestoreHost() + "/emulator/v1/projects/" + options.projectId + "/databases/(default)/documents",
519
+ body: JSON.stringify({
520
+ database: "projects/" + options.projectId + "/databases/(default)"
521
+ })
522
+ })];
626
523
  case 1:
627
- _d = __assign.apply(void 0, [__assign.apply(void 0, _e.concat([(_f.sent())])), { hub: hub }]);
628
- return [3 /*break*/, 3];
629
- case 2:
630
- _d = undefined;
631
- _f.label = 3;
632
- case 3:
633
- discovered = _d;
634
- emulators = {};
635
- if (hub) {
636
- emulators.hub = hub;
637
- }
638
- for (_i = 0, SUPPORTED_EMULATORS_1 = SUPPORTED_EMULATORS; _i < SUPPORTED_EMULATORS_1.length; _i++) {
639
- emulator = SUPPORTED_EMULATORS_1[_i];
640
- hostAndPort = getEmulatorHostAndPort(emulator, config[emulator], discovered);
641
- if (hostAndPort) {
642
- emulators[emulator] = hostAndPort;
643
- }
524
+ resp = _a.sent();
525
+ if (resp.statusCode !== 200) {
526
+ throw new Error(JSON.parse(resp.body.error));
644
527
  }
645
- if (!((_a = config.database) === null || _a === void 0 ? void 0 : _a.rules)) return [3 /*break*/, 5];
646
- assertEmulatorRunning(emulators, 'database');
647
- return [4 /*yield*/, loadDatabaseRules(emulators.database, projectId, config.database.rules)];
648
- case 4:
649
- _f.sent();
650
- _f.label = 5;
651
- case 5:
652
- if (!((_b = config.firestore) === null || _b === void 0 ? void 0 : _b.rules)) return [3 /*break*/, 7];
653
- assertEmulatorRunning(emulators, 'firestore');
654
- return [4 /*yield*/, loadFirestoreRules(emulators.firestore, projectId, config.firestore.rules)];
655
- case 6:
656
- _f.sent();
657
- _f.label = 7;
658
- case 7:
659
- if (!((_c = config.storage) === null || _c === void 0 ? void 0 : _c.rules)) return [3 /*break*/, 9];
660
- assertEmulatorRunning(emulators, 'storage');
661
- return [4 /*yield*/, loadStorageRules(emulators.storage, config.storage.rules)];
662
- case 8:
663
- _f.sent();
664
- _f.label = 9;
665
- case 9: return [2 /*return*/, new RulesTestEnvironmentImpl(projectId, emulators)];
528
+ return [2 /*return*/];
666
529
  }
667
530
  });
668
531
  });
669
532
  }
670
- var SUPPORTED_EMULATORS = ['database', 'firestore', 'storage'];
671
-
672
533
  /**
673
- * @license
674
- * Copyright 2021 Google LLC
534
+ * Run a setup function with background Cloud Functions triggers disabled. This can be used to
535
+ * import data into the Realtime Database or Cloud Firestore emulator without triggering locally
536
+ * emulated Cloud Functions.
675
537
  *
676
- * Licensed under the Apache License, Version 2.0 (the "License");
677
- * you may not use this file except in compliance with the License.
678
- * You may obtain a copy of the License at
538
+ * This method only works with Firebase CLI version 8.13.0 or higher.
679
539
  *
680
- * http://www.apache.org/licenses/LICENSE-2.0
681
- *
682
- * Unless required by applicable law or agreed to in writing, software
683
- * distributed under the License is distributed on an "AS IS" BASIS,
684
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
685
- * See the License for the specific language governing permissions and
686
- * limitations under the License.
540
+ * @param fn an function which returns a promise.
687
541
  */
688
- function withFunctionTriggersDisabled(fnOrHub, maybeFn) {
542
+ function withFunctionTriggersDisabled(fn) {
689
543
  return __awaiter(this, void 0, void 0, function () {
690
- var hub, disableRes, result, enableRes;
544
+ var hubHost, disableRes, result, enableRes;
691
545
  return __generator(this, function (_a) {
692
546
  switch (_a.label) {
693
547
  case 0:
694
- if (typeof fnOrHub === 'function') {
695
- maybeFn = fnOrHub;
696
- hub = getEmulatorHostAndPort('hub');
697
- }
698
- else {
699
- hub = getEmulatorHostAndPort('hub', fnOrHub);
700
- if (!maybeFn) {
701
- throw new Error('The callback function must be specified!');
702
- }
703
- }
704
- if (!hub) {
705
- throw new Error('Please specify the Emulator Hub host and port via arguments or set the environment ' +
706
- ("varible " + EMULATOR_HOST_ENV_VARS.hub + "!"));
707
- }
708
- hub.host = fixHostname(hub.host);
709
- makeUrl(hub, '/functions/disableBackgroundTriggers');
710
- return [4 /*yield*/, fetch__default['default'](makeUrl(hub, '/functions/disableBackgroundTriggers'), {
711
- method: 'PUT'
548
+ hubHost = getHubHost();
549
+ return [4 /*yield*/, requestPromise(request__namespace.put, {
550
+ method: 'PUT',
551
+ uri: "http://" + hubHost + "/functions/disableBackgroundTriggers"
712
552
  })];
713
553
  case 1:
714
554
  disableRes = _a.sent();
715
- if (!disableRes.ok) {
716
- throw new Error("HTTP Error " + disableRes.status + " when disabling functions triggers, are you using firebase-tools 8.13.0 or higher?");
555
+ if (disableRes.statusCode !== 200) {
556
+ throw new Error("HTTP Error " + disableRes.statusCode + " when disabling functions triggers, are you using firebase-tools 8.13.0 or higher?");
717
557
  }
718
558
  result = undefined;
719
559
  _a.label = 2;
720
560
  case 2:
721
561
  _a.trys.push([2, , 4, 6]);
722
- return [4 /*yield*/, maybeFn()];
562
+ return [4 /*yield*/, fn()];
723
563
  case 3:
724
564
  result = _a.sent();
725
565
  return [3 /*break*/, 6];
726
- case 4: return [4 /*yield*/, fetch__default['default'](makeUrl(hub, '/functions/enableBackgroundTriggers'), {
727
- method: 'PUT'
566
+ case 4: return [4 /*yield*/, requestPromise(request__namespace.put, {
567
+ method: 'PUT',
568
+ uri: "http://" + hubHost + "/functions/enableBackgroundTriggers"
728
569
  })];
729
570
  case 5:
730
571
  enableRes = _a.sent();
731
- if (!enableRes.ok) {
732
- throw new Error("HTTP Error " + enableRes.status + " when enabling functions triggers, are you using firebase-tools 8.13.0 or higher?");
572
+ if (enableRes.statusCode !== 200) {
573
+ throw new Error("HTTP Error " + enableRes.statusCode + " when enabling functions triggers, are you using firebase-tools 8.13.0 or higher?");
733
574
  }
734
575
  return [7 /*endfinally*/];
735
576
  case 6:
@@ -739,29 +580,12 @@ function withFunctionTriggersDisabled(fnOrHub, maybeFn) {
739
580
  });
740
581
  });
741
582
  }
742
- /**
743
- * Assert the promise to be rejected with a "permission denied" error.
744
- *
745
- * Useful to assert a certain request to be denied by Security Rules. See example below.
746
- * This function recognizes permission-denied errors from Database, Firestore, and Storage JS SDKs.
747
- *
748
- * @param pr the promise to be asserted
749
- * @returns a Promise that is fulfilled if pr is rejected with "permission denied". If pr is
750
- * rejected with any other error or resolved, the returned promise rejects.
751
- * @public
752
- * @example
753
- * ```javascript
754
- * const unauthed = testEnv.unauthenticatedContext();
755
- * await assertFails(get(doc(unauthed.firestore(), '/private/doc'), { ... });
756
- * ```
757
- */
758
583
  function assertFails(pr) {
759
- return pr.then(function () {
584
+ return pr.then(function (v) {
760
585
  return Promise.reject(new Error('Expected request to fail, but it succeeded.'));
761
586
  }, function (err) {
762
- var _a, _b;
763
- var errCode = ((_a = err === null || err === void 0 ? void 0 : err.code) === null || _a === void 0 ? void 0 : _a.toLowerCase()) || '';
764
- var errMessage = ((_b = err === null || err === void 0 ? void 0 : err.message) === null || _b === void 0 ? void 0 : _b.toLowerCase()) || '';
587
+ var errCode = (err && err.code && err.code.toLowerCase()) || '';
588
+ var errMessage = (err && err.message && err.message.toLowerCase()) || '';
765
589
  var isPermissionDenied = errCode === 'permission-denied' ||
766
590
  errCode === 'permission_denied' ||
767
591
  errMessage.indexOf('permission_denied') >= 0 ||
@@ -774,25 +598,37 @@ function assertFails(pr) {
774
598
  return err;
775
599
  });
776
600
  }
777
- /**
778
- * Assert the promise to be rejected with a "permission denied" error.
779
- *
780
- * This is a no-op function returning the passed promise as-is, but can be used for documentational
781
- * purposes in test code to emphasize that a certain request should succeed (e.g. allowed by rules).
782
- *
783
- * @public
784
- * @example
785
- * ```javascript
786
- * const alice = testEnv.authenticatedContext('alice');
787
- * await assertSucceeds(get(doc(alice.firestore(), '/doc/readable/by/alice'), { ... });
788
- * ```
789
- */
790
601
  function assertSucceeds(pr) {
791
602
  return pr;
603
+ }
604
+ function requestPromise(method, options) {
605
+ return new Promise(function (resolve, reject) {
606
+ var callback = function (err, resp, body) {
607
+ if (err) {
608
+ reject(err);
609
+ }
610
+ else {
611
+ resolve({ statusCode: resp.statusCode, body: body });
612
+ }
613
+ };
614
+ // Unfortunately request's default method is not very test-friendly so having
615
+ // the caler pass in the method here makes this whole thing compatible with sinon
616
+ method(options, callback);
617
+ });
792
618
  }
793
619
 
620
+ exports.apps = apps;
794
621
  exports.assertFails = assertFails;
795
622
  exports.assertSucceeds = assertSucceeds;
796
- exports.initializeTestEnvironment = initializeTestEnvironment;
623
+ exports.clearFirestoreData = clearFirestoreData;
624
+ exports.database = database;
625
+ exports.discoverEmulators = discoverEmulators;
626
+ exports.firestore = firestore;
627
+ exports.initializeAdminApp = initializeAdminApp;
628
+ exports.initializeTestApp = initializeTestApp;
629
+ exports.loadDatabaseRules = loadDatabaseRules;
630
+ exports.loadFirestoreRules = loadFirestoreRules;
631
+ exports.loadStorageRules = loadStorageRules;
632
+ exports.useEmulators = useEmulators;
797
633
  exports.withFunctionTriggersDisabled = withFunctionTriggersDisabled;
798
634
  //# sourceMappingURL=index.cjs.js.map