-
Notifications
You must be signed in to change notification settings - Fork 1.4k
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
Conditionally perform assertions, allow tests to commit to the results #1692
Comments
@danr interesting! AVA doesn't let you create new tests once tests have started running. I can't quite tell how Taking this example: const test = require('ava')
const { check, gen } = require('ava-check')
test('addition is commutative', check(gen.int, gen.int, (t, numA, numB) => {
t.true(numA + numB === numB + numA)
})); What if function check(genA, genB, implementation) {
return async t => {
while (true) {
const result = await t.try(implementation, genA(), genB())
if (result.passed || cannotMinimizeFurther()) {
return result.commit()
}
}
}
} With a rough type definition of: interface ExecutionContext {
try (implementation: (t: ExecutionContext, ...args: any[]) => void, ...args: any[]): Promise<TryResult>
}
interface TryResult {
passed: boolean
assertionErrors: AssertionError[]
commit (): boolean
} And in actual English: I like how this is low-level, which means we can support interesting higher-order tests. @avajs/core what do you think? |
@novemberborn: Thanks for your response and the write up. Your interface ExecutionContext {
try (implementation: (t: ExecutionContext) => void): Promise<TryResult>
} The call to const result = await t.try(t2 => implementation(t2, genA(), genB())) Rationale: improved type-safety and smaller type signature for (A name that is not a javascript keyword must be used instead of Your I am a bit skeptical about this behaviour:
Is this not overly restrictive? There should be no particular reason to make this a test failure by default. |
Perhaps. We have a pattern of supporting additional arguments that get passed to the implementation, seems nice to retain that.
It should work as a property.
That's how AVA behaves out of the box. Tests must use assertions. IMHO not committing a |
Alright! I retract all those remarks then :) |
Any further comments on this? Is it likely that this would be accepted upstreams? If so can anyone give me some pointers or how to implement what @novemberborn and I have discussed? |
@sindresorhus what do you think about my proposal? |
@novemberborn I like it. It's simple and can enable a lot of interesting use-cases. 👍 from me. |
Expanding on my earlier comment #1692 (comment) there's the question of what to do with We do support Perhaps we should do the same when passing the execution context to the Should we allow recursively calling Does Ordinarily assertions are implemented in
This is the point where my architecting runs into "this should really be played with in code" so I'm going to stop. @danr let me know if you want to take this on, happy to review code and give pointers! |
I've thought about this some more and I think it's wrong. Potentially a third-party module is used which then calls a user-provided implementation. Users may want to plan the number of assertions in their implementation. The third-party module wouldn't be able to do this. Instead we should not allow |
Hey @novemberborn, great to see your interest in this. I'm swamped time-wise right now so I can't contribute anything code-wise atm.
I agree with this. Consider the quick-check usage: the test that is started using |
We should allow the test result to be discarded, perhaps without even waiting for the promise returned by |
I arrived at this issue searching for a way to retry assertions until they succeed, similar to how Scala Specs2 does it https://github.com/etorreborre/specs2/blob/master/tests/src/test/scala/org/specs2/matcher/EventuallyMatchersSpec.scala in pseudo-code:
In spec2, by default it retries 40 times with a delay of 100ms, but both are configurable and have in the past needed to use with delay of 0ms and delay of 1000ms. One example of where this is interesting. This allows you to avoid adding sleep for testing slow async operations. It will keep retrying until ready or max retries is reached. Is there any wait do that today? |
To help anyone wanting the same feature, here is how I implemented it:
Of course this has the drawback of only supporting UPDATE: this is what I did: https://github.com/dashuser33/darkcoin-client/blob/master/src/lib/async.ts#L20 |
I like property based testing too and used jsverify as in ava-jsverify by @imranolas. it worked nice but also augments Ava internals (I believe). so integration can be harsh sometimes. |
I was thinking about utilising macros for this purpose. do you think it is feasible? |
@iamstarkov There is a work in progress solution sitting in the #1947. I've been using it on my project and it works for now. There will be changes before it will get merged into master, but if you really would like to, you can check it out at that specific commit bde2be1. I also use jsverify but I modified the connector between ava and jsverify: https://gist.github.com/qlonik/9a297285284d71f7da47022f120ef4ad. The modification handles the logging slightly better, provides typings, and works with try-commit/discard pull request. It is written to work in a way similar to the original ava-jsverify. Maybe later on, it could be modified to be a macro. |
Please consider my pull request #2078 |
We've landed @qlonik's PR and it'll be released soon. For follow-up issues see https://github.com/orgs/avajs/projects/1. |
Please see #1692 (comment) for the accepted proposal and #1692 (comment) for follow-up.
Original issue follows:
Description: add observeTest and commitToResult
Right now we have a function
test
of which the essence has this type signature:It would be helpful for library writers if there was a function:
edit: fixed the type signature
For my purposes
TestResult
can be a completely opaque type.The use for it is to make this a result for the main driver. For the lack of a better name I will call it
commitToResult
for now. This could either be a function exported by AVA (or a method on AVA's exportedtest
), or a method onTestContext
:or
Use case: property based testing
The use case for this is property-based testing, which was first introduced in Haskell with the package QuickCheck.
There are quite a few implementations for JavaScript, for example jsverify, testcheck-js. The idea is to generate random data and test if functions satsify properties run on these data to approximate universal quantification. If the test fails it is common practice in these libraries to try to shrink the generated data. Then the user can be presented with a small (and hopefully minimal) counterexample.
The library writer of a property-based testing would then run tests written using asserts as in AVA-style, but behind the hoods it would be run with
observeTest
, and if it fails start a loop trying to shrink the randomly generated input until it cannot be shrunk anymore and then report the smallest possible failingTestResult
usingcommitToResult
.There is intergration for AVA in
testcheck-js/AVA-check, but it has to use the AVA internals and is thus a pain to maintain, see for example this commit in a PR by me: leebyron/testcheck-js@65ef263 So there would be clear benefits for library writers if AVA could expose these two functions.
The text was updated successfully, but these errors were encountered: