Claude-skill-registry firebase-testing
Guide for testing Firebase Admin SDK with Vitest mocks. Use when writing tests that involve Firebase Auth, Firestore, or Firebase App.
install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/firebase-testing" ~/.claude/skills/majiayu000-claude-skill-registry-firebase-testing && rm -rf "$T"
manifest:
skills/data/firebase-testing/SKILL.mdsource content
Firebase Testing Patterns
This skill provides patterns for mocking Firebase Admin SDK in Vitest tests.
Mock Helpers Location
Firebase mocks are located in
app/tests/mocks/firebase.ts and provide:
- Mock Firebase App instancecreateFirebaseAppMock()
- Mock Firebase Auth with verifyIdToken, getUsercreateFirebaseAuthMock()
- Mock Firestore with collection, doc, getcreateFirestoreMock()
- Reset all mocks between testsresetFirebaseMocks()
Firebase Plugin Test Template
import Fastify from "fastify"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { createFirebaseAppMock, createFirebaseAuthMock, createFirestoreMock, } from "../../mocks/firebase.js"; const mockApp = createFirebaseAppMock(); const mockAuth = createFirebaseAuthMock(); const mockFirestore = createFirestoreMock(); vi.mock("firebase-admin/app", () => ({ getApps: vi.fn(() => [mockApp]), initializeApp: vi.fn(() => mockApp), cert: vi.fn(), })); vi.mock("firebase-admin/auth", () => ({ getAuth: vi.fn(() => mockAuth), })); vi.mock("firebase-admin/firestore", () => ({ getFirestore: vi.fn(() => mockFirestore), })); describe("Firebase Plugin", () => { beforeEach(() => { vi.clearAllMocks(); }); afterEach(async () => { // Clear module cache so dynamic imports get fresh mocked modules vi.resetModules(); }); it("should register firebase decorator", async () => { const { default: firebasePlugin } = await import( "../../../src/plugins/firebase.js" ); const fastify = Fastify(); await fastify.register(firebasePlugin); await fastify.ready(); expect(fastify.firebase).toBeDefined(); await fastify.close(); }); });
Auth Testing Patterns
Valid Token Authentication
it("should authenticate with valid token", async () => { const mockDecodedToken = { uid: "test-user-123", email: "test@example.com", email_verified: true, }; mockAuth.verifyIdToken.mockResolvedValue(mockDecodedToken); const response = await fastify.inject({ method: "GET", url: "/protected", headers: { authorization: "Bearer valid-token" }, }); expect(response.statusCode).toBe(200); expect(mockAuth.verifyIdToken).toHaveBeenCalledWith("valid-token", false); });
Invalid Token Handling
it("should return 401 for invalid token", async () => { mockAuth.verifyIdToken.mockRejectedValue( new Error("Firebase ID token has invalid signature"), ); const response = await fastify.inject({ method: "GET", url: "/protected", headers: { authorization: "Bearer invalid-token" }, }); expect(response.statusCode).toBe(401); });
Token Revocation
it("should return 401 when token is revoked", async () => { const revokedError = Object.assign(new Error("Token has been revoked"), { code: "auth/id-token-revoked", }); mockAuth.verifyIdToken.mockRejectedValue(revokedError); const response = await fastify.inject({ method: "GET", url: "/protected", headers: { authorization: "Bearer revoked-token" }, }); expect(response.statusCode).toBe(401); expect(response.json().message).toContain("Token has been revoked"); });
Missing Authorization Header
it("should return 401 when no authorization header", async () => { const response = await fastify.inject({ method: "GET", url: "/protected", }); expect(response.statusCode).toBe(401); });
Firestore Testing Patterns
Mocking Collection Queries
it("should query Firestore collection", async () => { const mockDocs = [ { id: "doc1", data: () => ({ name: "Test 1" }) }, { id: "doc2", data: () => ({ name: "Test 2" }) }, ]; mockFirestore.collection.mockReturnValue({ get: vi.fn().mockResolvedValue({ docs: mockDocs }), limit: vi.fn().mockReturnThis(), }); // Test code that queries Firestore });
Mocking Document Operations
it("should get a document", async () => { const mockDoc = { exists: true, id: "doc-id", data: () => ({ field: "value" }), }; mockFirestore.collection.mockReturnValue({ doc: vi.fn().mockReturnValue({ get: vi.fn().mockResolvedValue(mockDoc), }), }); // Test code that gets a document });
Key Patterns
- Mock before import: Use
at module level before importing tested modulesvi.mock() - Dynamic imports: Use
after mocks are set up to ensure mocks are appliedawait import() - Reset between tests:
in beforeEach - clears mock call historyvi.clearAllMocks()
in afterEach - clears module cache so dynamic imports get fresh mocked modulesvi.resetModules()
- Realistic data: Use realistic mock data that matches Firebase structures
Commands
cd app npm run test # Run all tests npm run test:coverage # Run tests with coverage
Boundaries
- Never use real Firebase credentials in tests
- Always mock Firebase Admin SDK modules
- Use the shared mock helpers from
tests/mocks/firebase.ts