Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Testing with Promise.done() #428

Closed
OJezu opened this issue Feb 13, 2015 · 6 comments
Closed

Testing with Promise.done() #428

OJezu opened this issue Feb 13, 2015 · 6 comments

Comments

@OJezu
Copy link

OJezu commented Feb 13, 2015

I have a scenario in which all I can do upon an error is crash the process (or pass to something that knows what to do with such things). I'm using Promise.done() for that. Problem is, I would like to unit test if in that scenario .done() is called, but without crashing unit test process. So before hacking around in prototypes I would like to ask:

Is there (or should be introduced) a "supported" way to do such testing?

@OJezu
Copy link
Author

OJezu commented Feb 13, 2015

I found (via debugging api doc) I can set when.Promise.onFatalRejection. Problem solved, but I think when.Promise.onFatalRejection could get more exposition.

@OJezu OJezu closed this as completed Feb 13, 2015
@rkaw92
Copy link
Contributor

rkaw92 commented Feb 13, 2015

Dnia 13 lutego 2015 16:40:52 CET, Christopher Chrapka notifications@github.com napisał(a):

Closed #428.


Reply to this email directly or view it on GitHub:
#428 (comment)

Hi,

This might end rather funky if you separate the unit tests from the main application, or do cross-module requires.

The way that require() caching works is that it will store a single copy of the module in its internal module map, indexed by name. However, if two copies are installed in different locations, even if one is a symlink to the other, you may find that the when module that you're monkey-patching is not the same object instance that the "when" your app is using. That is, it may be hard to prevent a split-brain module situation and as such relying on globals is not recommended. I have had a case of duplicate "when" modules in an application personally.

A better approach may be exposing an EventEmitter from your object/code and calling .emit('error') in .done()'s rejection callback. If no handler is registered, the process shall crash. Your tests can then call .on() and prevent this.

@OJezu
Copy link
Author

OJezu commented Feb 14, 2015

@rkaw92 You know, mocha has something like after(). So...

it('should crash process', function(d){
    var org_onFatalRejection = when.Promise.onFatalRejection;
    after(function(){
        when.Promise.onFatalRejection = org_onFatalRejection;
    });
    when.Promise.onFatalRejection = function(rejection){
        try{
            rejection.value.should.be.instanceOf(Errors.FatalError);
            d();
        } catch(err){
            d(err);
        }
    };
    (...)
});

@briancavalier
Copy link
Member

@ohJeez, yes indeed, that is a fairly typical way to test something like onFatalRejection. However, I think I might go for a more direct approach. If you simply assume that done has been implemented correctly in when.js--that is, assume that if it's called, then it will indeed crash the process--then all you need to do is spy on done. Testing that onFatalRejection is called is probably too fine grained of an implementation detail to test.

For example, you could simply mock/spy/override when.Promise.prototype.done, and then verify that it was called.

@rkaw92's point is a good one, though, and worth expanding on a bit. In a node app, it's entirely possible for multiple copies of when.js (or any package, for that matter) to be in play (via transitive dependencies). Each copy would have it's own when.Promise constructor with its own onFatalRejection property. It's just important to keep in mind that by overriding one of them, you won't be overriding them all. That's why it's important not to rely on being able to override it for all cases.

That's the impetus behind the new process events in node and window events in browsers in when >= 3.7.0. If all copies of when.js in play are emitting those, then its possible to observe them centrally. Other promise implementations have also added those events, as well. So, as long as all the copies of all the promise implementations in your app do that, it's possible to centrally observe all unhandled rejections.

As of right now, though, there's no 'fatalRejection` event.

@OJezu
Copy link
Author

OJezu commented Feb 15, 2015

@briancavalier I tried overwriting when.Promise.prototype.done, but I had strange results. It had old behaviour (not-ovewritten) when tests were run, unless I used mocha --watch in which case, on second run it indeed used the overwritten method. I think that prototype (or methods) must be copied at some point, and I didn't feel like searching through when code to see what is exactly happening.

@OJezu OJezu reopened this Feb 15, 2015
@OJezu OJezu closed this as completed Feb 15, 2015
@OJezu
Copy link
Author

OJezu commented Feb 15, 2015

Crap, [Reopen and comment] button is awfully big.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants