Firebase 本地模拟器中的模拟功能
Mock function in Firebase local emulator
如所述here,我正在使用本地模拟器(在线)对我的云功能进行测试。
Index.js:
var status = 200;
exports.saveAndSendMail = functions.https.onCall( async (req, res) => {
try{
let jsons = req.body;
await saveInfirestore(jsons);
await sendMail("Data saved", jsons);
} finally {
closeConnection(res, status);
}
async function saveInfirestore(json) {
//execute business logic and save in firestore (irrelevant for this question)
}
function closeConnection (res, status){
res.sendStatus(status);
res.end();
}
async function sendMail(title, message) {
try {
AWS.config.loadFromPath('./config_mail.json');
// Create sendEmail params
var params = {
Destination: {
ToAddresses: [
'mymail@gmail.com'
]
},
Message: { /* required */
Body: { /* required */
Html: {
Charset: "UTF-8",
Data: JSON.stringfy(message);
}
},
Subject: {
Charset: 'UTF-8',
Data: title
}
},
Source: '"Origin" <origin@gmail.com>',
ReplyToAddresses: [
'origin@gmail.com'
]
};
// Create the promise and SES service object
var sendPromise = new AWS.SES({apiVersion: '2022-17-01'}).sendEmail(params).promise();
}
catch(e){
throw e;
}
// Handle promise's fulfilled/rejected states
sendPromise.then(
function(data) {
console.log(data.MessageId);
}).catch(
function(err) {
console.error(err, err.stack);
});
}
index.test.js
const { expect } = require("chai");
const admin = require("firebase-admin");
const test = require("firebase-functions-test")({
projectId: process.env.GCLOUD_PROJECT,
});
const myFunctions = require("../index");
describe("Unit tests", () => {
after(() => {
test.cleanup();
});
it("test if save is correct", async () => {
const wrapped = test.wrap(myFunctions.saveAndSendMail);
const req = {
body: [{
value: 5,
name: 'mario'
}]
};
const result = await wrapped(req);
let snap = await db.collection("collection_data").get();
expect(snap.size).to.eq(1);
snap.forEach(doc => {
let data = doc.data();
expect(data.value).to.eql(5);
expect(data.name).to.eql('mario');
});
});
我执行它:firebase emulators:exec "npm 运行 test"
我有 2 个问题。
1 - 执行时,我收到错误 TypeError: res.sendStatus is not a function
。如果我最终在块中评论 closeConnection
调用 (index.js),此代码 运行 完美且所有测试和“预期” 运行 成功。但是,这种正确的方法是模拟此方法或模拟 'res' 调用。我试过用这样的东西模拟:
const res = {
sendStatus: (status) => {
},
end: () => {
}
}
const result = await wrapped(req, res);
但是,我收到这个错误:
Error: Options object {} has invalid key "sendStatus"
at /home/linuxuser/my-project/firebase/functions/myfolder/node_modules/firebase-functions-test/lib/main.js:99:19
at Array.forEach (<anonymous>)
at _checkOptionValidity (node_modules/firebase-functions-test/lib/main.js:97:26)
at wrapped (node_modules/firebase-functions-test/lib/main.js:57:13)
at Context.<anonymous> (test/index.test.js:50:26)
at processImmediate (node:internal/timers:464:21)
问题 2:
我不希望每次执行测试时都收到一封电子邮件。我如何模拟 sendMail 函数?
需要指出的非常重要的一点是,您目前正在尝试使用 Firebase callable function, as shown by the function heading functions.https.onCall(() => {});
. Since you want to work with requests and response codes, the correct type of function to use is an HTTP function。您只需要更改 index.js
:
中的标题
exports.saveAndSendMail = functions.https.onRequest(async (req, res) => {
// function body
});
现在,您的第一个问题可以通过正确模拟传递给函数(在 index.test.js
内)的 res
object 来解决。测试 HTTP 函数时,您不能在调用函数时使用 test.wrap()
,也不能像使用 const result = await wrapped(req);
那样期望结果 这是因为 Wrap
仅支持测试 onCall
职能。您可以在 documentation.
中看到关于如何调用 HTTP 函数进行测试的另一个片段
it("test if save is correct", async () => {
const req = {
body: [{
value: 5,
name: 'mario'
}]
};
// mocking the response object that is returned from the function:
const res = {
sendStatus: (code) => {
expect(code).to.eql(200); // asserting that we get 200 back as the response code
},
end: () => {
}
};
const result = await myFunctions.saveAndSendMail(req, res); // mocking a call to an HTTP function, without test.wrap()
// rest of the function…
对于你的第二个问题,我之前没有使用过 AWS SES,但似乎 this library 提供了模拟函数的方法,这样你就不必在测试期间实际发送电子邮件。
如所述here,我正在使用本地模拟器(在线)对我的云功能进行测试。
Index.js:
var status = 200;
exports.saveAndSendMail = functions.https.onCall( async (req, res) => {
try{
let jsons = req.body;
await saveInfirestore(jsons);
await sendMail("Data saved", jsons);
} finally {
closeConnection(res, status);
}
async function saveInfirestore(json) {
//execute business logic and save in firestore (irrelevant for this question)
}
function closeConnection (res, status){
res.sendStatus(status);
res.end();
}
async function sendMail(title, message) {
try {
AWS.config.loadFromPath('./config_mail.json');
// Create sendEmail params
var params = {
Destination: {
ToAddresses: [
'mymail@gmail.com'
]
},
Message: { /* required */
Body: { /* required */
Html: {
Charset: "UTF-8",
Data: JSON.stringfy(message);
}
},
Subject: {
Charset: 'UTF-8',
Data: title
}
},
Source: '"Origin" <origin@gmail.com>',
ReplyToAddresses: [
'origin@gmail.com'
]
};
// Create the promise and SES service object
var sendPromise = new AWS.SES({apiVersion: '2022-17-01'}).sendEmail(params).promise();
}
catch(e){
throw e;
}
// Handle promise's fulfilled/rejected states
sendPromise.then(
function(data) {
console.log(data.MessageId);
}).catch(
function(err) {
console.error(err, err.stack);
});
}
index.test.js
const { expect } = require("chai");
const admin = require("firebase-admin");
const test = require("firebase-functions-test")({
projectId: process.env.GCLOUD_PROJECT,
});
const myFunctions = require("../index");
describe("Unit tests", () => {
after(() => {
test.cleanup();
});
it("test if save is correct", async () => {
const wrapped = test.wrap(myFunctions.saveAndSendMail);
const req = {
body: [{
value: 5,
name: 'mario'
}]
};
const result = await wrapped(req);
let snap = await db.collection("collection_data").get();
expect(snap.size).to.eq(1);
snap.forEach(doc => {
let data = doc.data();
expect(data.value).to.eql(5);
expect(data.name).to.eql('mario');
});
});
我执行它:firebase emulators:exec "npm 运行 test"
我有 2 个问题。
1 - 执行时,我收到错误 TypeError: res.sendStatus is not a function
。如果我最终在块中评论 closeConnection
调用 (index.js),此代码 运行 完美且所有测试和“预期” 运行 成功。但是,这种正确的方法是模拟此方法或模拟 'res' 调用。我试过用这样的东西模拟:
const res = {
sendStatus: (status) => {
},
end: () => {
}
}
const result = await wrapped(req, res);
但是,我收到这个错误:
Error: Options object {} has invalid key "sendStatus"
at /home/linuxuser/my-project/firebase/functions/myfolder/node_modules/firebase-functions-test/lib/main.js:99:19
at Array.forEach (<anonymous>)
at _checkOptionValidity (node_modules/firebase-functions-test/lib/main.js:97:26)
at wrapped (node_modules/firebase-functions-test/lib/main.js:57:13)
at Context.<anonymous> (test/index.test.js:50:26)
at processImmediate (node:internal/timers:464:21)
问题 2:
我不希望每次执行测试时都收到一封电子邮件。我如何模拟 sendMail 函数?
需要指出的非常重要的一点是,您目前正在尝试使用 Firebase callable function, as shown by the function heading functions.https.onCall(() => {});
. Since you want to work with requests and response codes, the correct type of function to use is an HTTP function。您只需要更改 index.js
:
exports.saveAndSendMail = functions.https.onRequest(async (req, res) => {
// function body
});
现在,您的第一个问题可以通过正确模拟传递给函数(在 index.test.js
内)的 res
object 来解决。测试 HTTP 函数时,您不能在调用函数时使用 test.wrap()
,也不能像使用 const result = await wrapped(req);
那样期望结果 这是因为 Wrap
仅支持测试 onCall
职能。您可以在 documentation.
it("test if save is correct", async () => {
const req = {
body: [{
value: 5,
name: 'mario'
}]
};
// mocking the response object that is returned from the function:
const res = {
sendStatus: (code) => {
expect(code).to.eql(200); // asserting that we get 200 back as the response code
},
end: () => {
}
};
const result = await myFunctions.saveAndSendMail(req, res); // mocking a call to an HTTP function, without test.wrap()
// rest of the function…
对于你的第二个问题,我之前没有使用过 AWS SES,但似乎 this library 提供了模拟函数的方法,这样你就不必在测试期间实际发送电子邮件。