question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Custom shrinkers like jsverify

See original GitHub issue

💬 Question and Help

Despite loving the idea that you don’t have to bother writing your own shrinkers most of the time in fast-check, for more complex cases it falls short. I was thinking of using a JSON diff as the counter examples produced contained too much noise to see what might have gone wrong. And rather than going that route or updating my old jsverify code, I thought it better to just ask how to do this in fast-check instead. My approach as mentioned in #1316, works good enough for most cases, but now that I have solved most issues, it seems to only produce counter examples that are not shrinked properly. I am pretty sure this is due to my use of .chain, but without it I cannot express how it should go about shrinking. So unless there have been some updates addressing the shrinking of recursive data structures that would allow me to do without .chain, I figure I will have to write my own shrinker.

In my previous issue #1316, I was told to check ArbitraryWithShrink.ts if I wanted to go about writing my own shrinker. The problem I have with this API is that for complex values, you want subvalues to use existing shrinkers, but I can’t. Fundamental building blocks like .array don’t have a .shrinkableFor. What then if I have an object value that I want to write a .shrinkableFor for, containing an array in one of its values? I don’t want to reproduce the shrinking logic for arrays just because my object contains one. Ideally I would only have to write the custom shrinking logic and leverage builtins shrinkers for the rest, like you do in jsverify. Am I going about it the wrong way, or are there any examples of this type of shrinking?

As an example, this is what I did in my jsverify code to shrink Tag objects and what I want to reproduce in fast-check:

function shrinkTag(ensureIsAttribute: boolean) {
  return shr.bless((tag: Tag) => {
    let shrs = lazyseq.nil
    if (tag.contents.length > 0) {
      shrs = shrs.append(() => {
        let tags = tag.contents.filter(content => typeof content !== "string") as Tag[]
        if (ensureIsAttribute) {
          tags = tags.map(tag => ({ ...tag, isAttribute: true }))
        }
        return tags
      })
    }
    if (tag.attributes.length > 0) {
      shrs = shrs.append(tag.attributes)
    }
    if (tag.contents.length > 0) {
      if (tag.isLiteral) {
        shrs = shrs.append(shrText(tag.contents[0] as string).map(text => ({ ...tag, contents: [text] })))
      } else {
        shrs = shrs.append(shrContents(tag.contents).map(contents => ({ ...tag, contents })))
      }
    }
    if (tag.attributes.length > 0) {
      shrs = shrs.append(
        shr
          .array(shrAttribute)(tag.attributes)
          .map(attributes => ({ ...tag, attributes })),
      )
    }
    shrs = shrs.append(shrTagName(tag.name).map(name => ({ ...tag, name })))
    if (tag.isLiteral) {
      shrs = shrs.append([{ ...tag, isLiteral: false }])
    }
    if (tag.isAttribute && !ensureIsAttribute) {
      shrs = shrs.append([{ ...tag, isAttribute: false }])
    }
    if (tag.isQuoted) {
      shrs = shrs.append([{ ...tag, isQuoted: false }])
    }
    return shrs
  })
}

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:18 (9 by maintainers)

github_iconTop GitHub Comments

1reaction
msteencommented, Jun 23, 2022

Thanks for letting me know, you are doing great work! This library makes me have confidence in my code on a level I would otherwise never be able to get, and thus makes working in TypeScript much more enjoyable.

1reaction
msteencommented, Jun 3, 2021

This is looking great! I have tested it locally and it works. Your example code does not type check for me (the helper), some unknown type gets injected, which requires quite a bit extra types to circumvent, so I just added a few @ts-ignore comments for now. I look forward to experimenting with this new version to see how I can improve my tests! I will be closing the issue as it should be addressed now. Thank you!

Read more comments on GitHub >

github_iconTop Results From Across the Web

dubzzz/jsverify-commands - GitHub
Bring commands to JSVerify property-based testing framework - GitHub ... The move has been done because the shrinkers provided by jsverify were far...
Read more >
fast-check - npm
Property based testing framework for JavaScript (like QuickCheck). Latest version: 3.1.2, last published: 3 days ago.
Read more >
Juzo Stump shrinkers
Discover the individually custom-made Juzo stump shrinkers to treat oedema on arms and legs. ... as well as Juzo Expert Cotton with skin-friendly...
Read more >
Property Testing with JSVerify · Part I - DEV Community ‍ ‍
JSVerify's API documentation appears to assume a certain level of familiarity with "type tetris" and functional idioms like monads.
Read more >
Creating a custom arbitrary in JSVerify | by Christopher Wells
So I have some code that I want to test. I've written some unit tests, but frankly they are getting fairly tiresome to...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found