如何从客户端使用 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 文件
我想在本地测试我的 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
中设置模拟器 urlvar 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_EMULATOR_HOST环境变量
如果您使用的库支持 FIRESTORE_EMULATOR_HOST 环境变量,运行:
export FIRESTORE_EMULATOR_HOST=localhost:8080
或者只需将 FIRESTORE_EMULATOR_HOST=localhost:8080 添加到您的 .env 文件