在 NodeJs 中使用 Jest 模拟 Http Post 请求

Sha*_*llu 2 javascript unit-testing mocking node.js jestjs

我有一个使用本机 https.request 使用 Azure Function 内的 Node Js 构建的外部 POST API,一切正常。现在我正在尝试构建单元测试用例,并对模拟 Request 方法感到震惊。

回调响应具有“on”功能,需要根据“data”或“end”值进行模拟。

我收到此错误TypeError: res.on is not a function

下面是代码。有什么建议 !

索引.js

'use strict';
const https = require('https')
const fs = require('fs')
const path = require('path')

module.exports = function(context, postData) {
    //Accessing Certificate and Passing along with Request Options for SSL Handshake
    var ca_path = path.join(__dirname, 'my_cert.cer');
    https.globalAgent.options.ca = fs.readFileSync(ca_path).toString()
        .split(/-----END CERTIFICATE-----\n?/)
        // may include an extra empty string at the end
        .filter(function(cert) { return cert !== ''; })
        // effectively split after delimiter by adding it back
        .map(function(cert) { return cert + '-----END CERTIFICATE-----\n'; });

    let auth = 'Basic ' + Buffer.from(process.env.username + ':' + process.env.pwd).toString('base64');

    let post_option = {
        host: process.env.host,
        path: process.env.path,
        method: 'POST',
        port: process.env.port,
        headers: {
            'Content-Type': 'application/json',
            'Authorization': auth,
            'X-Correlation-ID': JSON.parse(postData).correlationId
        }
    };

    return new Promise(function(resolve, reject) {
        var req = https.request(post_option, function(res) {
            // accumulate data
            var body = [];
            res.on('data', function(chunk) { //here is the type error
                body.push(chunk);
            });
            // resolve on end
            res.on('end', function() {
                context.log("API status: " + res.statusCode);
                if (res.statusCode == 200) {
                    try {
                        body = JSON.parse(Buffer.concat(body).toString());
                        context.log("API Success: ");
                    } catch (err) {
                        reject(err);
                    }
                    resolve(body);
                } else if (res.statusCode == 401) {
                    let errJson = {};
                    context.log("API authentication error...");
                    let err = new Error();
                    errJson["errorCode"] = res.statusCode;
                    errJson["errorMessage"] = res.statusMessage;
                    errJson["errorDescription"] = res.statusMessage;
                    err = errJson;
                    return reject(err);
                } else {
                    body = JSON.parse(Buffer.concat(body).toString());
                    context.log("API error...", body);
                    let err = new Error();

                    if (body.error != null && body.error != undefined) {
                        err = body.error;
                    } else {
                        let errJson = {};
                        errJson["errorCode"] = res.statusCode;
                        errJson["errorMessage"] = res.statusMessage;
                        errJson["errorDescription"] = res.statusMessage;
                        err = errJson;
                    }
                    return reject(err);
                }
            });
        });
        // reject on request error
        req.on('error', function(err) {
            context.log("API Generic error...", err);
            let err = new Error();
            let errJson = {};
            if (err.message && err.message.indexOf("ENOTFOUND") >= 0)
                errJson["errorCode"] = 404;
            else
                errJson["errorCode"] = 500;
            errJson["errorMessage"] = err.message;
            errJson["errorDescription"] = err.message;
            err = errJson;
            reject(err);
        });
        if (postData) {
            req.write(postData);
        }
        req.end();
    });
}
Run Code Online (Sandbox Code Playgroud)

索引.test.js

 var https = require('https');
    jest.mock('https', () => ({
    ...jest.requireActual('https'), // import and retain the original functionalities
    request: (post_option, cb) => cb('res')({
         on: jest.fn()
    }),
    on: jest.fn(),
    write: jest.fn(),
    end: jest.fn()
}));


 /*
jest.mock('https', () => ({
...jest.requireActual('https'), // import and retain the original functionalities
request: (post_option, cb) => cb('res')({
    on: (data, cb) => cb('data')
}),
on: jest.fn(),
write: jest.fn(),
end: jest.fn()
}));
*/

/*    jest.mock('https', () => ({
      ...jest.requireActual('https'), // import and retain the original functionalities
      request: (post_option, cb) => cb(jest.fn(() => ({
        on: jest.fn()
      }))),
      on: jest.fn(),
      write: jest.fn(),
      end: jest.fn()
      })); 
*/

/*  jest.mock('https', () => ({
    ...jest.requireActual('https'), // import and retain the original functionalities
    request: (post_option, cb) => cb({
     on: jest.fn()
    })
    })); 
*/
Run Code Online (Sandbox Code Playgroud)

尝试了不同的方法来为“on”功能创建模拟,但没有成功。

Sha*_*llu 6

经过3个小时的实验,我终于能够模拟“res”的“on”功能了。

cb 实际上应该设置为一个需要 2 个参数的函数

这是模拟语法。

let apiResponseBody = `{
                         "status": "Dummy Request sent to API"
                       }`;
    
var https = require('https');
jest.mock('https', () => ({
 ...jest.requireActual('https'), // import and retain the original functionalities
 request: (post_option, cb) => cb({
  on: (data, cb) => cb(Buffer.from(apiResponseBody, 'utf8')),
  statusCode: 200,
  statusMessage: 'API Success'
 }),
 on: jest.fn(),
 write: jest.fn(),
 end: jest.fn()
}));
Run Code Online (Sandbox Code Playgroud)