- PHP 8.3, 8.4, 8.5, or 8.6
- Composer
- Node.js 20.12 or later
- Google Chrome to generate registration tokens and FIDs
- A Java Development Kit (JDK) for emulator tests (CI uses Java 21)
- The gRPC PHP extension for Firestore emulator and live integration tests
jqfor the service account command in step 13, or another way to compact the JSON
From the project root, install the project dependencies and test tools:
composer setup-
Go to the Firebase Console and create a new project. You don't need to enable Google AI assistance, or Google Analytics.
-
Go to the project settings and note down the project id.
-
In the project settings, create a new web app. The app nickname doesn't matter. After creating the app, note down the
App ID. From the app's SDK setup scripts, note down theapiKey. -
Enable the Firebase App Check API in the Google Cloud Console for the project.
-
Go to https://console.firebase.google.com/u/0/project/_/authentication/providers and enable the "Email/Password" (including "Email Link"), and "Anonymous" login methods.
-
Go to the Cloud Messaging tab and note down the
Sender ID. -
On the same page, in the "Web configuration" and "Web push certificates" sections, generate a new key pair and note down the public key. This is the VAPID key.
-
Go to the Service accounts tab and click on the "Generate new private key" button. This will download a JSON file containing your service account credentials.
-
Go to the Realtime Database and create a new database. Start it in "Lock mode" and note down the database URL. Note down the reference URL, it will look something like
https://<project-id>-default-rtdb.europe-west1.firebasedatabase.app/ -
Go to the Firestore Database and create a new database. Select the "Standard edition" and choose a location. The location doesn't matter, but it makes sense to use the same as one you chose for the realtime database. Start it in "Production mode". Don't enable backups. This is the default Firestore database, it is named
(default). You don't need to note this one down. -
(Optional) Create another Firestore database. This will ask you to update your plan to a pay-as-you-go plan and to link the Firebase Project to a Cloud Billing account. I haven't been charged so far, but usage on additional databases is billable. If you don't create a second Firestore database, some tests will be skipped. Create a second Firestore and name it
customor another name, note it down. -
(Optional) Create a new tenant in the Google Cloud Console of your project. You will be asked to enable the Cloud Identity Platform API. Then go to the Identity Platform settings, go to the "Security" tab. In the "Multi tenancy" section, click on the "Allow tenants" button. You will then be redirected to the tenants overview. Add a tenant and note down the tenant ID. If you don't create a tenant, some tests will be skipped. If you do create a tenant, select it in Identity Platform and enable anonymous and email/password authentication under Providers.
-
Compact the service account JSON file you downloaded in step 8 to one line, for example with
jq, and copy the output:jq -c . path/to/service-account.json -
Copy
tools/messaging/.env.disttotools/messaging/.envand fill in the values you obtained in the previous steps:FIREBASE_PROJECT_ID="project id from step 2" FIREBASE_APP_ID="app id from step 3" FIREBASE_API_KEY="apiKey from step 3" FIREBASE_MESSAGING_SENDER_ID="Sender ID from step 6" FIREBASE_VAPID_KEY="VAPID key from step 7"
-
With Google Chrome installed, generate a registration token and a Firebase Installation ID (FID). Each command prints one value:
node tools/messaging/generate.mjs token node tools/messaging/generate.mjs fid
-
Copy
tests/.env.disttotests/.envand fill in the values you obtained in the previous steps:TEST_FIREBASE_APP_ID="app id from step 3" TEST_FIREBASE_RTDB_URI="database URL from step 9" TEST_FIREBASE_TENANT_ID="tenant ID from step 12, optional" TEST_FIREBASE_INSTALLATION_IDS='["<FID from step 15>"]' TEST_REGISTRATION_TOKENS='["<registration token from step 15>"]' TEST_FIRESTORE_CUSTOM_DB_NAME="custom Firestore database name from step 11, optional" GOOGLE_APPLICATION_CREDENTIALS='<one-line JSON from step 13>'
For GitHub Actions secrets, use the JSON values without the outer .env quotes.
PHPUnit loads tests/.env through tests/bootstrap.php. Use composer reset-project only with a test project: it
reads tests/.env and deletes Realtime Database data and Auth users.
Run composer test:unit for unit tests, composer analyze for static analysis, or composer lint for Rector,
PHP-CS-Fixer, and Composer normalization. composer test:all runs these three checks together.
You should now be able to run the integration tests with composer test:integration.
After installing dependencies and tools with composer setup, run:
composer test:emulatorNo Firebase project, service account, Firebase CLI login, or tests/.env is needed. Emulator tests always use
demo-firebase-php, avoiding Firebase CLI requests for a real project's configuration. The Database namespace is
demo-firebase-php-default-rtdb.
The emulator bootstrap ignores tests/.env and replaces inherited credentials with synthetic service account metadata
and a freshly generated, test-only RSA signing key for custom token tests. Separate tests explicitly remove credentials
to cover credentialless Auth and Database clients. Tenant tests use demo-tenant.
The command starts the Auth, Realtime Database, and Firestore emulators on ports 9099, 9100, and 8080, runs
the tests in the emulator group, and stops the emulators afterward. It sets the emulator host variables for you.
The full live integration suite remains available through composer test:integration and the protected CI workflow.
Emulator tests run in ordinary pull request CI, including external contributor PRs, without secrets.
Firestore tests cover client construction and a document write/read/delete round trip with invalid credentials. The construction tests can also run separately without a running emulator or real credentials:
XDEBUG_MODE=off tools/phpunit tests/Integration/Factory/FirestoreEmulatorTest.phpAdditional PHPUnit options can be passed through the runner, for example:
composer test:emulator -- --filter=testSignInWithCustomTokenThe Composer command disables Xdebug. To collect coverage, invoke the runner directly with XDEBUG_MODE=coverage,
as CI does. The runner accepts the same PHPUnit options:
XDEBUG_MODE=coverage php tests/bin/run-emulator-tests.php --coverage-clover=build/emulator-coverage.xmlInstall dependencies and let the Firebase CLI download the Database and Firestore emulators while online before testing offline.
Then disconnect external networking, leaving loopback available, and run composer test:emulator again. The tests must
pass without access to Firebase or Google APIs. Firebase CLI update checks or telemetry may still attempt external
connections; failures of those optional requests must not prevent the tests from passing.
Run composer test:coverage to generate coverage for the full PHPUnit suite using the normal bootstrap. Live
integration tests require a configured test project and credentials. This command does not start emulators; collect
emulator coverage separately using the runner command above.
Before pushing, run composer pre-push, which fixes lint issues, runs static analysis, lint, unit tests, and a backward
compatibility check. Install and run the BC checker separately with PHP 8.5:
composer tools:bc:install
composer test:bcRepositories without tags are skipped. The BC checker is excluded from composer setup and composer tools:update
because its locked dependencies do not support PHP 8.3 or 8.6. Update it with composer tools:bc:update under PHP 8.5.
CI installs the same lockfile.