我有一个Firebase函数,可以检查Chargebee中是否存在电子邮件。它的工作方式如下:
const cbCmd = chargeBee.customer.list({ email: { is: email }, include_deleted: false, limit: 1 });
const callbackResolver = new Promise<any>((resolve, reject) => {
void cbCmd.request((err: any, res: WrappedListCustomerResp) => {
if (err) {
reject(err);
}
resolve(!res.list.find(payee => payee.customer.email === email));
});
});
return Promise.resolve(callbackResolver);
基本上,cbCmd
包含一个名为request
的方法,它最终运行API请求。request
被发送给一个函数,它描述了我如何转换Chargebee输出的数据。(Chargebee并没有在他们的打字稿包中完全描述他们在他们的文件中返回的内容。为了更好地描述转换,我研究了返回内容的数据类型,并创建了自己的接口。)
我如何用茉莉花对此进行单元测试?
发布于 2022-10-25 12:46:15
为了充分描述这一解决方案,需要提供一些背景信息。
全局性方法
详细信息
嘲弄有关的功能
与ChargeBee API的交互是通过一个简单的方法完成的:
import {ChargeBee} from 'chargebee-typescript';
const chargebee = new ChargeBee();
所有的API方法都是这样提供的。在Javascript方面,下面是chargebee.customer
发生的情况,例如:
const resources = require("./resources");
class ChargeBee {
get customer() {
return resources.Customer;
}
}
resources
中的每个东西都提供了自己的静态函数,可以完成所需的一切。例如,Customer
有以下内容:
class Customer extends model_1.Model {
// OPERATIONS
//-----------
...
static list(params) {
return new request_wrapper_1.RequestWrapper([params], {
'methodName': 'list',
'httpMethod': 'GET',
'urlPrefix': '/customers',
'urlSuffix': null,
'hasIdInUrl': false,
'isListReq': true,
}, chargebee_1.ChargeBee._env);
}
}
RequestWrapper
对象包含正在执行实际工作的request
方法。这个方法做了一些有趣的事情:
request(callBack = undefined, envOptions) {
let deferred = util_1.Util.createDeferred(callBack);
...
return deferred.promise;
}
static createDeferred(callback) {
let deferred = q_1.defer();
if (callback) {
deferred.promise.then(function (res) {
setTimeout(function () {
callback(null, res);
}, 0);
}, function (err) {
setTimeout(function () {
callback(err, null);
}, 0);
});
}
return deferred;
}
基本上,q_1.defer()
创建了一个包含Promise
的对象,以及其他的东西。他们使用deferred.promise.then
将发送给函数的代码锁存到整个API请求中,以便在Promise
开始解析后执行。
要模拟它,您需要重写有关getter的prototype属性。返回customer.list
的备用实现。方便地,上面的ChargeBee的createDeferred
函数是export
编辑的,因此可以利用它来制作一些与ChargeBee的模式非常接近的东西。
整个模拟是这样的:
spyOnProperty<any>(mockedChargebee.ChargeBee.prototype, 'customer', 'get').and.returnValue({
list: () => ({
request: (callBack?: any) => {
const deferred = Util.createDeferred(callBack);
deferred.resolve({ list: [] });
return deferred.promise;
}
})
});
重要双边投资条约:
spyOnProperty
,因为该函数是作为属性输出的。get
之三。Util.createDeferred
来确保我们接近于遵循与Chargebee一样的方式。在这里没有保证,但也许这样做比滚动自己承诺的细节更好。Promise
之后,deferred.resolve
才会实际运行。在deferred.resolve({list: []})
中,您定义的行为将在稍后解析Promise
时发生。如果您非常熟悉resolve
的解决顺序,那么可能是显而易见的;这对我来说并不明显。这里的总体行为是:(a)首先通过承诺链发送{list: []}
;(b)发送{list: []}
作为对任何定义为callback
的内容的输入;(c)在这个特定示例中,callback
将运行resolve(!res.list.find(payee => payee.customer.email === email))
,生成resolve(false)
;(d) false
是承诺链的最终结果。创建/导入测试函数
在完成spyOnProperty
之后,我使用了一个简单的动态导入来完成这个操作。这确保初始化代码const chargebee = new ChargeBee();
将使用我在spyOnProperty
中提供的备用函数。(初始化代码发生在./index
中:未显示。)
const enableSignup = await import('./index').then(m => m.enableSignup);
测试
我碰巧是在使用Firebase,所以我使用了一个Firebase测试库来包装这个函数。然后,使用await
进行测试。
const wrapped = firebaseTestFns.wrap(enableSignup);
const fnd = await wrapped('someemail');
expect(fnd).toBeTrue();
https://stackoverflow.com/questions/74200001
复制相似问题