Firebase 本地模拟器中的 Mock 函数

发布于 2025-01-10 21:36:41 字数 4369 浏览 0 评论 0原文

此处所述,我正在使用本地模拟器(在线)在我的云函数中进行测试。

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: [
            '[email protected]'
            ]
        },
        Message: { /* required */
            Body: { /* required */
        Html: {
                Charset: "UTF-8", 
                Data: JSON.stringfy(message);
                }
            },
            Subject: {
                Charset: 'UTF-8',
                Data: title
            }
            },
        Source: '"Origin" <[email protected]>',
        ReplyToAddresses: [
            '[email protected]'
        ]
        };

        // 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 run test"

我有两个问题。

1 - 执行时,我收到错误 TypeError: res.sendStatus is not a function。如果我在块finally (index.js) 中注释 closeConnection 调用,则此代码可以完美运行,并且所有测试和“预期”都会成功运行。但是,这个正确的方法是模拟此方法或模拟“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 功能?

Such as described here, I'm using local emulator (on-line) to make tests im my cloud functions.

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: [
            '[email protected]'
            ]
        },
        Message: { /* required */
            Body: { /* required */
        Html: {
                Charset: "UTF-8", 
                Data: JSON.stringfy(message);
                }
            },
            Subject: {
                Charset: 'UTF-8',
                Data: title
            }
            },
        Source: '"Origin" <[email protected]>',
        ReplyToAddresses: [
            '[email protected]'
        ]
        };

        // 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');
        });
    
    });

I execute it with: firebase emulators:exec "npm run test"

I have 2 problems.

1 - When execute, I receive the error TypeError: res.sendStatus is not a function. If I comment closeConnection call in block finally (index.js), this code run perfectly and all tests and "expect" run with success. But, this correct way is mock this method or mock 'res' calls. I tried mock with something like this:

       const res = {
            sendStatus: (status) => {
            },
            end: () => {
            }
          }
    
    const result = await wrapped(req, res);

But, I receive this error:

 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)

Problem 2:

I'm not wish receive an e-mail each time that tests executes. How I mock sendMail function?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

不可一世的女人 2025-01-17 21:36:41

需要指出的非常重要的一点是,您当前正在尝试使用 Firebase 可调用函数,如函数标题 functions.https.onCall(() => {}); 所示。由于您想要处理请求和响应代码,因此要使用的正确函数类型是 HTTP 函数。您只需要更改 index.js 中的标题:

exports.saveAndSendMail = functions.https.onRequest(async (req, res) => {
    // function body
});

现在,您的第一个问题可以通过正确模拟传递给函数的 res 对象来解决(在 index.test.js 内)。测试 HTTP 函数时,调用函数时不得使用 test.wrap(),也不得像使用 const result = waitwrapped(req); 那样期望结果> 这是因为 Wrap 仅支持测试 onCall 函数。您可以在文档<中查看如何调用 HTTP 函数进行测试的另一个片段< /a>.

  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,但似乎这个库 提供了模拟函数的方法,这样您就不必在测试期间实际发送电子邮件。

Something very important to point out is that you are currently trying to use a 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. You would only need to change the heading in your index.js:

exports.saveAndSendMail = functions.https.onRequest(async (req, res) => {
    // function body
});

Now, your first problem can then be solved by correctly mocking the res object that is passed to the function (inside index.test.js). When testing HTTP functions, you must not use test.wrap() when calling the function, nor expect the result as you were doing with const result = await wrapped(req); This is since Wrap being only supported for testing onCall functions. You can see another snippet of how to call an HTTP function for testing in the 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…

For your second problem, I haven’t used AWS SES before, but it seems this library offers ways to mock the functions so that you won’t have to actually send emails during your tests.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文