Skip to content

Commit 77018d7

Browse files
authored
chore(firestore): improve contributor documentation and test infra (#9864)
1 parent 8daacbf commit 77018d7

3 files changed

Lines changed: 135 additions & 54 deletions

File tree

packages/firestore/CONTRIBUTING.md

Lines changed: 98 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -7,70 +7,118 @@ the testing environment.
77

88
## Integration Testing
99

10-
### Setting up a project for testing
10+
### Setting up the Firestore emulator
1111

12-
You will need a production project to test the Firestore SDK. You can create
13-
a new project by visiting the
14-
[Firebase Console](https://console.firebase.google.com/). Make sure that the
15-
project has Cloud Firestore enabled in the database section of the console.
12+
Integration tests that run against the Firestore emulator expect
13+
that it runs on port 8080.
14+
15+
- [Install the Firebase CLI](https://firebase.google.com/docs/cli/).
16+
```bash
17+
npm install -g firebase-tools
18+
```
19+
- [Install the Firestore emulator](https://firebase.google.com/docs/firestore/security/test-rules-emulator#install_the_emulator).
20+
```bash
21+
firebase setup:emulators:firestore
22+
```
23+
- Run the emulator:
24+
```bash
25+
firebase emulators:start --only firestore
26+
```
27+
28+
## Testing Firestore
29+
30+
Testing Firestore is organized along three dimensions:
31+
32+
1. **Environment**: Where the code runs.
33+
- **Node.js**: Fast, V8-based testing using Mocha. Perfect for logic that doesn't require a browser.
34+
- **Browsers**: Uses Karma to run tests in real browser engines (Chrome, Firefox, WebKit). Essential for testing IndexedDB and WebChannels.
35+
2. **SDK Type**: Which version of the SDK is being tested.
36+
- **Full SDK**: Includes real-time listeners, offline persistence, and caching.
37+
- **Lite SDK**: A REST-only, lightweight version without persistence or real-time support.
38+
3. **Backend**: Which server the tests communicate with.
39+
- **Emulator**: Local server (default).
40+
- **Production**: The live Firebase backend.
41+
- **Nightly**: Pre-release backend for catching upcoming server changes.
42+
43+
### Running Tests
44+
45+
All commands must be run from the `packages/firestore/` directory.
46+
47+
```bash
48+
# Full SDK - Node (Emulator)
49+
yarn test:node
1650

17-
See
18-
[Automated Setup](https://github.com/firebase/firebase-js-sdk#automated-setup)
19-
for more details.
51+
# Full SDK - Browser (Chrome Headless, Emulator)
52+
yarn test:browser
2053

21-
### Setting up the Firestore emulator
54+
# Lite SDK - Node (Emulator)
55+
yarn test:lite
2256

23-
The integration tests require that the Firestore emulator is running
24-
on port 8080, which is default when running it via CLI.
57+
# Lite SDK - Browser (Chrome Headless, Emulator)
58+
yarn test:lite:browser
59+
```
2560

26-
* [Install the Firebase CLI](https://firebase.google.com/docs/cli/).
27-
```
28-
npm install -g firebase-tools
29-
```
30-
* [Install the Firestore
31-
emulator](https://firebase.google.com/docs/firestore/security/test-rules-emulator#install_the_emulator).
32-
```
33-
firebase setup:emulators:firestore
34-
```
35-
* Run the emulator
36-
```
37-
firebase emulators:start --only firestore
38-
```
61+
### Environment Variables & Flags
3962

40-
### Running Firestore Tests
63+
Use these variables to change the target backend or database:
4164

42-
All commands must be run from the `packages/firestore/` directory.
65+
- **`FIRESTORE_TARGET_BACKEND`**: Set to `emulator`, `prod`, or `nightly`. `nightly` is only available to Googlers.
66+
- **`FIRESTORE_TARGET_DB_ID`**: Targets a specific database ID (default is `(default)`).
67+
- **`--firestoreEdition=enterprise`**: Enables enterprise-specific tests (sets `RUN_ENTERPRISE_TESTS=true`).
68+
- **`BROWSERS`**: (Browser tests only) A comma-separated list of browsers: `ChromeHeadless`, `Firefox`, `WebkitHeadless`.
69+
- Example: `BROWSERS=Firefox,WebkitHeadless yarn test:browser`
4370

44-
```
45-
# Come up to date on dependencies after performing git pull
46-
(cd ../../; yarn && yarn build)
71+
### Persistence
4772

48-
# Run all tests once (browser and node)
49-
yarn test
73+
- **Browsers**: Persistence (IndexedDB) is tested natively.
74+
- **Node.js**: Node lacks a native database. Use `yarn test:node:persistence` to enable a mock persistence layer for testing offline logic in Node.
5075

51-
# Run all browser tests once (unit and integration)
52-
yarn test:browser
76+
### Filtering Tests (Grep)
5377

54-
# Debug browser tests in Chrome and keep the browser open (and watch for file
55-
# changes).
56-
yarn test:browser:debug
78+
Use the `--grep` flag to run specific tests.
5779

58-
# Run only the browser unit or integration tests
59-
yarn test:browser --unit
60-
yarn test:browser --integration
80+
```bash
81+
yarn test:node --grep 'SortedSet'
82+
yarn test:browser --grep 'Query'
83+
```
6184

62-
# Run browser integration tests against a Firestore server running on
63-
# localhost:8080.
64-
yarn test:browser:emulator --integration
85+
## Testing Firestore Pipelines
6586

66-
# Run all node tests once (unit and integration) against the emulator.
67-
yarn test:node
87+
### Enterprise Edition & Database IDs
88+
89+
To test Pipeline features that require the Enterprise backend:
90+
91+
- **Named Databases**: Use a database ID other than `(default)`. In our automated tests, we typically use the ID `enterprise`.
92+
- **Edition Flag**: Pass `--firestoreEdition=enterprise` to enable Enterprise-specific test cases and assertions.
6893

69-
# Run a subset of tests whose names match a filter.
70-
yarn test:browser --grep 'SortedSet keeps elements in the right order'
71-
yarn test:node --grep 'SortedSet keeps elements in the right order'
94+
Example: Running Pipeline integration tests against production with an enterprise database:
7295

73-
# Run tests against the production backend.
74-
yarn test:node:prod
75-
yarn test:node:persistence:prod
96+
```bash
97+
yarn test:node:prod:enterprise --grep 'Pipeline'
7698
```
99+
100+
### Testing Environments for Pipelines
101+
102+
- **Emulator**: Supports basic pipeline structures and some aggregations.
103+
- **Nightly**: Preferred for testing new Pipeline features before they reach Production. Use `FIRESTORE_TARGET_BACKEND=nightly`.
104+
- **Production**: Used for final validation of released Pipeline features.
105+
106+
## Debugging
107+
108+
### CLI Debugging
109+
110+
We provide `:debug` scripts that wait for a debugger to attach:
111+
112+
- **Node**: `yarn test:node:debug` (uses `node --inspect-brk`).
113+
- **Browser**: `yarn test:browser:debug` (keeps Chrome open and watches for file changes).
114+
115+
### VSCode Debugging
116+
117+
Use the **Run and Debug** pane in VSCode. Recommended configurations:
118+
119+
- **Firestore Unit Tests (Node)**: Fast debugging for Node logic.
120+
- **Firestore Integration Tests (Node)**: Debugs against the emulator.
121+
- **Firestore Integration Tests (Browser)**: Debugs in Chrome.
122+
- **Firestore Enterprise Lite Tests**: Debugs Lite SDK against Nightly/Enterprise.
123+
124+
Most configurations will prompt you for a `grepString` to filter tests before starting.

packages/firestore/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@
4545
"test:node": "ts-node ./scripts/run-tests.ts --main=test/register.ts --emulator 'test/{,!(browser|lite)/**/}*.test.ts'",
4646
"test:node:prod": "ts-node ./scripts/run-tests.ts --main=test/register.ts 'test/{,!(browser|lite)/**/}*.test.ts'",
4747
"test:node:prod:enterprise": "ts-node ./scripts/run-tests.ts --main=test/register.ts --databaseId=enterprise --firestoreEdition=enterprise 'test/{,!(browser|lite)/**/}*.test.ts'",
48+
"test:node:nightly": "ts-node ./scripts/run-tests.ts --main=test/register.ts 'test/{,!(browser|lite)/**/}*.test.ts' --targetBackend=nightly",
49+
"test:node:debug": "ts-node ./scripts/run-tests.ts --main=test/register.ts --emulator --debug 'test/{,!(browser|lite)/**/}*.test.ts'",
4850
"test:node:persistence": "ts-node ./scripts/run-tests.ts --main=test/register.ts --persistence --emulator 'test/{,!(browser|lite)/**/}*.test.ts'",
4951
"test:node:persistence:prod": "ts-node ./scripts/run-tests.ts --main=test/register.ts --persistence 'test/{,!(browser|lite)/**/}*.test.ts'",
5052
"test:travis": "ts-node --compiler-options='{\"module\":\"commonjs\"}' ../../scripts/emulator-testing/firestore-test-runner.ts",

packages/firestore/scripts/run-tests.ts

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,14 @@ const argv = yargs
4646
type: 'string',
4747
description: 'Filter tests by name (regex)'
4848
},
49+
targetBackend: {
50+
type: 'string',
51+
description: 'The backend to test against (emulator, prod, nightly)'
52+
},
53+
debug: {
54+
type: 'boolean',
55+
description: 'Run tests in debug mode (node --inspect-brk)'
56+
}
4957
})
5058
.parseSync();
5159

@@ -57,6 +65,11 @@ const babel = resolve(__dirname, '../babel-register.js');
5765
process.env.NO_TS_NODE = 'true';
5866
process.env.TEST_PLATFORM = argv.platform;
5967

68+
if (argv.targetBackend) {
69+
process.env.FIRESTORE_TARGET_BACKEND = argv.targetBackend;
70+
}
71+
72+
let executable = nyc;
6073
let args = [
6174
'--reporter',
6275
'lcovonly',
@@ -69,6 +82,22 @@ let args = [
6982
'../../config/mocharc.node.js'
7083
];
7184

85+
if (argv.debug) {
86+
// Bypassing nyc for debug mode
87+
executable = 'node';
88+
args = [
89+
'--inspect-brk',
90+
mocha,
91+
'--require',
92+
babel,
93+
'--require',
94+
argv.main,
95+
'--config',
96+
'../../config/mocharc.node.js',
97+
'--no-timeouts'
98+
];
99+
}
100+
72101
if (argv.emulator) {
73102
process.env.FIRESTORE_TARGET_BACKEND = 'emulator';
74103
}
@@ -94,7 +123,7 @@ if (argv.grep) {
94123

95124
args = args.concat(argv._ as string[]);
96125

97-
const spawnPromise = spawn(nyc, args, {
126+
const spawnPromise = spawn(executable, args, {
98127
stdio: 'inherit',
99128
cwd: process.cwd()
100129
});
@@ -104,11 +133,13 @@ const childProcess = spawnPromise.childProcess;
104133
spawnPromise.catch(error => {
105134
// When a test fails, there will be a non-zero error code. Simply exit this process,
106135
// and don't print a stack trace.
107-
if (typeof error.code === 'number') {
136+
// Note: error.code is the exit code of the spawned process.
137+
if (typeof error.code === 'number' && error.code > 0) {
138+
// If it's a standard test failure (mocha exit code), we don't need a runner stack trace.
108139
process.exit(error.code);
109140
} else {
110-
// The error code will not be a number for a real crash (e.g., spawn
111-
// failed to start), so print the entire stack trace for debugging.
141+
// For other errors (spawn failed, runner crash, etc.), print the stack trace.
142+
console.error('Test runner failed to execute:');
112143
console.error(error);
113144
process.exit(1);
114145
}

0 commit comments

Comments
 (0)