Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions .github/workflows/scripts/firebase.emulator.template.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"name": "react-native-firebase-testing",
"firestore": {
"rules": "firestore.rules",
"indexes": "firestore.indexes.json"
},
"functions": {
"predeploy": ["cd functions && yarn", "cd functions && yarn --cwd \"$RESOURCE_DIR\" build"],
"source": "functions",
"ignore": [".yarn", "yarn.lock", "*.log", "node_modules"]
},
"database": {
"rules": "database.rules"
},
"storage": {
"rules": "storage.rules"
},
"emulators": {
"auth": { "port": 9099 },
"database": { "port": 9000 },
"firestore": { "port": 8080 },
"functions": { "port": 5001 },
"storage": { "port": 9199 },
"ui": { "enabled": false }
}
}
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -548,6 +548,8 @@ google-services.json
GoogleService-Info.plist

tests/harness.overrides.js
tests/e2e-slots.env.json
.github/workflows/scripts/.e2e-emulator-*.json

# RNFB TurboModule codegen — misplaced iOS provider stubs under Android output paths
# (NewArch-AD-5: okf-bundle/new-architecture/architecture-decisions.md — commit generated
Expand Down
25 changes: 24 additions & 1 deletion okf-bundle/testing/running-e2e.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ yarn tests:macos:test-cover

5. **Report locations** — [Coverage design](coverage-design.md).

