Chapter 26 · Testing, Emulator Suite, CI/CD, Index/Rules Deployment, and Schema Migration

Emulator Suite for Firestore / Auth / Functions-Like Integration Testing and Known Differences from Production

Test AtlasMart locally with Firestore/Auth/Functions-like flows while treating emulator gaps as explicit production-canary requirements.

Advanced · 180–240 minutesEmulator Suite · demo projects · Rules tests · production gaps · CINode 22+ · Firebase CLI course baseline 15.30.0 · JS SDK 12.19.0 · Admin SDK 14.4.0 · rules-unit-testing 5.0.2Mandatory lab demo project + Emulator Suite/no-cost · managed staging/production canaries explicitly optionalLast reviewed: 17 September 2026

1. AtlasMart release candidate: green locally, unknown in production

AtlasMart has a release candidate that passes unit tests, reads and writes correctly against the local Firestore emulator, and signs in through the Auth emulator. The team is tempted to call that “production verified.” That conclusion is too strong. The emulator is a behavioral development and integration environment, not a proof of managed indexes, quota enforcement, production contention, IAM, billing, network topology, App Check enforcement, recovery features, or production latency.

Chapter 26 turns that gap into an explicit delivery system. Local tests must prove deterministic application and Security Rules behavior; a small production canary must prove only the managed-service properties the emulator cannot model.

Learning outcomes
  • Connect Firestore/Auth/Functions-like flows to one demo project without accidental production access.
  • Use emulators:exec, deterministic reset, rules tests and shared seed state in CI.
  • Name the current Firestore emulator gaps around compound indexes, limits and transactions.
  • Separate mobile/web Rules authorization from Admin/server IAM authorization during tests.
  • Define a production-canary contract instead of treating emulator speed or success as capacity proof.
Execution and safety note

Use the Emulator Suite, a Firebase demo project, or an isolated test project for destructive, security-sensitive, billing-sensitive, migration, backup/restore, or write-heavy exercises unless the lesson explicitly marks managed verification as required. Treat shown output as expected evidence unless it is explicitly identified as captured output, and re-check current Firebase/Google Cloud edition, mode, quota, pricing, and security documentation before production execution.

Chapter 26 reproducibility baseline · reviewed 17 September 2026

AtlasMart keeps project ID demo-atlasmart-firestore, Standard-edition Native mode, database (default), Node.js 22+, Firebase CLI course baseline 15.30.0, Firebase JavaScript SDK 12.19.0, Firebase Admin Node SDK 14.4.0, @firebase/rules-unit-testing 5.0.2, Firestore emulator 127.0.0.1:8080, Auth emulator 127.0.0.1:9099, and Emulator UI 127.0.0.1:4000. Mandatory work uses a demo- project and local emulators only. Cloud deployment, IAM, App Check enforcement, billing, production indexes, quotas, contention, Query Insights/Key Visualizer, backup/PITR, and Enterprise/MongoDB-compatibility canaries are explicitly optional managed checks, never silently inferred from emulator success.

2. Vocabulary: what each test surface proves

Surface What it is What it proves What it does not prove
Firestore emulator Local implementation of the Firestore API and Rules engine. SDK request shape, document/query behavior, Rules evaluation, many transactions/listeners, trigger integration. Production composite-index readiness, all limits, production contention, billing, regional latency, IAM.
Auth emulator Local Firebase Authentication service. Client auth flows and locally issued emulator tokens used by Rules tests. Production identity-provider configuration, production token trust, abuse controls.
Functions emulator / functions-like worker Local Functions runtime or deterministic worker subscribed to local writes. Cross-service orchestration and idempotent handler behavior. Managed cold starts, Eventarc delivery characteristics, cloud IAM/networking.
Rules unit test @firebase/rules-unit-testing request under mocked auth. Allow/deny behavior for mobile/web Rules paths. Admin SDK authorization; server libraries bypass Rules.
Production canary Bounded request in an isolated managed environment. Only selected managed properties: index readiness, IAM, quotas, latency, billing/observability signals. Full-load safety unless the canary was designed for that exact load.

3. Use a demo project as the hard safety boundary

