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

Return thrown error/rejected promise from t.throws #576

Merged
merged 1 commit into from
Mar 2, 2016
Merged

Return thrown error/rejected promise from t.throws #576

merged 1 commit into from
Mar 2, 2016

Conversation

kasperlewau
Copy link
Contributor

If a throws assertion passes, we should return the reason for said pass. That entails;

  • A thrown Error.
  • A Promise rejection.
  • An Observable error.

Loosely based on the description of #493. I consider it to be loosely based on it, because of the following differences (in the Promised-land):

// Desired
test(t => {
  const expected = new Error('foo');
  const actual = t.throws(() => Promise.reject(expected));
  t.is(expected, actual); // true
})

// Implemented
test(t => {
  const expected = new Error('foo');
  const actual = t.throws(() => Promise.reject(expected));
  t.is(expected, actual.reason); //true 
})

I hijacked the result.reason property because I wasn't fully comfortable in excluding the base result properties out of a successful throws assertion, which was heavily used in test/promise and test/observable. However this can be changed quite easily, to more closely reflect the initial desires of #493.


Haven't taken a stab at docs for the changes made yet, I'll get on top of that on my way home from work.

@mention-bot
Copy link

By analyzing the blame information on this pull request, we identified @ariporad, @SamVerschueren and @sotojuan to be potential reviewers

err = function (err) {
return err.message === errMsg;
};
}

assert.throws(fn, err, msg);

if (errMsg) {
return Error(errMsg);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

errMsg is the expected message. The workaround above stems from #125 and was done because assert.throws doesn't take a string argument as the expected message, but we did want that behavior in AVA.

In other words it's not something to be returned.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might actually be able to kill this if-block entirely given your suggestion at https://github.com/sindresorhus/ava/pull/576/files#r54448454. I'll give it a whirl!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, you're returning a very different value here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's gone!

@novemberborn
Copy link
Member

I don't understand why you're changing lib/test. What am I missing?

No need to exhaustively test .throws(). Just need to verify it returns the thrown error. You do need a test for when a rejected promise is returned though. You shouldn't need to change the observable and promise tests.

@novemberborn
Copy link
Member

Cool getting there!

@kasperlewau
Copy link
Contributor Author

I don't understand why you're changing lib/test. What am I missing?

This might be a case of me not writing the tests as one should to get it working as expected. But when going back and reverting the changes made to lib/test makes the following spec break;

// test/promise.js
test('throws becomes the promise rejection', function (t) {
    var rejection;
    ava(function (a) {
        a.plan(1);

        rejection = new Error('foo');
        var promise = Promise.reject(rejection);
        return a.throws(promise);
    }).run().then(function (result) {
        t.is(result.passed, true);
        t.is(result.result.assertCount, 1);
        t.is(result.reason, rejection);
        t.end();
    });
});

this line is the real deal-breaker in this specific case. Without it, I don't see how one would return the rejection reason to the callee.

Again, it's not that far-fetched that this test does not in fact belong here and I'm just doing it wrong.


On that note, my pizza just arrived. I'll be back in a bit 🍕

@kasperlewau
Copy link
Contributor Author

Sorry, I phased out after having my supper last night (I blame Comedy Central). I got around to cleaning some stuff out, but I'm sort of at a loss on how to handle the test case for a Promise rejection.

So far I'm at this point;

test('.throws() becomes the rejection reason of promise', function (t) {
    var expected = new Error();

    assert.throws(Promise.reject(expected)).then(function (err) {
        assert.same(expected, err);
        t.end();
    });
});

But that's not actually testing the return value of throws. Still working on trying to figure that one out - I keep looking at test/promises and the way Promises are handled in there but, I haven't gotten it to work just yet.

@kasperlewau
Copy link
Contributor Author

Alright, I reckon we're good to go there with the latest changes made.

  • lib/test changes are gone.
  • test/[promises|observables] changes are gone.
  • Promise rejection assertion is in place in test/assert
    • Could potentially be cleaned up ever so slightly?
  • Code has been touched up as per @novemberborn's suggestions.

Let me know what you think, I've got an itch in my squash finger.


I guess a brief look from @jamestalmage would be warranted as well, given he's the author of #493.

@kasperlewau kasperlewau changed the title [WIP] t.throws return reason(s) t.throws return thrown error/promise rejection Mar 1, 2016
@kasperlewau kasperlewau changed the title t.throws return thrown error/promise rejection Return thrown error/rejected promise from t.throws Mar 1, 2016
@vadimdemedes
Copy link
Contributor

To me, returning object with reason property is not logical. If t.throws() throws, everything is good and execution is continued, there's no "failure reason", because nothing failed. Why don't we just return error from t.throws()?

@kasperlewau
Copy link
Contributor Author

@vdemedes Sorry, I should've probably updated the OP. Like I stated before, I wasn't all too comfy with overriding the return value of test.exit to reflect what happened with test.throws. I overcomplicated the matter.


The way it works now is this;

test(t => {
  const expected = new Error();
  const actual = t.throws(Promise.reject(expected));
  t.same(expected, actual); 
});

Whereas what I was doing in the beginning was something like so;

test(t => {
  const expected = new Error();
  return t.throws(Promise.reject(expected));
}).then(result) {
  // result.reason === expected
}

I was trying to cater to the test/promise suite, as opposed to testing throws where it should be tested (in test/assert). That whole snafu is gone now however, after touching up on the parts Mark mentioned.

I'll gladly edit the OP when I get a on the train. At work currently.

@vadimdemedes
Copy link
Contributor

Oh great, so it does return thrown Error from t.throws(), right? No rush, thank you!

@kasperlewau
Copy link
Contributor Author

Oh great, so it does return thrown Error from t.throws(), right?

It does indeed! :)

