1"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([["17095"],{59215(e,t,n){n.r(t),n.d(t,{assets:()=>o,contentTitle:()=>l,default:()=>h,frontMatter:()=>a,metadata:()=>i,toc:()=>r});var i=n(85256),s=n(61058),c=n(24801);let a={title:"What's new in fast-check 4.2.0?",authors:["dubzzz"],tags:["release","scheduler","race-conditions","async-testing"]},l,o={authorsImageUrls:[void 0]},r=[{value:"Context",id:"context",level:2},{value:"<code>waitIdle</code> a better <code>waitAll</code>",id:"waitidle-a-better-waitall",level:2},{value:"<code>waitNext</code> a better <code>waitOne</code>",id:"waitnext-a-better-waitone",level:2},{value:"Changelog since 4.1.0",id:"changelog-since-410",level:2},{value:"Features",id:"features",level:3},{value:"Fixes",id:"fixes",level:3}];function d(e){let t={a:"a",code:"code",h2:"h2",h3:"h3",li:"li",p:"p",pre:"pre",ul:"ul",...(0,c.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.p,{children:"With version 4.2.0, we are re-affirming our will to provide our users with efficient and easy to use primitives around race condition detection. Because race conditions are far from easy to detect and think of we want to make them easy to track. For that reason we decided to introduce two new primitives to help you waiting for the scheduler to be done."}),"\n",(0,s.jsx)(t.p,{children:"Continue reading to explore the detailed updates it brings."}),"\n","\n",(0,s.jsx)(t.h2,{id:"context",children:"Context"}),"\n",(0,s.jsxs)(t.p,{children:["When releasing version 4.0.0 of fast-check we decided that having a predictable behaviour on ",(0,s.jsx)(t.code,{children:"waitOne"})," and ",(0,s.jsx)(t.code,{children:"waitAll"})," was key. We thus dropped a subtle gotcha from their respective implementations that was making them dependent on how many micro tasks were to be awaited before scheduling the next ones. While making them more predictive (no threshold effect) it made them harder to use making race condition detection more complex to write. That said primitives like ",(0,s.jsx)(t.code,{children:"waitFor"})," stayed simple to use even they forced our users to build something we can wait for."]}),"\n",(0,s.jsxs)(t.h2,{id:"waitidle-a-better-waitall",children:[(0,s.jsx)(t.code,{children:"waitIdle"})," a better ",(0,s.jsx)(t.code,{children:"waitAll"})]}),"\n",(0,s.jsxs)(t.p,{children:["The newly introduced ",(0,s.jsx)(t.code,{children:"waitIdle"})," provides a simple, efficient and predicable way to wait for all tasks to be scheduled by ",(0,s.jsx)(t.code,{children:"fc.scheduler"}),". It does not come with the gotchas we had on ",(0,s.jsx)(t.code,{children:"waitAll"})," in previous majors while offering an API as easy to use."]}),"\n",(0,s.jsx)(t.p,{children:"Let see how it simplify the flow of checking race conditions:"}),"\n",(0,s.jsx)(t.pre,{children:(0,s.jsx)(t.code,{className:"language-ts",children:"import { test, expect } from 'vitest';\n\ntest('our test', async () => {\n await fc.assert(\n fc.asyncProperty(fc.scheduler(), async (s) => {\n const fetchIdFor = s.scheduleFunction(async (name) => `id:${name}`);\n const { doStuff, warmup } = buildDoStuff(fetchIdFor);\n await warmup();\n let done = false;\n doStuff('name').then(() => (done = true));\n await s.waitAll();\n expect(done).toBe(true);\n }),\n );\n});\n\n// In a real world example, the function below would probably have been defined\n// into a dedicated file not being the file holding the test.\nfunction buildDoStuff(fetchIdFor) {\n return {\n doStuff: async function doStuff(name) {\n const { default: executeTaskOnId } = await import('./executor');\n await executeTaskOnId(await fetchIdFor(name));\n },\n warmup: async function warmup(name) {\n await import('./executor');\n },\n };\n}\n"})}),"\n",(0,s.jsxs)(t.p,{children:["This test does not pass. Actually nothing got scheduled in time so ",(0,s.jsx)(t.code,{children:"waitAll"})," ended immediatelly. Calling ",(0,s.jsx)(t.code,{children:"s.report()"})," after the execution of ",(0,s.jsx)(t.code,{children:"waitAll"})," and checking its output confirms it: nothing has been released by the scheduler and the scheduler has not seen any tasks yet. The whole problem is that the call to ",(0,s.jsx)(t.code,{children:"fetchIdFor"})," is delayed a bit too much for ",(0,s.jsx)(t.code,{children:"waitAll"})," to see it. Overall ",(0,s.jsx)(t.code,{children:"waitAll"})," makes the test harder to reason about as it may trigger failures for non obvious reasons that depends on micro-tasks."]}),"\n",(0,s.jsxs)(t.p,{children:["With ",(0,s.jsx)(t.code,{children:"waitIdle"}),", the test would have passed. The call would have been triggered and we would have scheduled all the expected tasks including the one from our call to ",(0,s.jsx)(t.code,{children:"fetchIdFor"}),"."]}),"\n",(0,s.jsxs)(t.h2,{id:"waitnext-a-better-waitone",children:[(0,s.jsx)(t.code,{children:"waitNext"})," a better ",(0,s.jsx)(t.code,{children:"waitOne"})]}),"\n",(0,s.jsxs)(t.p,{children:["With the same idea as ",(0,s.jsx)(t.code,{children:"waitIdle"}),", we created ",(0,s.jsx)(t.code,{children:"waitNext"}),". Instead of waiting for everything to be done, it waits for exactly N tasks to be scheduled no matter which ones. It can be seen as a better ",(0,s.jsx)(t.code,{children:"waitOne"})," adding the ability to wait for things to be really scheduled and based on a count."]}),"\n",(0,s.jsx)(t.h2,{id:"changelog-since-410",children:"Changelog since 4.1.0"}),"\n",(0,s.jsx)(t.p,{children:"The version 4.2.0 is based on version 4.1.1, but let see what's changed since 4.1.0 itself."}),"\n",(0,s.jsx)(t.h3,{id:"features",children:"Features"}),"\n",(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsxs)(t.li,{children:["(",(0,s.jsx)(t.a,{href:"https://github.com/dubzzz/fast-check/pull/5953",children:"PR#5953"}),") Do not silent errors popping in ",(0,s.jsx)(t.code,{children:"act"})]}),"\n",(0,s.jsxs)(t.li,{children:["(",(0,s.jsx)(t.a,{href:"https://github.com/dubzzz/fast-check/pull/5890",children:"PR#5890"}),") Introduce new awaiter on our ",(0,s.jsx)(t.code,{children:"scheduler"})]}),"\n",(0,s.jsxs)(t.li,{children:["(",(0,s.jsx)(t.a,{href:"https://github.com/dubzzz/fast-check/pull/6016",children:"PR#6016"}),") Introduce ",(0,s.jsx)(t.code,{children:"waitIdle"}),", a revamped ",(0,s.jsx)(t.code,{children:"waitAll"})," for ",(0,s.jsx)(t.code,{children:"scheduler"})]}),"\n",(0,s.jsxs)(t.li,{children:["(",(0,s.jsx)(t.a,{href:"https://github.com/dubzzz/fast-check/pull/6026",children:"PR#6026"}),") Deprecate ",(0,s.jsx)(t.code,{children:"waitOne"})," and ",(0,s.jsx)(t.code,{children:"waitAll"})]}),"\n"]}),"\n",(0,s.jsx)(t.h3,{id:"fixes",children:"Fixes"}),"\n",(0,s.jsxs)(t.ul,{children:["\n",(0,s.jsxs)(t.li,{children:["(",(0,s.jsx)(t.a,{href:"https://github.com/dubzzz/fast-check/pull/5900",children:"PR#5900"}),") Bug: Avoid overlapping tasks during ",(0,s.jsx)(t.code,{children:"scheduler"})," execution"]}),"\n",(0,s.jsxs)(t.li,{children:["(",(0,s.jsx)(t.a,{href:"https://github.com/dubzzz/fast-check/pull/5903",children:"PR#5903"}),") CI: Only run coverage for ubuntu on node 22"]}),"\n",(0,s.jsxs)(t.li,{children:["(",(0,s.jsx)(t.a,{href:"https://github.com/dubzzz/fast-check/pull/5904",children:"PR#5904"}),") CI: Shard Vitest execution on Windows runners"]}),"\n",(0,s.jsxs)(t.li,{children:["(",(0,s.jsx)(t.a,{href:"https://github.com/dubzzz/fast-check/pull/5907",children:"PR#5907"}),") CI: Always publish on pkg-pr-new"]}
1),"\n",(0,s.jsxs)(t.li,{children:["(",(0,s.jsx)(t.a,{href:"https://github.com/dubzzz/fast-check/pull/5935",children:"PR#5935"}),") CI: Get rid of LFS storage"]}),"\n",(0,s.jsxs)(t.li,{children:["(",(0,s.jsx)(t.a,{href:"https://github.com/dubzzz/fast-check/pull/5936",children:"PR#5936"}),") CI: Safer and faster static assets with hash checks"]}),"\n",(0,s.jsxs)(t.li,{children:["(",(0,s.jsx)(t.a,{href:"https://github.com/dubzzz/fast-check/pull/5943",children:"PR#5943"}),") CI: Stop stale from closing validated ideas"]}),"\n",(0,s.jsxs)(t.li,{children:["(",(0,s.jsx)(t.a,{href:"https://github.com/dubzzz/fast-check/pull/5954",children:"PR#5954"}),") CI: Make poisoning test compatible with Node 24"]}),"\n",(0,s.jsxs)(t.li,{children:["(",(0,s.jsx)(t.a,{href:"https://github.com/dubzzz/fast-check/pull/5969",children:"PR#5969"}),") CI: Measure coverage on Mac OS"]}),"\n",(0,s.jsxs)(t.li,{children:["(",(0,s.jsx)(t.a,{href:"https://github.com/dubzzz/fast-check/pull/5971",children:"PR#5971"}),") CI: Better exclusion list for Vitest"]}),"\n",(0,s.jsxs)(t.li,{children:["(",(0,s.jsx)(t.a,{href:"https://github.com/dubzzz/fast-check/pull/5989",children:"PR#5989"}),") CI: Attempt to stabilize tests"]}),"\n",(0,s.jsxs)(t.li,{children:["(",(0,s.jsx)(t.a,{href:"https://github.com/dubzzz/fast-check/pull/5894",children:"PR#5894"}),") Doc: Release note for 4.1.0"]}),"\n",(0,s.jsxs)(t.li,{children:["(",(0,s.jsx)(t.a,{href:"https://github.com/dubzzz/fast-check/pull/5937",children:"PR#5937"}),") Doc: Reference social media links on blog authors"]}),"\n",(0,s.jsxs)(t.li,{children:["(",(0,s.jsx)(t.a,{href:"https://github.com/dubzzz/fast-check/pull/5938",children:"PR#5938"}),") Doc: Fix social images on /docs and /blog"]}),"\n",(0,s.jsxs)(t.li,{children:["(",(0,s.jsx)(t.a,{href:"https://github.com/dubzzz/fast-check/pull/5965",children:"PR#5965"}),") Doc: update stringMatching docs"]}),"\n",(0,s.jsxs)(t.li,{children:["(",(0,s.jsx)(t.a,{href:"https://github.com/dubzzz/fast-check/pull/5966",children:"PR#5966"}),") Doc: Fix typo in model-based-testing.md"]}),"\n",(0,s.jsxs)(t.li,{children:["(",(0,s.jsx)(t.a,{href:"https://github.com/dubzzz/fast-check/pull/6015",children:"PR#6015"}),") Doc: Add new contributor matthyk"]}),"\n",(0,s.jsxs)(t.li,{children:["(",(0,s.jsx)(t.a,{href:"https://github.com/dubzzz/fast-check/pull/5973",children:"PR#5973"}),") Test: Drop unused checks in tests"]}),"\n",(0,s.jsxs)(t.li,{children:["(",(0,s.jsx)(t.a,{href:"https://github.com/dubzzz/fast-check/pull/6019",children:"PR#6019"}),") Test: Stop testing against Node 18"]}),"\n",(0,s.jsxs)(t.li,{children:["(",(0,s.jsx)(t.a,{href:"https://github.com/dubzzz/fast-check/pull/5901",children:"PR#5901"}),") Performance: Slightly faster ",(0,s.jsx)(t.code,{children:"scheduler"})," with explicit ",(0,s.jsx)(t.code,{children:"undefined"})," check"]}),"\n"]})]})}function h(e={}){let{wrapper:t}={...(0,c.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(d,{...e})}):d(e)}},24801(e,t,n){n.d(t,{R:()=>a,x:()=>l});var i=n(13706);let s={},c=i.createContext(s);function a(e){let t=i.useContext(c);return i.useMemo(function(){return"function"==typeof e?e(t):{...t,...e}},[t,e])}function l(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:a(e.components),i.createElement(c.Provider,{value:t},e.children)}},85256(e){e.exports=JSON.parse('{"permalink":"/blog/2025/07/18/whats-new-in-fast-check-4-2-0","source":"@site/blog/2025-07-18-whats-new-in-fast-check-4-2-0/index.md","title":"What\'s new in fast-check 4.2.0?","description":"With version 4.2.0, we are re-affirming our will to provide our users with efficient and easy to use primitives around race condition detection. Because race conditions are far from easy to detect and think of we want to make them easy to track. For that reason we decided to introduce two new primitives to help you waiting for the scheduler to be done.","date":"2025-07-18T00:00:00.000Z","tags":[{"inline":true,"label":"release","permalink":"/blog/tags/release"},{"inline":true,"label":"scheduler","permalink":"/blog/tags/scheduler"},{"inline":true,"label":"race-conditions","permalink":"/blog/tags/race-conditions"},{"inline":true,"label":"async-testing","permalink":"/blog/tags/async-testing"}],"readingTime":4.46,"hasTruncateMarker":true,"authors":[{"name":"Nicolas Dubien","title":"fast-check maintainer","url":"https://github.com/dubzzz","socials":{"bluesky":"https://bsky.app/profile/nicolas.dubien.me","github":"https://github.com/dubzzz","linkedin":"https://www.linkedin.com/in/nicolas-dubien-623a9342/"},"imageURL":"/img/_/avatar_48_dubzzz.jpg","key":"dubzzz","page":null}],"frontMatter":{"title":"What\'s new in fast-check 4.2.0?","authors":["dubzzz"],"tags":["release","scheduler","race-conditions","async-testing"]},"unlisted":false,"prevItem":{"title":"What\'s new in fast-check 4.3.0?","permalink":"/blog/2025/09/05/whats-new-in-fast-check-4-3-0"},"nextItem":{"title":"What\'s new in fast-check 4.1.0?","permalink":"/blog/2025/04/06/whats-new-in-fast-check-4-1-0"}}')}}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.