如何使用Firebase Emulator设置Firebase Firestore和云功能测试套件以进行JS开发

Jür*_*ter 4 firebase google-cloud-functions google-cloud-firestore

根据以下Firebase团队的google I / O(2019)帖子,新的模拟器允许我们结合使用Firebase /数据库和云功能来完全模拟我们的Firebase服务器代码。这也意味着我们应该能够为此编写测试。

我们将发布一个全新的Cloud Functions模拟器,该模拟器还可以与Cloud Firestore模拟器进行通信。因此,如果您想构建一个功能来触发Firestore文档更新并将数据写回数据库,则可以在笔记本电脑上本地编码和测试整个流程(来源:Firebase Blog Entry

我可以找到多个资源来查找/描述每个单独的模拟,但没有一起使用

  1. 单元测试云功能
  2. 模拟数据库写入
  3. 模拟Firestore写入

Jür*_*ter 7

要为云功能设置测试环境以允许您模拟读/写和设置测试数据,您必须执行以下操作。请记住,这是真正的模拟/触发云功能。因此,在写入Firestore之后,您需要稍等片刻,直到云函数完成写入/处理,然后才能读取断言数据。

可以在下面找到带有以下代码的示例仓库:https : //github.com/BrandiATMuhkuh/jaipuna-42-firebase-emulator

前提条件

我假设此时您已经建立了一个Firebase项目,其中包含一个functions文件夹index.js。测试稍后将在functions/test文件夹中。如果没有项目设置,请使用firebase init来设置项目。

安装依赖项

首先添加/安装下面的依赖关系:mocha@firebase/testingfirebase-functions-testfirebase-functionsfirebase-adminfirebase-toolsfunctions/package.json不是根文件夹。

替换所有jaipuna-42-firebase-emulator名称

使用自己的很重要project-id。它必须是 project-id您自己的项目,并且必须存在。伪造的ID无法使用。因此,请jaipuna-42-firebase-emulator在下面的代码中搜索所有内容,然后将其替换为project-id

index.js示例云功能

// functions/index.js

const functions = require("firebase-functions");
const admin = require("firebase-admin");

// init the database
admin.initializeApp(functions.config().firebase);
let fsDB = admin.firestore();

const heartOfGoldRef = admin
    .firestore()
    .collection("spaceShip")
    .doc("Heart-of-Gold");

exports.addCrewMemeber = functions.firestore.document("characters/{characterId}").onCreate(async (snap, context) => {
    console.log("characters", snap.id);

    // before doing anything we need to make sure no other cloud function worked on the assignment already
    // don't forget, cloud functions promise an "at least once" approache. So it could be multiple
    // cloud functions work on it. (FYI: this is called "idempotent")

    return fsDB.runTransaction(async t => {
        // Let's load the current character and the ship
        const [characterSnap, shipSnap] = await t.getAll(snap.ref, heartOfGoldRef);

        // Let's get the data
        const character = characterSnap.data();
        const ship = shipSnap.data();

        // set the crew members and count
        ship.crew = [...ship.crew, context.params.characterId];
        ship.crewCount = ship.crewCount + 1;

        // update character space status
        character.inSpace = true;

        // let's save to the DB
        await Promise.all([t.set(snap.ref, character), t.set(heartOfGoldRef, ship)]);
    });
});


Run Code Online (Sandbox Code Playgroud)

摩卡测试文件index.test.js

// functions/test/index.test.js


// START with: yarn firebase emulators:exec "yarn test --exit"
// important, project ID must be the same as we currently test

// At the top of test/index.test.js
require("firebase-functions-test")();

const assert = require("assert");
const firebase = require("@firebase/testing");

// must be the same as the project ID of the current firebase project.
// I belive this is mostly because the AUTH system still has to connect to firebase (googles servers)
const projectId = "jaipuna-42-firebase-emulator";
const admin = firebase.initializeAdminApp({ projectId });

beforeEach(async function() {
    this.timeout(0);
    await firebase.clearFirestoreData({ projectId });
});

async function snooz(time = 3000) {
    return new Promise(resolve => {
        setTimeout(e => {
            resolve();
        }, time);
    });
}

it("Add Crew Members", async function() {
    this.timeout(0);

    const heartOfGold = admin
        .firestore()
        .collection("spaceShip")
        .doc("Heart-of-Gold");

    const trillianRef = admin
        .firestore()
        .collection("characters")
        .doc("Trillian");

    // init crew members of the Heart of Gold
    await heartOfGold.set({
        crew: [],
        crewCount: 0,
    });

    // save the character Trillian to the DB
    const trillianData = { name: "Trillian", inSpace: false };
    await trillianRef.set(trillianData);

    // wait until the CF is done.
    await snooz();

    // check if the crew size has change
    const heart = await heartOfGold.get();
    const trillian = await trillianRef.get();

    console.log("heart", heart.data());
    console.log("trillian", trillian.data());

    // at this point the Heart of Gold has one crew member and trillian is in space
    assert.deepStrictEqual(heart.data().crewCount, 1, "Crew Members");
    assert.deepStrictEqual(trillian.data().inSpace, true, "In Space");
});


Run Code Online (Sandbox Code Playgroud)

运行测试

要一次性运行测试和仿真器,我们导航到该functions文件夹并编写yarn firebase emulators:exec "yarn test --exit"。此命令也可以在您的CI管道中使用

如果一切正常,您应该看到以下输出

  ? Add Crew Members (5413ms)

  1 passing (8S)
Run Code Online (Sandbox Code Playgroud)


Ben*_*ing 6

对于那些在测试 firestore 触发器方面遇到困难的人,我制作了一个示例存储库,希望能够对其他人有所帮助。

https://github.com/benwinding/example-jest-firestore-triggers

它使用 jest 和本地 firebase 模拟器。