Test Extension
Full-lifecycle manual testing of Firebase extensions against a production Firebase project.
Important: Always ask the user for their Firebase project ID before running any scripts. All scripts require PROJECT_ID to be set.
Quick Start
# 0. Set the target project (ask the user for this)
export PROJECT_ID="<user-provided-project-id>"
# 1. Build the extension
cd <extension>/functions && npm install && npm run build
# 2. Install the extension (interactive — user must run this)
# ! firebase ext:install ./<extension-dir> --project=$PROJECT_ID
# 3. Write test data to trigger the extension
.skills/test-extension/scripts/write-firestore-doc.sh <collection> '<json>'
# 4. Watch for completion
.skills/test-extension/scripts/watch-status.sh <collection> <doc-id>
# 5. Read the result
.skills/test-extension/scripts/read-firestore-doc.sh <collection>/<doc-id>
# 6. Clean up test data
.skills/test-extension/scripts/delete-firestore-doc.sh <collection>/<doc-id>
Prerequisites
- The user must be authenticated:
firebase loginorgcloud auth application-default login - The extension must already be installed on the target project, or install it first (see below)
PROJECT_IDenvironment variable must be set
Installing an Extension
firebase ext:install is interactive — there is no --params flag or non-interactive mode for providing configuration values. You cannot pipe or echo answers into it.
Option 1: Manual config files + deploy (recommended for agents)
This is the non-interactive approach. You create the config files and deploy:
Create
firebase.jsonat the repo root (if it doesn't exist):{ "extensions": { "<instance-id>": "./<extension-dir>" } }Create
extensions/<instance-id>.envwith the param values. See extension-specific reference docs for the correct params (e.g. references/multimodal-genai.md).For secret params (like
API_KEY), createextensions/<instance-id>.secret.local:API_KEY=<ask the user for this>Deploy:
firebase deploy --only extensions --project=$PROJECT_ID
Use Vertex AI as the provider when possible — it uses the project's service account for auth, so no API key secret is needed.
Option 2: Interactive install (user runs it)
Suggest the user runs the install command themselves:
! firebase ext:install ./<extension-dir> --project=$PROJECT_ID
The ! prefix runs it in the current session so the user can interact with the prompts.
Deployment Gotchas
- Do NOT use
--forcewithfirebase deploy --only extensions. It will delete all extension instances on the project that are not infirebase.json. - Instance ID conflicts: If an instance with the same ID already exists, use a different instance ID (e.g.
firestore-multimodal-genai-test). Use a unique collection name too to avoid conflicts with existing data. - Immutable params: Some params like
LOCATIONare immutable after install. If you need to change them, uninstall and reinstall. - Never hardcode or commit API keys or secrets. Always ask the user.
Checking Logs
After triggering an extension, check Cloud Function logs to verify behavior:
gcloud functions logs read ext-<instance-id>-<function-name> \
--project=$PROJECT_ID --limit=20 --region=<location>
The function name is typically generateText for Firestore-triggered GenAI extensions and generateOnCall for callable functions. The region must match the extension's LOCATION param.
Uninstalling
firebase ext:uninstall <instance-id> --project=$PROJECT_ID --force
This removes the extension and cleans up firebase.json and the .env file. It does NOT delete Firestore data created by the extension.
Extension Type Routing
Before testing, determine the extension's trigger type:
- Firestore-triggered (most GenAI extensions): Write a document to the configured collection. See references/firestore-extensions.md for per-extension details.
- Storage-triggered (image/video/audio extensions): Upload a file to the configured bucket. See references/storage-extensions.md.
- Other (Pub/Sub, HTTPS): See the extension's own test files for patterns.
Firestore Extension Testing Flow
- Write a document with the required input fields (e.g.
promptfor chatbot) - The extension triggers on the write and sets
status.statetoPROCESSING - On completion,
status.statebecomesCOMPLETEDand the response field is populated - If it fails,
status.statebecomesERROREDwithstatus.errorcontaining the message
Gotchas:
- The document must NOT already have the response field populated, or the extension skips it
- The document must NOT already have
status.stateset toPROCESSING,COMPLETED, orERRORED - To re-trigger, either create a new document or clear the response field and status
Storage Extension Testing Flow
- Upload a file to the configured storage bucket via
gsutilor the Firebase CLI - The extension triggers on
object.finalize - Output is typically written to a Firestore collection or a different storage bucket
- Check Firestore or the output bucket for results
Available Scripts
All scripts require PROJECT_ID to be set. They use the Firebase/Google Cloud REST APIs with application default credentials:
| Script | Purpose |
|---|---|
write-firestore-doc.sh |
Write a JSON document to a collection |
read-firestore-doc.sh |
Read a document or list a collection |
delete-firestore-doc.sh |
Delete a specific document |
watch-status.sh |
Poll a document until status.state matches a target |
Source: GoogleCloudPlatform/firebase-extensions — distributed by TomeVault.