title: Error Mocking Firebase Admin in Jest: "TypeError: admin.firestore is not a function"
body: <p>I have a function to handle connecting to Cloud Firestore through the Admin SDK. I know the function works fine, as the app connects and allows writing to the database.</p>
  
  <p>Now I am trying to test this function with Jest. To avoid testing outside the scope of this function, I am mocking the firebase-admin Node module. However, my test is failing with the error "TypeError: admin.firestore is not a function".</p>
  
  <p>My function and tests are both written in TypeScript, run via ts-jest, but I don't think this is a TypeScript error, as VS Code has no complaints. I believe this is an issue with Jest's automatic mocking.</p>
  
  <p><code>admin.firebase()</code> is a valid call. The TypeScript definition file defines it as <code>function firestore(app?: admin.app.App): admin.firestore.Firestore;</code></p>
  
  <p>I've read over the Jest docs, but I'm not understanding how to fix this.</p>
  
  <p>This is my function:</p>
  
  <pre><code>// /src/lib/database.ts
  
  import * as admin from "firebase-admin"
  
  /**
   * Connect to the database
   * @param key - a base64 encoded JSON string of serviceAccountKey.json
   * @returns - a Cloud Firestore database connection
   */
  export function connectToDatabase(key: string): FirebaseFirestore.Firestore {
    // irrelevant code to convert the key
  
    try {
      admin.initializeApp({
        credential: admin.credential.cert(key),
      })
    } catch (error) {
      throw new Error(`Firebase initialization failed. ${error.message}`)
    }
  
    return admin.firestore() // this is where it throws the error
  }
  </code></pre>
  
  <p>Here is my test code:</p>
  
  <pre><code>// /tests/lib/database.spec.ts
  
  jest.mock("firebase-admin")
  import * as admin from "firebase-admin"
  import { connectToDatabase } from "@/lib/database"
  
  describe("database connector", () =&gt; {
    it("should connect to Firebase when given valid credentials", () =&gt; {
      const key = "ewogICJkdW1teSI6ICJUaGlzIGlzIGp1c3QgYSBkdW1teSBKU09OIG9iamVjdCIKfQo=" // dummy key
  
      connectToDatabase(key) // test fails here
  
      expect(admin.initializeApp).toHaveBeenCalledTimes(1)
      expect(admin.credential.cert).toHaveBeenCalledTimes(1)
      expect(admin.firestore()).toHaveBeenCalledTimes(1)
    })
  })
  </code></pre>
  
  <p>Here are my relevant (or possibly relevant) package.json (installed with Yarn v1):</p>
  
  <pre><code>{
    "dependencies": {
      "@firebase/app-types": "^0.6.0",
      "@types/node": "^13.13.5",
      "firebase-admin": "^8.12.0",
      "typescript": "^3.8.3"
    },
    "devDependencies": {
      "@types/jest": "^25.2.1",
      "expect-more-jest": "^4.0.2",
      "jest": "^25.5.4",
      "jest-chain": "^1.1.5",
      "jest-extended": "^0.11.5",
      "jest-junit": "^10.0.0",
      "ts-jest": "^25.5.0"
    }
  }
  </code></pre>
  
  <p>And my jest config:</p>
  
  <pre class="lang-js prettyprint-override"><code>// /jest.config.js
  
  module.exports = {
    setupFilesAfterEnv: ["jest-extended", "expect-more-jest", "jest-chain"],
    preset: "ts-jest",
    errorOnDeprecated: true,
    testEnvironment: "node",
    moduleNameMapper: {
      "^@/(.*)$": "&lt;rootDir&gt;/src/$1",
    },
    moduleFileExtensions: ["ts", "js", "json"],
    testMatch: ["&lt;rootDir&gt;/tests/**/*.(test|spec).(ts|js)"],
    clearMocks: true,
  }
  </code></pre>