如何从客户端使用 firestore 模拟器

How to use firestore emulator from client

我想在本地测试我的 firebase 函数。 这些函数进行 firestore 查询。

所以我启动模拟器 firebase emulators:start 并在我的客户端中使用 firebase.functions().useFunctionsEmulator('http://localhost:5001').

当我在客户端调用它们时,我的函数运行良好。我可以在 firestore 模拟器中 read/write 数据。

问题:

我想直接在我的客户端中读取 firestore 模拟器数据,例如:

firebase.firestore().collection('tests').get().then(tests => {
    console.log( tests.docs.map(test=>test.map) )
})

但我找不到如何在我的客户端中设置 firestore 模拟器。

这是我尝试过的:

1) Firestore 设置

firebase.firestore().settings({
    host:'http://localhost:8080',
    ssl:false
})

结果:

我在我的客户端控制台中得到 @firebase/firestore: Firestore (6.3.5): Could not reach Cloud Firestore backend. Backend didn't respond within 10 seconds.

http请求returns'Not found'

2) 在我的 firebaseConfig

中设置模拟器 url
var firebaseConfig = {
    // ...
    databaseURL: "http://localhost:8080",
    // ...
}

firebase.initializeApp(firebaseConfig)

在这种情况下,请求远程服务器 (https://firestore.googleapis.com..)。

所以我想设置这两种情况之一:

1) 在我的函数模拟器中使用远程 firestore

2) 在我的客户端代码中使用本地 firestore 模拟器。

有人做过吗?

安装测试库

npm i -D @firebase/testing

在另一个终端中设置并启动模拟器:

firebase setup:emulators:firestore

firebase serve --only firestore

设置测试

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

// Helper function to setup test db
function authedApp(auth) {
  return firebase
    .initializeTestApp({ projectId: FIRESTORE_PROJECT_ID, auth })
    .firestore();
}

// Setup methods
beforeEach(async () => {
  // Clear the database between tests
  await firebase.clearFirestoreData({ projectId: FIRESTORE_PROJECT_ID });
});

// Clean up apps between tests.
afterEach(async () => {
  await Promise.all(firebase.apps().map(app => app.delete()));
});

运行 测试

it("should retrieve correct item", async () => {
  // Init test db
  const db = authedApp(null);

  // Manually add item to collection
  const ref = await db.collection(COLLECTION_NAME).add({name: 'test item'});

  // Fetch item by id 
  const resp = await db.collection(COLLECTION_NAME).doc(ref.id).get();

  // test the output
  expect(resp).toBeDefined();
  expect(resp).toEqual(expect.objectContaining({name: 'test item'}));
});

当然,您的特定设置和环境会有所不同,但这至少应该给您一个大概的想法。更多信息:https://firebase.google.com/docs/rules/unit-tests

来自“Test your Cloud Firestore Security Rules”的注释

Data written to the Cloud Firestore emulator is held in memory until the emulator is stopped. If the emulator is run continuously, this may have an impact on test isolation. To ensure that data written in one test is not read in another, either explicitly clear your data with clearFirestoreData, or assign a different project ID for each independent test: when you call firebase.initializeAdminApp or firebase.initializeTestApp, append a user ID, timestamp, or random integer to the projectID.

编辑: 不久前我写了一篇 blog post,其中对主题进行了更详细的介绍。

我也遇到了同样的问题。我发现了以下示例,它看起来仍在进行中:

https://github.com/firebase/quickstart-nodejs/tree/master/firestore-emulator/browser-quickstart

他们没有在示例中直接使用 @firebase/testing。当我确实尝试在我的 webpack 代码中嵌入 @firebase/testing 时,它会尝试通过 grpc 进行连接,而 grpc 会尝试执行 fs.existsSync,这在 webpack 浏览器上下文中不存在.他们更喜欢通过 WebChannel 启用该功能。

截至 2019 年 11 月的一些注意事项:

  • 您可能会在使用 X-Goog-API 连接到 localhost:8080 的控制台中看到错误。我不确定那是干什么用的。
  • 您可能会遇到以下错误:@firebase/firestore: Firestore (6.3.5): Could not reach Cloud Firestore backend. Backend didn't respond within 10 seconds.

尽管有这些错误,我的函数仍然能够连接到本地 firestore。

我当时测试的版本:

  • firebase-js-sdk 6.3.1
  • firebase-工具 7.3.1

11 月 18 日更新:

  • 我在 quickstart-nodejs github 中提出了一个问题,看来我只需要使用最新版本的所有内容。

版本:

  • firebase-js-sdk v7.4.0
  • firebase-tools v7.8.0

好的,我找到了怎么做:

1) 在本地启动功能模拟器:

set GOOGLE_APPLICATION_CREDENTIALS=./privatekey.json && firebase serve --only functions

2) 然后是客户端:

if (process.env.NODE_ENV === 'development') {
    firebase.functions().useFunctionsEmulator('http://localhost:5001')
}

好的,这很简单...在您的 firestore cient 配置中,您应该提供 host,而不是 firestore 的来源(协议是使用 ssl 参数):

firebase.firestore().settings({
    host: 'localhost:8080',
    ssl: false
})

至少当我遇到完全相同的错误时,这为我解决了。

仅供阅读本文的任何人参考 - 如果您 运行 遇到 firestore 客户端问题,您可以使用 debug 级别的日志记录,只需设置 firebase.firestore.setLogLevel('debug')。如果 OP 这样做了,他可能已经注意到 firebase 正在 http://http://localhost:8080/...

访问 firestore

定义FIRESTORE_EMULATOR_HOST环境变量

如果您使用的库支持 FIRESTORE_EMULATOR_HOST 环境变量,运行:

export FIRESTORE_EMULATOR_HOST=localhost:8080

或者只需将 FIRESTORE_EMULATOR_HOST=localhost:8080 添加到您的 .env 文件