A Firebase demo project uses a demo- prefix and has no live resources. If code attempts to call a Firebase product whose emulator is not running, the request fails instead of falling through to production. That makes demo-atlasmart-firestore the right mandatory CI project ID.

firebase.json
{  "firestore": {    "rules": "firestore.rules",    "indexes": "firestore.indexes.json",    "edition": "standard"  },  "emulators": {    "auth": { "host": "127.0.0.1", "port": 9099 },    "firestore": { "host": "127.0.0.1", "port": 8080 },    "ui": { "host": "127.0.0.1", "port": 4000 }  }}
package.json scripts
{  "scripts": {    "test:rules": "node --test test/rules/*.test.mjs",    "test:integration": "node --test test/integration/*.test.mjs",    "ci:firebase": "firebase emulators:exec --project demo-atlasmart-firestore --only auth,firestore 'npm run test:rules && npm run test:integration'"  }}

All SDKs, emulators and locally emulated Functions must use the same project ID. That identity is how the suite wires Firestore/Auth/Functions interactions together.

4. Client path vs server path: test the correct trust boundary

Request path Local identity Authorization surface Production counterpart
Web/mobile Firestore SDK Auth emulator token Firestore Security Rules Firebase Auth + Rules; optional App Check is separate abuse-reduction control.
Admin/server SDK FIRESTORE_EMULATOR_HOST + project ID Emulator accepts server operations; Rules are bypassed. ADC/service identity + IAM; application-layer authorization remains your responsibility.
Firestore-triggered local function Local emulator event Handler code + local service configuration Managed trigger delivery, IAM and retries require cloud verification.
admin-emulator.mjs
process.env.FIRESTORE_EMULATOR_HOST = "127.0.0.1:8080";process.env.GCLOUD_PROJECT = "demo-atlasmart-firestore";import { initializeApp } from "firebase-admin/app";import { getFirestore } from "firebase-admin/firestore";initializeApp({ projectId: "demo-atlasmart-firestore" });export const db = getFirestore();
Safety rule

Never set FIRESTORE_EMULATOR_HOST or Auth-emulator environment variables in a production runtime. Make emulator wiring an explicit test-only configuration branch.

5. Known Firestore emulator differences are release-gate inputs

Difference Current emulator behavior Release consequence
Compound indexes The emulator does not track compound indexes and executes any otherwise valid query. A locally passing compound query still needs a managed staging/canary check and source-controlled index definition.
Limits Not all production limits are enforced. CI must include static checks against documented request/document/transaction limits and a bounded managed canary where necessary.
Transactions Not all production transaction behavior is reproduced; contention/locks can differ. Use emulator for correctness/retry/idempotency; use controlled pre-production load for contention and latency.
Named databases UI Backend can create named databases, but Emulator UI support is narrower than the service. Do not infer named-database production behavior from UI availability.
Performance/billing Local process, no managed billing/capacity model. Never publish emulator p95/p99 as production SLO or cost evidence.

6. Rules-first integration test with clean state

test/rules/products.test.mjs
import fs from "node:fs";import test from "node:test";import assert from "node:assert/strict";import {  initializeTestEnvironment,  assertSucceeds,  assertFails} from "@firebase/rules-unit-testing";import { doc, getDoc, setDoc } from "firebase/firestore";let env;test.before(async () => {  env = await initializeTestEnvironment({    projectId: "demo-atlasmart-firestore",    firestore: { rules: fs.readFileSync("firestore.rules", "utf8") }  });});test.beforeEach(async () => {  await env.clearFirestore();  await env.withSecurityRulesDisabled(async ctx => {    await setDoc(doc(ctx.firestore(), "products", "sku-red-1"), {      tenantId: "t-red", visibility: "tenant", active: true,      schemaVersion: 1, name: "Red Mug"    });  });});test("tenant can read own product", async () => {  const db = env.authenticatedContext("u-red", { tenantId: "t-red" }).firestore();  await assertSucceeds(getDoc(doc(db, "products", "sku-red-1")));});test("other tenant is denied", async () => {  const db = env.authenticatedContext("u-blue", { tenantId: "t-blue" }).firestore();  await assertFails(getDoc(doc(db, "products", "sku-red-1")));});test.after(async () => env.cleanup());

