dubzzz / fast-check

Property based testing framework for JavaScript (like QuickCheck) written in TypeScript

Home Page:https://fast-check.dev/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Non-termination of test execution in Jest when tested function mutates its arguments

gruhn opened this issue Β· comments

πŸ› Bug Report

In some situations test execution doesn't appear to terminate. It also does not run into a timeout. I suspect this can happen when the tested function mutates its arguments. I have only observed this with Jest, so I'm not sure if this is rather a Jest issue.

To Reproduce

Consider the following example (full setup available in this repository):

const fc = require('fast-check')

// the function to be tested
function nasty(array) {
    array.push(1) // nasty argument mutation
    return array
}

test('demo test', () => {
    fc.assert(fc.property(
        fc.array(fc.integer()),
        array_before => {
            const array_after = nasty(array_before)

            // some random assertion that should eventually fail
            expect(array_after.length).toBeLessThenOrEqual(3)
        }
    ))
})

If I run this with Jest, it looks like this. Note, if I pass a copy of array_before into nasty, the test run terminates immediately (with a failure as expected). So I really think the argument mutation is the offender here.

Screen.Recording.2022-09-26.at.16.23.34.mov

Your environment

Packages / Softwares Version(s)
fast-check 3.1.4
node v16.0.5
jest 29.0.3

Hey,

Thanks a lot for the report, but this is actually something fully expected as written in the official documentation. See:

The predicate function must not change the inputs it received. If it needs to, it has to clone them before going on. Impacting the inputs might led to bad shrinking and wrong display on error.

Link: https://github.com/dubzzz/fast-check/blob/main/packages/fast-check/documentation/Runners.md#properties

Unfortunately patching this kind of issue would have an overall negative performance impact for all tests being written via fast-check. Meanwhile I could probably come with some kind of helper to at least detect poisoned inputs (as the one I already provide to detect poisoned globals via @fast-check/poisoning).

I see... Thanks for the quick response. But do you understand why it's not terminating? Shouldn't Jests timeout kick in eventually?

If I'm not wrong, by default, Jest is unable to kill a test running into an infinite loop so it might be the reason why the test cannot be stopped. But they might have a worker based version that can do that (not sure).

Regarding this issue on itself, I'll probably check to see if I can make array's shrink more resilient to external modifications. But fixing it or not will highly depends on the overall runtime cost it can add.

Makes sense. Close this if you want. Thanks you!

Let's keep it opened for now so that I can have a reminder that there is possibly a quick improvement to do for the shrinker of arrays.

Good news: I have some ideas to make it work with, I hope, no runtime footprint but probably a huge memory footprint as I'll have to keep one copy of the array in memory to make the code work. I'll work on it soon and assess impacts to check whether acceptable or not. The risk of side effects being huge, it does not seem that an issue to try to limit that kind of issues to the end user a little bit more if feasible without any excessive impact.

I'll close it for now and probably take it back later as part of a more important set of changes