What's new in fast-check 4.2.0?
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.
Continue reading to explore the detailed updates it brings.
Context
When releasing version 4.0.0 of fast-check we decided that having a predictable behaviour on waitOne
and 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 waitFor
stayed simple to use even they forced our users to build something we can wait for.
waitIdle
a better waitAll
The newly introduced waitIdle
provides a simple, efficient and predicable way to wait for all tasks to be scheduled by fc.scheduler
. It does not come with the gotchas we had on waitAll
in previous majors while offering an API as easy to use.
Let see how it simplify the flow of checking race conditions:
import { test, expect } from 'vitest';
test('our test', async () => {
await fc.assert(
fc.asyncProperty(fc.scheduler(), async (s) => {
const fetchIdFor = s.scheduleFunction(async (name) => `id:${name}`);
const { doStuff, warmup } = buildDoStuff(fetchIdFor);
await warmup();
let done = false;
doStuff('name').then(() => (done = true));
await s.waitAll();
expect(done).toBe(true);
}),
);
});
// In a real world example, the function below would probably have been defined
// into a dedicated file not being the file holding the test.
function buildDoStuff(fetchIdFor) {
return {
doStuff: async function doStuff(name) {
const { default: executeTaskOnId } = await import('./executor');
await executeTaskOnId(await fetchIdFor(name));
},
warmup: async function warmup(name) {
await import('./executor');
},
};
}
This test does not pass. Actually nothing got scheduled in time so waitAll
ended immediatelly. Calling s.report()
after the execution of 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 fetchIdFor
is delayed a bit too much for waitAll
to see it. Overall waitAll
makes the test harder to reason about as it may trigger failures for non obvious reasons that depends on micro-tasks.
With 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 fetchIdFor
.
waitNext
a better waitOne
With the same idea as waitIdle
, we created 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 waitOne
adding the ability to wait for things to be really scheduled and based on a count.
Changelog since 4.1.0
The version 4.2.0 is based on version 4.1.1, but let see what's changed since 4.1.0 itself.
Features
- (PR#5953) Do not silent errors popping in
act
- (PR#5890) Introduce new awaiter on our
scheduler
- (PR#6016) Introduce
waitIdle
, a revampedwaitAll
forscheduler
- (PR#6026) Deprecate
waitOne
andwaitAll
Fixes
- (PR#5900) Bug: Avoid overlapping tasks during
scheduler
execution - (PR#5903) CI: Only run coverage for ubuntu on node 22
- (PR#5904) CI: Shard Vitest execution on Windows runners
- (PR#5907) CI: Always publish on pkg-pr-new
- (PR#5935) CI: Get rid of LFS storage
- (PR#5936) CI: Safer and faster static assets with hash checks
- (PR#5943) CI: Stop stale from closing validated ideas
- (PR#5954) CI: Make poisoning test compatible with Node 24
- (PR#5969) CI: Measure coverage on Mac OS
- (PR#5971) CI: Better exclusion list for Vitest
- (PR#5989) CI: Attempt to stabilize tests
- (PR#5894) Doc: Release note for 4.1.0
- (PR#5937) Doc: Reference social media links on blog authors
- (PR#5938) Doc: Fix social images on /docs and /blog
- (PR#5965) Doc: update stringMatching docs
- (PR#5966) Doc: Fix typo in model-based-testing.md
- (PR#6015) Doc: Add new contributor matthyk
- (PR#5973) Test: Drop unused checks in tests
- (PR#6019) Test: Stop testing against Node 18
- (PR#5901) Performance: Slightly faster
scheduler
with explicitundefined
check