为什么我在使用模拟器执行测试时仍然从生产中获取 firestore 数据?

why I am still getting firestore data from production when performing testing using emulator?

我正在使用

我正在尝试对预定的云功能执行单元测试。我的云函数是这样的

export const deleteExpiredEvents = functions
.pubsub.schedule("0 0 * * *") 
.timeZone("Asia/Jakarta")
.onRun(async (context) => {

    // delete expired events


});

我这样测试上面的功能

import * as admin from "firebase-admin";
import * as firebase from "firebase-functions-test";

const test = firebase({
  databaseURL: "https://xxxx.firebaseio.com",
  projectId: projectID,
}, "./service-account.json");

const db = admin.initializeApp().firestore();

beforeEach( async () => {
    // create dummy expired event
   
    await db.doc(`events/${event1.eventID}`).set(event1);
    await db.doc(`events/${event2.eventID}`).set(event2);
    await db.doc(`events/${event3.eventID}`).set(event3);
});

it("should not delete events that not expired", async () => {
 
     const wrap = test.wrap(myFunctions.deleteExpiredEvents);

     const context = {};  
     wrap(context); // execute function
        
     const querySnapshot = await db.collection("events").get();
     querySnapshot.docs.forEach((snapshot) => console.log(snapshot.data().eventID));
        
     // the rest of my code test ....
});

正如您从上面的代码中看到的,在 before 块中,我尝试创建虚拟事件数据,因此我希望我的 firestore 模拟器将填充这 3 个虚拟事件数据。

然后在 it 块中,我尝试获取所有事件,然后 console.log 所有 eventIDs

我预计我将从之前在 before 块中创建的 firestore 模拟器获得 3 个事件,但我不知道为什么我获得 74 个事件(而不是仅仅 3 个),它来自 firestore生产数据,不是来自 firestore 模拟器

我相信我在执行测试时已经 运行 firebase emulators:start 、firestore、函数和 pubsub 模拟器 运行ning。

为什么我在模拟器启动后仍然从生产中获取 firestore 数据?

我尝试从这里阅读文档:https://firebase.google.com/docs/emulator-suite/connect_firestore

据说:

The Firebase Admin SDKs automatically connect to the Cloud Firestore emulator when the FIRESTORE_EMULATOR_HOST environment variable is set:

export FIRESTORE_EMULATOR_HOST="localhost:8080"

所以我运行

export FIRESTORE_EMULATOR_HOST="localhost:8080"

然后

firebase emulators:start

它仍然从生产中获取数据。事实上,如果我断开互联网连接,测试将不会 运行!

我不知道为什么要检查

console.log(process.env.FIRESTORE_EMULATOR_HOST); // I expect, it will be will be "localhost:8080"
console.log(process.env.FUNCTIONS_EMULATOR); // I expect, it will be "true"

但我会得到两个值的 undefined,就像这样

看完后github issue in here。我终于找到解决办法了!

首先,在您的 package.json 中,编写您的测试脚本。我的脚本是这样的

"scripts": {
    "test-security-rules": "mocha -r ts-node/register src/tests/firestore_security_rules_tests --recursive --extension .test.ts --timeout 60000 --exit",
    "test-cloud-functions": "mocha -r ts-node/register src/tests/cloud_function_tests --recursive --extension .test.ts --timeout 60000 --exit"
  }

关闭模拟器,不要 运行 firebase emulators:start .但执行

firebase emulators:exec "npm run test-cloud-functions"

然后如果你打印

console.log(process.env.FIRESTORE_EMULATOR_HOST);

该值将不再是未定义的,但在我的情况下它将是 "localhost:8080"

这里是 documentation 关于 exec

更新到最新的 firestore 模拟器后 (v1.11.14.jar)

我想我找到了这个解决方案

  1. 运行 你的模拟器像往常一样使用 firebase emulators:start
  2. 在您的终端中,运行

export FIRESTORE_EMULATOR_HOST="localhost:8080"(对于mac)

set FIRESTORE_EMULATOR_HOST="localhost:8080"(对于windows)

  1. 运行你照常考试。