6. **One e2e at a time** — never overlap `:test-cover` runs on one host. All platforms share Metro `:8081` and the test-runner WebSocket port (default **8090**); parallel runs race on coverage/device/emulator state. Every run starts after [clean pre-flight](#pre-flight-is-the-host-clear-to-start). Log triage for port/orchestration markers: [test-runner host orchestration](#test-runner-host-orchestration-log-triage-only).
6. **One e2e at a time (default)** — never overlap `:test-cover` runs on one host unless each run uses a distinct port/device slot via [configurable e2e environment](#configurable-e2e-environment). Serial runs share Metro `:8081` and the test-runner WebSocket port (default **8090**); parallel runs race on coverage/device/emulator state without slotted env. Every run starts after [clean pre-flight](#pre-flight-is-the-host-clear-to-start). Log triage for port/orchestration markers: [test-runner host orchestration](#test-runner-host-orchestration-log-triage-only).

7. **No source edits during e2e** — wait/cancel cleanly before editing `packages/**`, `tests/**`, or bundle-affecting OKF docs. Saves can hot reload/rebundle and invalidate tests/coverage.

Expand Down Expand Up @@ -502,6 +502,29 @@ See also: [unit-focused-tier loop](#unit-focused-tier-iteration-loop), [dispatch
- **adb empty** — `adb kill-server && adb start-server && adb devices`
- **Stale processes** — one Metro (`:8081`), one emulator set (`:8080`, `:9099`, `:9000`, `:4400`, …). Stray listener on `:8090` after a run → [pre-flight recovery](#pre-flight-recovery), then restart background services with [Rules §1–2](#rules) (`yarn tests:packager:jet`, `yarn tests:emulator:start`).

<a id="configurable-e2e-environment"></a>

### Configurable e2e environment

Serial e2e uses committed defaults (Metro `:8081`, Jet `:8090` / `:8190` / `:8290`, emulators `:8080` / `:9099` / …). To run multiple platform jobs on one host — or to pin a non-default slot — export env vars **before** Metro/native build and `:test-cover`. Unset vars keep legacy serial behaviour.

| Variable | Purpose |
|----------|---------|
| `RCT_METRO_PORT`, `RNFB_METRO_PORT` | Metro bundler port (global fallback) |
| `RNFB_{ANDROID,IOS,MACOS}_METRO_PORT` | Per-platform Metro port |
| `JET_REMOTE_PORT`, `JET_METRO_PORT` | Test-runner WebSocket + Metro hint (global) |
| `RNFB_{ANDROID,IOS,MACOS}_JET_PORT` | Per-platform Jet WebSocket port |
| `RNFB_JET_CONTROL_PORT` | Jet HTTP control plane (default `JET_REMOTE_PORT + 1`) |
| `RNFB_{ANDROID,IOS,MACOS}_EMULATOR_{FIRESTORE,AUTH,DATABASE,FUNCTIONS,STORAGE,HUB,LOGGING}_PORT` | Per-platform Firebase emulator suite |
| `RNFB_DETOX_ANDROID_CONFIG`, `RNFB_DETOX_IOS_CONFIG` | Detox configuration name (e.g. `android.emu.debug.slot1`, `ios.sim.debug.slot1`) |
| `RNFB_E2E_PLATFORM`, `RNFB_E2E_SLOT` | Active platform label and slot index for orchestration scripts |
| `RNFB_ANDROID_AVD`, `RNFB_IOS_SIMULATOR`, `RNFB_ANDROID_EMULATOR_BOOT_ARGS` | Device selection overrides |
| `ORG_GRADLE_PROJECT_reactNativeDevServerPort` | Android Gradle Metro port (set to match `RNFB_ANDROID_METRO_PORT`) |
| `SIMCTL_CHILD_RCT_METRO_PORT` | iOS simulator child Metro port |
| `RNFB_E2E_DEBUG` | Verbose `[rnfb-e2e]` port resolution logging in app helpers |

Helper scripts (not canonical `:test-cover` entrypoints): `scripts/e2e/start-emulator-slotted.sh`, `yarn tests:e2e:setup-android-avds`, `yarn tests:e2e:setup-ios-sims`.

### Android emulator gray screen / Quick Boot (blocking)

Detox's default emulator launch **restores the AVD Quick Boot snapshot** unless told otherwise. On `TestingAVD` that can leave the device **`offline` on a gray screen** — `adb devices` shows `emulator-XXXX offline` and Detox hangs on `wait-for-device`.
Expand Down
12 changes: 7 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,27 +41,27 @@
"tests:emulator:start:windows": "yarn tests:emulator:prepare && cd ./.github/workflows/scripts && ./start-firebase-emulator.bat --no-daemon",
"tests:emulator:start-ci": "yarn tests:emulator:prepare && cd ./.github/workflows/scripts && ./start-firebase-emulator.sh",
"tests:android:build": "run-script-os",
"tests:android:build:default": "cd tests && yarn detox build --configuration android.emu.debug",
"tests:android:build:default": "bash -c 'cd tests && yarn detox build --configuration \"${RNFB_DETOX_ANDROID_CONFIG:-android.emu.debug}\"'",
"tests:android:build:windows": "cd tests && yarn detox build --configuration android.emu.debug.windows",
"tests:android:build:release": "cd tests && yarn detox build --configuration android.emu.release",
"tests:android:manual": "cd tests && yarn react-native run-android",
"tests:android:test": "cd tests && yarn detox test --configuration android.emu.debug",
"tests:android:test": "bash -c 'cd tests && yarn detox test --configuration \"${RNFB_DETOX_ANDROID_CONFIG:-android.emu.debug}\"'",
"tests:android:test:debug": "cd tests && yarn detox test --configuration android.emu.debug --inspect",
"tests:android:test-reuse": "cd tests && yarn detox test --configuration android.emu.debug --reuse",
"tests:android:test-cover": "cd tests && yarn detox test --configuration android.emu.debug --loglevel verbose",
"tests:android:test-cover": "bash -c 'cd tests && yarn detox test --configuration \"${RNFB_DETOX_ANDROID_CONFIG:-android.emu.debug}\" --loglevel verbose'",
"tests:android:test-cover-reuse": "cd tests && yarn detox test --configuration android.emu.debug --reuse",
"tests:android:pull-native-coverage": "node tests/scripts/pull-native-coverage.js --android-pull",
"tests:android:post-e2e-coverage": "node tests/scripts/pull-native-coverage.js --android-post-e2e",
"tests:android:test:jacoco-report": "cd tests/android && ./gradlew jacocoAndroidTestReport",
"tests:ios:build": "cd tests && yarn detox build --configuration ios.sim.debug",
"tests:ios:build": "bash -c 'cd tests && yarn detox build --configuration \"${RNFB_DETOX_IOS_CONFIG:-ios.sim.debug}\"'",
"tests:ios:build:release": "cd tests && yarn detox build --configuration ios.sim.release",
"tests:ios:detox-framework-cache:rebuild": "cd tests && yarn detox rebuild-framework-cache",
"tests:ios:manual": "cd tests && SIMCTL_CHILD_GULGeneratedClassDisposeDisabled=1 CC=clang CPLUSPLUS=clang++ LD=clang LDPLUSPLUS=clang++ yarn react-native run-ios",
"tests:ios:test": "cd tests && SIMCTL_CHILD_GULGeneratedClassDisposeDisabled=1 yarn detox test --configuration ios.sim.debug --loglevel warn",
"tests:ios:test:release": "cd tests && SIMCTL_CHILD_GULGeneratedClassDisposeDisabled=1 yarn detox test --configuration ios.sim.release --loglevel warn",
"tests:ios:test:debug": "cd tests && SIMCTL_CHILD_GULGeneratedClassDisposeDisabled=1 yarn detox test --configuration ios.sim.debug --loglevel warn --inspect",
"tests:ios:test-reuse": "cd tests && SIMCTL_CHILD_GULGeneratedClassDisposeDisabled=1 yarn detox test --configuration ios.sim.debug --reuse --loglevel warn",
"tests:ios:test-cover": "cd tests && SIMCTL_CHILD_GULGeneratedClassDisposeDisabled=1 yarn detox test --configuration ios.sim.debug --loglevel verbose",
"tests:ios:test-cover": "bash -c 'cd tests && SIMCTL_CHILD_GULGeneratedClassDisposeDisabled=1 yarn detox test --configuration \"${RNFB_DETOX_IOS_CONFIG:-ios.sim.debug}\" --loglevel verbose'",
"tests:ios:test-cover-reuse": "cd tests && SIMCTL_CHILD_GULGeneratedClassDisposeDisabled=1 yarn detox test --configuration ios.sim.debug --reuse --loglevel warn",
"tests:ios:test:process-coverage": "node tests/scripts/process-ios-native-coverage.js",
"tests:ios:test-cover-and-process": "yarn tests:ios:test-cover && yarn tests:ios:test:process-coverage",
Expand All @@ -71,6 +71,8 @@
"tests:macos:manual": "cd tests && yarn react-native run-macos",
"tests:macos:test": "cd tests && npx jet --target=macos --coverage",
"tests:macos:test-cover": "cd tests && npx jet --target=macos --coverage",
"tests:e2e:setup-android-avds": "bash ./scripts/e2e/create-android-avds.sh",
"tests:e2e:setup-ios-sims": "bash ./scripts/e2e/create-ios-simulators.sh",
"format:js": "prettier --write \"packages/**/*.{js,ts,tsx}\"",
"format:markdown": "prettier --write \"docs/**/*.md[x]\""
},
Expand Down
15 changes: 12 additions & 3 deletions packages/ai/lib/requests/request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,21 @@
logger.info(
'Running VertexAI in test environment, pointing to Firebase Functions emulator URL',
);
const isAndroid = Platform.OS === 'android';
let fnHost = '127.0.0.1';
let fnPort = 5001;
try {
const { getE2eEmulatorHost, getE2eEmulatorPort } = require('@react-native-firebase/app/e2e/helpers');

Check failure on line 64 in packages/ai/lib/requests/request.ts

View workflow job for this annotation

GitHub Actions / Lint

Replace `·getE2eEmulatorHost,·getE2eEmulatorPort` with `⏎··········getE2eEmulatorHost,⏎··········getE2eEmulatorPort,⏎·······`
fnHost = getE2eEmulatorHost();
fnPort = getE2eEmulatorPort('functions');
} catch (_e) {
const isAndroid = Platform.OS === 'android';
fnHost = isAndroid ? '10.0.2.2' : '127.0.0.1';
}
Comment on lines +61 to +70

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

Dynamic require statements with static string literals like require('@react-native-firebase/app/e2e/helpers') are statically analyzed by Metro bundler at build time. Since the e2e directory is typically excluded from published npm packages, this will cause production builds of consumer applications to fail with a module resolution error, even though it is wrapped in a try/catch block.

Instead of requiring the test helper, you can directly resolve the host and port using Platform.OS and the environment variables inlined by Babel during test runs.

      const isAndroid = Platform.OS === 'android';
      let fnHost = isAndroid ? '10.0.2.2' : '127.0.0.1';
      let fnPort = 5001;

      const platformKey = isAndroid ? 'ANDROID' : (Platform.OS as string) === 'macos' ? 'MACOS' : 'IOS';
      const envPort = process.env[`RNFB_${platformKey}_EMULATOR_FUNCTIONS_PORT`];
      if (envPort) {
        fnPort = parseInt(envPort, 10);
      }


if (this.stream) {
emulatorUrl = `http://${isAndroid ? '10.0.2.2' : '127.0.0.1'}:5001/react-native-firebase-testing/us-central1/testFetchStream`;
emulatorUrl = `http://${fnHost}:${fnPort}/react-native-firebase-testing/us-central1/testFetchStream`;
} else {
emulatorUrl = `http://${isAndroid ? '10.0.2.2' : '127.0.0.1'}:5001/react-native-firebase-testing/us-central1/testFetch`;
emulatorUrl = `http://${fnHost}:${fnPort}/react-native-firebase-testing/us-central1/testFetch`;
}
return emulatorUrl;
}
Expand Down
3 changes: 2 additions & 1 deletion packages/app/e2e/config.e2e.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,9 @@ describe('config', function () {
// NOTE: "preferencesClearAll" clears Firestore settings. Set DB as emulator again.
after(async function () {
const { connectFirestoreEmulator, getFirestore } = firestoreModular;
const { getE2eEmulatorPort } = require('../../app/e2e/helpers');
if (Platform.other) return;
connectFirestoreEmulator(getFirestore(), 'localhost', 8080);
connectFirestoreEmulator(getFirestore(), 'localhost', getE2eEmulatorPort('firestore'));
});

it('should set bool values', async function () {
Expand Down
87 changes: 87 additions & 0 deletions packages/app/e2e/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,90 @@ exports.getE2eEmulatorHost = function getE2eEmulatorHost() {
}
return '127.0.0.1';
};

function platformKey() {
if (Platform.other) {
return 'macos';
}
if (Platform.android) {
return 'android';
}
return 'ios';
}

const DEFAULT_EMULATOR = {
firestore: 8080,
auth: 9099,
database: 9000,
functions: 5001,
storage: 9199,
};

const DEFAULT_JET = {
android: 8090,
ios: 8190,
macos: 8290,
};

function e2eDebug(msg, extra) {
if (process.env.RNFB_E2E_DEBUG !== '1') {
return;
}
const pk = platformKey();
// eslint-disable-next-line no-console
console.log(`[rnfb-e2e] platform=${pk} ${msg}`, extra || '');
}

function prefixedEmulatorPort(service) {
const pk = platformKey();
const key = `RNFB_${pk.toUpperCase()}_EMULATOR_${service.toUpperCase()}_PORT`;
if (process.env[key]) {
return parseInt(process.env[key], 10);
}
return null;
}

exports.getE2ePlatformKey = platformKey;

exports.getE2eEmulatorPort = function getE2eEmulatorPort(service) {
const prefixed = prefixedEmulatorPort(service);
if (prefixed) {
e2eDebug(`emulator.${service} from env`, prefixed);
return prefixed;
}
const fallback = DEFAULT_EMULATOR[service] ?? 8080;
e2eDebug(`emulator.${service} default`, fallback);
return fallback;
};

exports.getJetRemotePort = function getJetRemotePort() {
if (process.env.JET_REMOTE_PORT) {
return parseInt(process.env.JET_REMOTE_PORT, 10);
}
const pk = platformKey();
const prefixed = process.env[`RNFB_${pk.toUpperCase()}_JET_PORT`];
if (prefixed) {
return parseInt(prefixed, 10);
}
return DEFAULT_JET[pk] ?? 8090;
};

exports.getJetRemoteUrl = function getJetRemoteUrl() {
const host = exports.getE2eEmulatorHost();
return `ws://${host}:${exports.getJetRemotePort()}`;
};

exports.getMetroPort = function getMetroPort() {
if (process.env.RCT_METRO_PORT) {
return parseInt(process.env.RCT_METRO_PORT, 10);
}
if (process.env.RNFB_METRO_PORT) {
return parseInt(process.env.RNFB_METRO_PORT, 10);
}
const pk = platformKey();
const prefixed = process.env[`RNFB_${pk.toUpperCase()}_METRO_PORT`];
if (prefixed) {
return parseInt(prefixed, 10);
}
return 8081;
};
9 changes: 7 additions & 2 deletions packages/auth/e2e/emailLink.e2e.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
const { getLastOob, signInUser } = require('./helpers');
const { getE2eEmulatorHost, getMetroPort } = require('../../app/e2e/helpers');

function emailLinkContinueUrl(random) {
return `http://${getE2eEmulatorHost()}:${getMetroPort()}/authLinkFoo?bar=${random}`;
}

describe('auth() -> emailLink Provider', function () {
beforeEach(async function () {
Expand Down Expand Up @@ -43,7 +48,7 @@ describe('auth() -> emailLink Provider', function () {
const auth = getAuth();
const random = Utils.randString(12, '#aa');
const email = `${random}@${random}.com`;
const continueUrl = `http://${Platform.android ? '10.0.2.2' : '127.0.0.1'}:8081/authLinkFoo?bar=${random}`;
const continueUrl = emailLinkContinueUrl(random);
const actionCodeSettings = {
url: continueUrl,
handleCodeInApp: true,
Expand Down Expand Up @@ -97,7 +102,7 @@ describe('auth() -> emailLink Provider', function () {
const auth = getAuth();
const random = Utils.randString(12, '#aa');
const email = `${random}@${random}.com`;
const continueUrl = `http://${Platform.android ? '10.0.2.2' : '127.0.0.1'}:8081/authLinkFoo?bar=${random}`;
const continueUrl = emailLinkContinueUrl(random);
const actionCodeSettings = {
url: continueUrl,
handleCodeInApp: true,
Expand Down
26 changes: 18 additions & 8 deletions packages/auth/e2e/helpers.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* eslint-disable no-console */
const { getE2eTestProject, getE2eEmulatorHost } = require('../../app/e2e/helpers');
const { getE2eTestProject, getE2eEmulatorHost, getE2eEmulatorPort } = require('../../app/e2e/helpers');

Check failure on line 2 in packages/auth/e2e/helpers.js

View workflow job for this annotation

GitHub Actions / Lint

Replace `·getE2eTestProject,·getE2eEmulatorHost,·getE2eEmulatorPort·` with `⏎··getE2eTestProject,⏎··getE2eEmulatorHost,⏎··getE2eEmulatorPort,⏎`

// Call HTTP REST API URL and return JSON response parsed into object
const callRestApi = async function callRestAPI(url, returnRedirectUrl = false) {
Expand Down Expand Up @@ -27,8 +27,9 @@
const response = await fetch(
'http://' +
getE2eEmulatorHost() +
':9099' +
'/emulator/v1/projects/' +
':' +
getE2eEmulatorPort('auth') +

Check failure on line 31 in packages/auth/e2e/helpers.js

View workflow job for this annotation

GitHub Actions / Lint

Insert `··`
'/emulator/v1/projects/' +

Check failure on line 32 in packages/auth/e2e/helpers.js

View workflow job for this annotation

GitHub Actions / Lint

Insert `··`
getE2eTestProject() +
'/accounts',
{
Expand All @@ -51,7 +52,8 @@
const response = await fetch(
'http://' +
getE2eEmulatorHost() +
':9099' +
':' +
getE2eEmulatorPort('auth') +
'/identitytoolkit.googleapis.com/v1/projects/' +
getE2eTestProject() +
'/accounts:update',
Expand All @@ -77,7 +79,9 @@
const getSmsCodesUrl =
'http://' +
getE2eEmulatorHost() +
':9099/emulator/v1/projects/' +
':' +
getE2eEmulatorPort('auth') +
'/emulator/v1/projects/' +
getE2eTestProject() +
'/verificationCodes';

Expand Down Expand Up @@ -117,7 +121,9 @@
const getOobCodesUrl =
'http://' +
getE2eEmulatorHost() +
':9099/emulator/v1/projects/' +
':' +
getE2eEmulatorPort('auth') +
'/emulator/v1/projects/' +
getE2eTestProject() +
'/oobCodes';

Expand Down Expand Up @@ -154,7 +160,9 @@
const resetPasswordUrl =
'http://' +
getE2eEmulatorHost() +
':9099/emulator/action?mode=resetPassword&lang=en&oobCode=' +
':' +
getE2eEmulatorPort('auth') +
'/emulator/action?mode=resetPassword&lang=en&oobCode=' +
oobCode +
'&apiKey=fake-api-key&newPassword=' +
newPassword;
Expand All @@ -165,7 +173,9 @@
const verifyEmailUrl =
'http://' +
getE2eEmulatorHost() +
':9099/emulator/action?mode=verifyEmail&lang=en&oobCode=' +
':' +
getE2eEmulatorPort('auth') +
'/emulator/action?mode=verifyEmail&lang=en&oobCode=' +
oobCode +
'&apiKey=fake-api-key';
return await callRestApi(verifyEmailUrl);
Expand Down
4 changes: 2 additions & 2 deletions packages/database/e2e/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
// eslint-disable-next-line no-console
console.warn = originalConsoleWarn;

const { getE2eTestProject, getE2eEmulatorHost } = require('../../app/e2e/helpers');
const { getE2eTestProject, getE2eEmulatorHost, getE2eEmulatorPort } = require('../../app/e2e/helpers');

Check failure on line 16 in packages/database/e2e/helpers.js

View workflow job for this annotation

GitHub Actions / Lint

Replace `·getE2eTestProject,·getE2eEmulatorHost,·getE2eEmulatorPort·` with `⏎··getE2eTestProject,⏎··getE2eEmulatorHost,⏎··getE2eEmulatorPort,⏎`

// TODO make more unique?
const ID = Date.now();
Expand Down Expand Up @@ -78,7 +78,7 @@
databaseName: DB_NAME,
rules: JSON.stringify(DB_RULES),
host: getE2eEmulatorHost(),
port: 9000,
port: getE2eEmulatorPort('database'),
},
}),
]);
Expand Down
7 changes: 4 additions & 3 deletions packages/firestore/e2e/helpers.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* eslint-disable no-console */
const { getE2eTestProject, getE2eEmulatorHost } = require('../../app/e2e/helpers');
const { getE2eTestProject, getE2eEmulatorHost, getE2eEmulatorPort } = require('../../app/e2e/helpers');

Check failure on line 2 in packages/firestore/e2e/helpers.js

View workflow job for this annotation

GitHub Actions / Lint

Replace `·getE2eTestProject,·getE2eEmulatorHost,·getE2eEmulatorPort·` with `⏎··getE2eTestProject,⏎··getE2eEmulatorHost,⏎··getE2eEmulatorPort,⏎`

/*
* Copyright (c) 2016-present Invertase Limited & Contributors
Expand All @@ -20,8 +20,9 @@

exports.wipe = async function wipe(debug = false, databaseId = '(default)', retries = 3) {
const host = getE2eEmulatorHost();
const fsPort = getE2eEmulatorPort('firestore');
const url =
`http://${host}:8080/emulator/v1/projects/` +
`http://${host}:${fsPort}/emulator/v1/projects/` +
getE2eTestProject() +
`/databases/${databaseId}/documents`;

Expand Down Expand Up @@ -105,7 +106,7 @@
databaseId = '(default)',
) {
const url =
`http://${getE2eEmulatorHost()}:8080/v1/projects/` +
`http://${getE2eEmulatorHost()}:${getE2eEmulatorPort('firestore')}/v1/projects/` +
getE2eTestProject() +
`/databases/${databaseId}/documents/${path}`;

Expand Down
Loading
Loading