firebase / firebase-functions-test

MIT License
232 stars 48 forks source link

Unit Testing: storageBucket not being passed by testEnv #91

Closed lloydrichards closed 3 years ago

lloydrichards commented 3 years ago

Version info

firebase-functions-test: 9.6.0

firebase-functions: 3.13.2

firebase-admin: 9.2.0

Test case

I have a unit test at the moment that is checking if a firebase function is correctly adding a file to my apps bucket. In the function I'm mostly using @google-cloud/storage but need to get the bucket name. At the head of the function, I call const bucket = gcs.bucket(admin.storage().bucket().name); in order to create a new Bucket(). This works fine when deployed but when running unit tests using firebase-functions-test I get errors saying the bucket is unspecified.

Steps to reproduce

  1. Have function using admin.storage().bucket()
  2. Setup a unit test that wraps the function in a testEnv
  3. Setup test to run the function with mock data
  4. Run test
import * as functions from "firebase-functions-test";
import "jest";
import { apiaryUpdated } from "../index";
import { mock_apiaryAfter, mock_apiaryBefore } from "./Mock/mock_apairy";

const testEnv = functions(
  {
    databaseURL: "https://hive-manager-2021-dev.firebaseio.com",
    storageBucket: "hive-manager-2021-dev.appspot.com",
    projectId: "hive-manager-2021-dev",
  },
  "./service-account.json"
);

describe("Apiary Tests", () => {
  let wrappedOnUpdate: any;

  beforeAll(() => {
    wrappedOnUpdate = testEnv.wrap(apiaryUpdated);
  });
  afterAll(() => {
    testEnv.cleanup();
  });

  test("Create Geo Thumb", async () => {
    const path = "Apiaries/--TEST APIARY--";
    const beforeSnap = testEnv.firestore.makeDocumentSnapshot(
      mock_apiaryBefore,
      path
    );
    const afterSnap = testEnv.firestore.makeDocumentSnapshot(
      mock_apiaryAfter,
      path
    );
    const changedSnap = testEnv.makeChange(beforeSnap, afterSnap);

    await wrappedOnUpdate(changedSnap);

    const after = await admin.firestore().doc(path).get();

    expect(after.data()?.picture.thumb).toBeTruthy();
  });
});

Expected behavior

In jest I'm expecting the test to run and see whether the expected value is true or false

Actual behavior

Get this error saying the storageBucket isn't set, even though it clearly is.

  ● Console

    console.warn
      {"severity":"WARNING","message":"Warning, FIREBASE_CONFIG and GCLOUD_PROJECT environment variables are missing. Initializing 
firebase-admin will fail"}

      at write (node_modules/firebase-functions/lib/logger.js:39:78)
      at Object.warn (node_modules/firebase-functions/lib/logger.js:90:5)
      at Object.setup (node_modules/firebase-functions/lib/setup.js:56:22)
      at Object.<anonymous> (node_modules/firebase-functions/lib/index.js:69:9)

  ● Apiary Tests › Create Geo Thumb

    Bucket name not specified or invalid. Specify a valid bucket name via the storageBucket option when initializing the app, or specify the bucket name explicitly when calling the getBucket() method.

      18 |   let newThumb = "";
      19 | 
    > 20 |   const bucket = gcs.bucket(admin.storage().bucket().name);
         |                                             ^
      21 | 
      22 |   const workingDir = join(tmpdir(), "thumbs");
      23 |   const timestamp = Math.floor(Date.now() / 1000);

      at new FirebaseError (node_modules/firebase-admin/lib/utils/error.js:43:28)
      at Storage.Object.<anonymous>.Storage.bucket (node_modules/firebase-admin/lib/storage/storage.js:111:15)
      at Object.<anonymous>.exports.getStaticMapThumb (src/Apiary/ApiaryThumb.ts:20:45)
      at Function.run (src/Apiary/ApiaryUpdated.ts:41:30)
      at wrapped (node_modules/firebase-functions-test/lib/main.js:72:30)
      at Object.<anonymous> (src/Test/apiary.online.test.ts:38:11)
lloydrichards commented 3 years ago

Solved my own problem 😅

Looks like I needed to import functions inside the beforeAll()

describe("Apiary Tests", () => {
  let MyFunctions;
  let wrappedOnUpdate: WrappedScheduledFunction | WrappedFunction;

  beforeAll(() => {
    MyFunctions = require("../index");
    wrappedOnUpdate = testEnv.wrap(MyFunctions.apiaryUpdated);

    return admin.firestore().doc(path).set(mock_apiaryDoc);
  });
  afterAll(() => {
    testEnv.cleanup();
  });
...

Just incase someone else has the same problem

joehan commented 3 years ago

Love this type of issue! 😄 Glad you were able to figure it out, closing this as part of a repo cleanup.