| name | test-extension |
| description | Test Firebase extensions end-to-end against a real Firebase project. Use when the user asks to test, verify, or debug an extension — covers building, installing, writing test data, triggering, and verifying output. |
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
export PROJECT_ID="<user-provided-project-id>"
cd <extension>/functions && npm install && npm run build
.skills/test-extension/scripts/write-firestore-doc.sh <collection> '<json>'
.skills/test-extension/scripts/watch-status.sh <collection> <doc-id>
.skills/test-extension/scripts/read-firestore-doc.sh <collection>/<doc-id>
.skills/test-extension/scripts/delete-firestore-doc.sh <collection>/<doc-id>
Prerequisites
- The user must be authenticated:
firebase login or gcloud auth application-default login
- The extension must already be installed on the target project, or install it first (see below)
PROJECT_ID environment 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.json at the repo root (if it doesn't exist):
{
"extensions": {
"<instance-id>": "./<extension-dir>"
}
}
-
Create extensions/<instance-id>.env with the param values. See extension-specific reference docs for the correct params (e.g. references/multimodal-genai.md).
-
For secret params (like API_KEY), create extensions/<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
--force with firebase deploy --only extensions. It will delete all extension instances on the project that are not in firebase.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
LOCATION are 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.
prompt for chatbot)
- The extension triggers on the write and sets
status.state to PROCESSING
- On completion,
status.state becomes COMPLETED and the response field is populated
- If it fails,
status.state becomes ERRORED with status.error containing 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.state set to PROCESSING, COMPLETED, or ERRORED
- 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
gsutil or 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 |