问题
I am trying to override (monkey patch) the it()
function of the Jasmine framework and in the process, I want to know if a function which is passed as the second argument to the it()
function is of type async
or not. I tried using the instanceof Promise
because all async
functions return a promise, but it never resolves to true and it never goes into the if block in the following code block. I have tried logging all the functions to the console and I found that all the async()
function specs have a return type of tslib_1.awaiter(some args..)
.
Here is what I have:
let newIt = jasmine.getEnv().it;
jasmine.getEnv().it = function(...args): jasmine.Spec {
// do something.
if(args[1] instanceOf Promise) {
debugger; // never comes in here.
// catch error.
}
return newIt.apply(this, arguments);
}
What am I doing wrong here? Could anyone please point me into a right direction?
Thank you.
Edit: Let's say I have the following two dummy specs, one is async and the other is synchronous:
Async Test:
const exp = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1);
}, 500);
});
};
it('asyncTest', async () => {
expect(await exp()).toEqual(1);
}, 600);
Synchronous:
it('testNon', () => {
expect(true).toBe(true);
});
回答1:
This is XY problem. As pointed in this answer there is usually no need to check that it's async
function because this doesn't matter. async
function is just a function that returns a promise. Both () => Promise.resolve()
and async () => {}
should be treated in same way.
This is confirmed by the fact that it's impossible to distinguish between async
and regular function in transpiled TypeScript code - both of them are just regular functions.
args[1] instanceOf Promise
is incorrect, because a function won't be an instance of Promise
.
Monkey-patching is generally performed this way (this isn't specific to Jasmine or this case):
let newIt = jasmine.getEnv().it;
jasmine.getEnv().it = function(...args): jasmine.Spec {
const fn = args[1];
let newFn;
if (fn.length > 0) {
// async spec with done param
newFn = function (done) {
const result = fn.call(this, done);
if(result instanceOf Promise)
// or even better,
// if(result && typeof result.then === 'function')
debugger;
return result;
}
} else {
newFn = function () {
const result = fn.call(this);
if(result instanceOf Promise)
debugger;
return result;
}
}
args[1] = newFn;
return newIt.apply(this, args);;
}
It's test function result that should be checked to be an instance of Promise
(or to be checked if it's thenable).
回答2:
This isn't working because the async functions always return a promise, but they aren't in themselves promises.
The simple answer is to look at the constructor of the function in question (but I'll explain why you shouldn't after):
const isAsync = func.constructor.name === 'AsyncFunction';
The problem with this approach is that async functions aren't really meant to be distinguishable from regular functions which return a promise. It would be better to use Promise.resolve
to turn the result of any function call into a Promise
, and await
that.
来源:https://stackoverflow.com/questions/49060405/how-to-programmatically-find-if-a-function-is-async