@@ -182,6 +183,29 @@ test('.throws()', function (t) {
t.end();
});

test('.throws() becomes the thrown Error', function (t) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

returns rather than becomes. Could lowercase Error as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gotcha!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would you like for me to change the subject of the Promise rejection while I'm at it? @novemberborn

'.throws() becomes the rejection reason of promise'
'.throws() returns the rejection reason of promise'

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, '.throws() returns the rejection reason of promise' is a correct version indeed.

@novemberborn
Copy link
Member

@kasperlewau cool! Just some simplifications in the test. Feel free to push up a squashed commit when that's fixed and I'll merge.

@kasperlewau
Copy link
Contributor Author

@novemberborn Resolved, squashed, pushed. Let the CI wait commence.

throw expected;
});

assert.same(actual, expected);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops wait. assert.same() means "deep equal". We want strict equality here. You should use assert.is(actual, expected) instead. Though the tests here are for AVA's assert module. Perhaps use t.is(actual, expected) which is from tap's assertion library (AVA's tests are run using tap).

Same below.

@novemberborn
Copy link
Member

@kasperlewau OK just the tiniest issue with the assertion. Feel free to force push again and I'll merge.

@kasperlewau
Copy link
Contributor Author

@novemberborn

Right-o! I'm still fairly new to ava (and tap for that matter). Coming from a chai background so I've hit the t.equal is not a function several times over now 😉

Off topic; same is a little bit far fetched when you want to perform a deep comparison. If you think twice about it, it makes all the more sense though. imho.

I'll get this sorted out!

@kasperlewau
Copy link
Contributor Author

Rebasing and pushing in a jiffy.

novemberborn added a commit that referenced this pull request Mar 2, 2016
Return thrown error/rejected promise from t.throws
@novemberborn novemberborn merged commit 829f91c into avajs:master Mar 2, 2016
@novemberborn
Copy link
Member

Thanks @kasperlewau!

giphy

@kasperlewau
Copy link
Contributor Author

Glad I could help! : )

@sindresorhus
Copy link
Member

Thank you! Keep'em coming :)

@vadimdemedes
Copy link
Contributor

Thanks a lot!

novemberborn added a commit that referenced this pull request Mar 17, 2016
PR #576 changed the `t.throws()` assertion to return the thrown error, or if
asynchronous a promise for the rejection reason. Unfortunately this only worked
for asynchronous errors.

The tests cover the changes in `lib/assert.js` but `t.throws()` is an *enhanced*
assertion. This commit ensures any values returned from `lib/assert.js`
assertions are indeed returned by the corresponding `t.` assertions.
@kasperlewau kasperlewau deleted the throws-return branch June 13, 2016 07:24
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

Successfully merging this pull request may close these issues.

5 participants