-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Make t.throws()
accept async function as parameter
#1650
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
Conversation
Hello, I am new here 😄 |
Broken on node 4 and 6 |
I don't think it matters whether the function is truly an |
@novemberborn So we need to try to execute the |
@okyantoro close. The way you're doing it now you're calling I think the trick is to capture This isn't great because of how we wrap |
@novemberborn I realize that calling |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking good @okyantoro, almost there!
t.notThrows()
should be updated so that if the function returns a rejected promise, the assertion still fails.
The documentation for t.throws()
and t.notThrows()
should be updated to reflect the new behavior.
Similarly the TypeScript definition needs to be updated. I don't think the current Flow types prohibit this behavior but the documentation should be updated there too.
Let me know if you get stuck anywhere. The type definitions may be a bit daunting if you haven't used TypeScript or Flow before.
lib/assert.js
Outdated
}; | ||
|
||
if (promise) { | ||
return handlePromise.call(this, promise); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
handlePromise
is an arrow function, so .call(this
isn't necessary. Just do return handlePromise(promise)
.
lib/assert.js
Outdated
return handlePromise.call(this, maybePromise); | ||
} | ||
if (isObservable(maybePromise)) { | ||
return handlePromise.call(this, observableToPromise(maybePromise)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you add a test for this code path?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sure, we can use already provided library zen-observable
in package.json
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Just updating the PR state to reflect that it needs a bit more work before it's merged.)
t.throws()
accept async function as parameter.t.throws()
accept async function as parameter
hi @novemberborn I'll continue this on saturday or sunday. Thank you for the suggestions and help |
hello @novemberborn |
@okyantoro yup. |
@novemberborn when I try to add function signature for
or maybe I did something wrong when added the function signature. |
index.js.flow
Outdated
@@ -56,12 +56,14 @@ type AssertContext = { | |||
// Assert that value is not deep equal to expected. | |||
notDeepEqual<U>(value: U, expected: U, message?: string): void; | |||
// Assert that function throws an error or promise rejects. | |||
// If the given function returns Promise, then the Promise will be evaluated instead. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Promise
=> a Promise
index.js.flow
Outdated
// @param error Can be a constructor, regex, error message or validation function. | ||
throws: { | ||
(value: PromiseLike<mixed>, error?: ErrorValidator, message?: string): Promise<any>; | ||
(value: () => mixed, error?: ErrorValidator, message?: string): any; | ||
}; | ||
// Assert that function doesn't throw an error or promise resolves. | ||
// If the given function returns Promise, then the Promise will be evaluated instead. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Promise
=> a Promise
readme.md
Outdated
@@ -948,7 +948,7 @@ Assert that `value` is not deeply equal to `expected`. The inverse of `.deepEqua | |||
|
|||
### `.throws(function|promise, [error, [message]])` | |||
|
|||
Assert that `function` throws an error, or `promise` rejects with an error. | |||
Assert that `function` throws an error, `promise` rejects with an error, or `function` that return rejected `promise`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
or `function` that return rejected `promise`.
⬇️
or `function` returns a rejected `promise`.
readme.md
Outdated
@@ -987,9 +997,19 @@ test('rejects', async t => { | |||
}); | |||
``` | |||
|
|||
Because a `function` that return a `promise` is allowed to be a parameter, then you can pass `async function` that throws exception as parameter: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This sentence needs to be better worded.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe we can make it simple like:
When testing an
async function
you must also wait for the assertion to complete:
@sindresorhus is it better?
readme.md
Outdated
### `.notThrows(function|promise, [message])` | ||
|
||
Assert that `function` does not throw an error or that `promise` does not reject with an error. | ||
Assert that `function` does not throw an error or that `promise` does not reject with an error. When you pass a `function` that return a `promise` as parameter, the returned promise will be evaluated instead. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return
=> returns
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
when I try to add function signature for function that return promise, I get the following error:
Odd! Perhaps try upgrading the Flow version used within AVA, perhaps it's a bug that has since been fixed.
This is almost there @okyantoro 👍 Don't forget to add pass and failure cases to https://github.com/avajs/ava/blob/a051d3e18dba92c893fddb08490a8627f586c231/test/assert.js#L624:L659 and https://github.com/avajs/ava/blob/master/test/assert.js#L701:L727.
index.js.flow
Outdated
@@ -56,12 +56,14 @@ type AssertContext = { | |||
// Assert that value is not deep equal to expected. | |||
notDeepEqual<U>(value: U, expected: U, message?: string): void; | |||
// Assert that function throws an error or promise rejects. | |||
// If the given function returns a Promise, then the Promise will be evaluated instead. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's go with:
// Assert that the promise rejects, or the function throws or returns a rejected promise.
index.js.flow
Outdated
// @param error Can be a constructor, regex, error message or validation function. | ||
throws: { | ||
(value: PromiseLike<mixed>, error?: ErrorValidator, message?: string): Promise<any>; | ||
(value: () => mixed, error?: ErrorValidator, message?: string): any; | ||
}; | ||
// Assert that function doesn't throw an error or promise resolves. | ||
// If the given function returns a Promise, then the Promise will be evaluated instead. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's go with:
// Assert that the promise resolves, or the function doesn't throws or returns a resolved promise.
readme.md
Outdated
await t.throws(async () => { | ||
throw new TypeError('🦄'); | ||
}); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps replace this example with the async function one you added above, and remove it there.
readme.md
Outdated
### `.notThrows(function|promise, [message])` | ||
|
||
Assert that `function` does not throw an error or that `promise` does not reject with an error. | ||
Assert that `function` does not throw an error or that `promise` does not reject with an error. When you pass a `function` that returns a `promise` as parameter, the returned promise will be evaluated instead. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Assert that
function
does not throw an error,promise
does not reject with an error, orfunction
returns a promise that does not reject with an error.
test/assert.js
Outdated
@@ -678,6 +679,28 @@ test('.throws() returns the rejection reason of promise', t => { | |||
}); | |||
}); | |||
|
|||
test('.throws() returns the rejection reason of function that return rejected `Promise`', t => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
.throws() returns the rejection reason of a promise returned by the function
test/assert.js
Outdated
}); | ||
}); | ||
|
||
test('.throws() throws exception from `Observable`', t => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
.throws() returns the error of an observable returned by the function
test/assert.js
Outdated
@@ -732,6 +755,22 @@ test('.notThrows() returns undefined for a fulfilled promise', t => { | |||
}); | |||
}); | |||
|
|||
test('.notThrows() returns undefined for a function that return fulfilled promise', t => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
.notThrows() returns undefined for a fulfilled promise returned by the function
test/assert.js
Outdated
}); | ||
}); | ||
|
||
test('.notThrows() returns undefined for a function that return `Observable`', t => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
.notThrows() returns undefined for an observable returned by the function
hi @novemberborn (value: () => PromiseLike<mixed>, error?: ErrorValidator, message?: string): Promise<any>;
(value: () => mixed, error?: ErrorValidator, message?: string): any; correct me if I am wrong.
isn't it already covered by these lines: test('.throws() returns the rejection reason of promise', t => {
const expected = new Error();
return assertions.throws(Promise.reject(expected)).then(actual => {
t.is(actual, expected);
t.end();
});
});
test('.throws() returns the rejection reason of a promise returned by the function', t => {
const expected = new Error();
return assertions.throws(() => {
return Promise.reject(expected);
}).then(actual => {
t.is(actual, expected);
t.end();
});
}); and test('.notThrows() returns undefined for a fulfilled promise', t => {
return assertions.notThrows(Promise.resolve(Symbol(''))).then(actual => {
t.is(actual, undefined);
});
});
test('.notThrows() returns undefined for a fulfilled promise returned by the function', t => {
return assertions.notThrows(() => {
return Promise.resolve(Symbol(''));
}).then(actual => {
t.is(actual, undefined);
});
}); ? Thank you |
I don't know @okyantoro. Don't worry about it, we can always open an issue for somebody else to refine the signature.
Those tests are specifically about the expected pass/fail behavior, given all the ways the assertion can be used. The other tests are about their return value. They exercise the same code paths but they're a little different in intent. It's useful to see all possible behaviors in one place. |
@novemberborn Oh I see. Updated. Is it correct? |
@okyantoro this is great! I pushed some minor tweaks but will merge when CI passes. Regarding my previous comment:
Turns out I was wrong here, |
Thank you @novemberborn |
When an async callback is given to
t.throws()
, it will execute the function and put the returnedPromise
topromise
variable. The rest is same as processingPromise
.This commit introduce new private function
isAsync()
insideasserts.wrapAssertions()
Refs: #1371