1
\$\begingroup\$

The introduction of async native support in Jasmine doesn't log the errors (i.e., specific line number where the error occurs) to the console. So, to get around this behavior and to make the errors appears in the console, I came up with this following solution to patch Jasmine.

I have the following function which I implemented to monkey patch the Jasmine. And I would like to reuse the same function for other functions like beforeEach, beforeAll and so on..

     function patchJasmineForAsyncError(method: string) {
        let oldFn = window[method];
        if (method === 'it' || method === 'fit') {
            window[method] = function (desc: string, fn: Function) {
                    oldFn(description, (done) => {
                    let p = fn();
                    if (p instanceof Promise) {
                        p.then(() => done()).catch(e => {
                            console.error(e);
                            done.fail(e);
                        });
                    }
                    });
            }
        } else {
            window[method] = function (axn: Function) {
                oldFn((done) => {
                    let p = axn();
                    if (p instanceof Promise) {
                        p.then(() => done()).catch(e => {
                            console.error(e);
                            done.fail(e);
                        });
                    }
                });
            }
        }
} 

As you can see the second part of the function (the else block) has quite a lot of duplication. I was wondering if there is an elegant way to minimize this and implement the function.

Note: the it and fit functions have two arguments desc and fn.. but the beforeAll, beforeEach.. etc have only one argument axn.

\$\endgroup\$
1
\$\begingroup\$

Just factor it out into a closure

function patchJasmineForAsyncError(method: string) {
    let oldFn = window[method];
    function create_logger(fn: Function) {
        return (done) => {
            let p = fn();
            if (p instanceof Promise) {
                p.then(done).catch(e => {
                    console.error(e);
                    done.fail(e);
                });
            }
        }
    }

    if (method === 'it' || method === 'fit') {
        window[method] = function(desc: string, fn: Function) {
            oldFn(desc, create_logger(fn));
        }
    } else {
        window[method] = function (axn: Function) {
            oldFn(create_logger(axn));
        }
    }
} 

We can clean this up a bit more by getting rid of some magic. I also got rid of the () => done() because that's the same as done.

function patchJasmineForAsyncError(method: string) {
    let oldFn = window[method];
    function create_logger(fn: Function) {
        return (done) => {
            let p = fn();
            if (p instanceof Promise) {
                p.then(done).catch(e => {
                    console.error(e);
                    done.fail(e);
                });
            }
        }
    }

    let allowed_methods = ['it', 'fit'];
    if (allowed_methods.includes(method)) {
        window[method] = function(desc: string, fn: Function) {
            oldFn(desc, create_logger(fn));
        }
    } else {
        window[method] = function (axn: Function) {
            oldFn(create_logger(axn));
        }
    }
} 

We can also reduce some of the duplication in assigning to window[method] if we're okay with adding a slight slow-down to the function, which should be fine.

function patchJasmineForAsyncError(method: string) {
    let oldFn = window[method];
    function create_logger(fn: Function) {
        return (done) => {
            let p = fn();
            if (p instanceof Promise) {
                p.then(done)
                 .catch(e => {
                    console.error(e);
                    done.fail(e);
                });
            }
        }
    }
    let allowed_methods = ['it', 'fit'];
    window[method] = function() {
        if (allowed_methods.includes(method)) {
            oldFn(arguments[0], create_logger(arguments[1]));
        } else {
            oldFn(create_logger(arguments[0]));
        }
    }
}
\$\endgroup\$
  • \$\begingroup\$ Damnn. Seems like I am too late to post my answer :P I did the way you did in the first method. Thanks a lot for the amazing answer :) \$\endgroup\$ – Tums Mar 8 '18 at 1:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.