# Test Extension

> 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. Use when this capability is needed.

- Skill: `tomevault-io/test-extension` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add tomevault-io/test-extension`
- Raw SKILL.md: https://api.skillmd.com/api/skills/tomevault-io/test-extension/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: tomevault-io (https://skillmd.com/u/tomevault-io)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/tomevault-io/test-extension

---


# 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

```bash
# 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 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:

1. Create `firebase.json` at the repo root (if it doesn't exist):
   ```json
   {
     "extensions": {
       "<instance-id>": "./<extension-dir>"
     }
   }
   ```

2. Create `extensions/<instance-id>.env` with the param values. See extension-specific reference docs for the correct params (e.g. [references/multimodal-genai.md](references/multimodal-genai.md)).

3. For secret params (like `API_KEY`), create `extensions/<instance-id>.secret.local`:
   ```
   API_KEY=<ask the user for this>
   ```

4. 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:

```bash
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

```bash
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](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](references/storage-extensions.md).
- **Other** (Pub/Sub, HTTPS): See the extension's own test files for patterns.

## Firestore Extension Testing Flow

1. Write a document with the required input fields (e.g. `prompt` for chatbot)
2. The extension triggers on the write and sets `status.state` to `PROCESSING`
3. On completion, `status.state` becomes `COMPLETED` and the response field is populated
4. 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

1. Upload a file to the configured storage bucket via `gsutil` or the Firebase CLI
2. The extension triggers on `object.finalize`
3. Output is typically written to a Firestore collection or a different storage bucket
4. 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](https://github.com/GoogleCloudPlatform/firebase-extensions) — distributed by [TomeVault](https://tomevault.io).
<!-- tomevault:4.0:skill_md:2026-06-17 -->