withSecurityRulesDisabled seeds fixtures without converting your fixture loader into a privileged production pattern. Each request test then executes with an explicit auth context.

7. Functions-like integration: assert idempotency, not delivery folklore

local-order-worker.mjs
export async function handleOrderCreated(event, db) {  const eventRef = db.doc(`eventReceipts/${event.id}`);  const orderRef = db.doc(`orders/${event.orderId}`);  await db.runTransaction(async tx => {    const receipt = await tx.get(eventRef);    if (receipt.exists) return; // duplicate delivery is harmless    tx.set(eventRef, { processedAt: event.now, source: "order-created" });    tx.update(orderRef, { workflowState: "accepted" });  });}

The local test can deliberately invoke the handler twice with the same event ID and assert one receipt and one state transition. It does not claim a particular production event-delivery latency or ordering guarantee.

8. Mandatory lab: CI contract

  1. Save firebase.json, firestore.rules, and firestore.indexes.json under version control.
  2. Use demo-atlasmart-firestore; verify no non-emulated product is required by the mandatory tests.
  3. Run firebase emulators:exec --project demo-atlasmart-firestore --only auth,firestore "npm run test:rules && npm run test:integration".
  4. At test start, clear Firestore or import a known seed; never depend on prior emulator state.
  5. Capture Rules test results, rule coverage endpoint, migration-version counts, and backfill checkpoints as CI artifacts.
  6. Maintain a separate production-canary checklist for indexes, IAM, limits, App Check, billing/metrics and latency.
Expected state

CI is repeatable from a clean clone, all local tests target the demo project, a denied cross-tenant Rules case is asserted, duplicate worker delivery is idempotent, and the release report explicitly lists production-only gaps.

9. Controlled failure: emulator as performance oracle

Wrong approach: run 20,000 local writes, observe a high operations/second number, then size production around it. The local process has different storage, networking, index enforcement and contention behavior. The number answers “how fast did this laptop/emulator execute this script?”—not “what production can sustain?”

Repair: keep the emulator benchmark only as a regression detector for your code path. Define a separate, bounded, billable pre-production load test with stop conditions and compare p50/p95/p99, errors, Query Explain/index evidence, and cost signals there.

Production judgment and bridge

A strong CI pipeline does not maximize emulator coverage; it assigns each requirement to the cheapest environment that can actually prove it. Local tests should be exhaustive for deterministic business logic and Rules. Cloud tests should be narrow, isolated and evidence-driven for managed-service properties. Lesson 2 makes that local layer reproducible under seed/reset, clocks, IDs and parallelism.

Knowledge check

  1. Why is a demo project safer than a real project for mandatory CI?
  2. What production property cannot be proven by a compound query passing in the emulator?
  3. Why must Admin SDK tests not be interpreted as Rules tests?
  4. What should a Functions-like test assert under duplicate delivery?
  5. What belongs in the production-canary contract?
Review the answers

1. A demo project has no live resources, so missing emulator coverage fails rather than falling through to production and billing.

2. Production composite-index existence/readiness; the emulator does not track compound indexes.

3. Server/Admin clients bypass Security Rules and use IAM in production.

4. Idempotency: a duplicate event must not duplicate the business effect.

5. Only managed properties the emulator cannot prove: indexes, IAM/App Check, real limits, contention/latency, observability/billing, backups/PITR and edition-specific behavior.

Summary and next step

This lesson established the working contract for Emulator Suite for Firestore/Auth/Functions-Like Integration Testing and Known Differences from Production. Keep its edition/mode assumptions, trust boundary, verification evidence, and operational constraints explicit when reusing the pattern.

Next, continue to Seed/Reset Test Data, Deterministic IDs/Clock Handling, and Parallel Test Isolation.

Authoritative references

Keep knowledge open

Help the academy stay free and grow.

If these tutorials save you time, a small donation supports new lessons, technical review, diagrams, examples, and long-term maintenance.

ETHEthereum / ERC-20 only
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0

Send only Ethereum or ERC-20 compatible assets to this address.