Skip to content

📝 Add release notes for fast-check 4.8.0#7095

Merged
dubzzz merged 3 commits into
mainfrom
claude/write-release-blog-post-uV1gT
Jun 25, 2026
Merged

📝 Add release notes for fast-check 4.8.0#7095
dubzzz merged 3 commits into
mainfrom
claude/write-release-blog-post-uV1gT

Conversation

@dubzzz

@dubzzz dubzzz commented Jun 25, 2026

Copy link
Copy Markdown
Owner

Description

This PR adds the release notes blog post for fast-check 4.8.0, documenting the new chainUntil arbitrary combiner and other changes since 4.7.0.

The blog post explains:

  • The new chainUntil combiner for iterative chaining with proper shrinking support
  • Why a dedicated combiner was needed over nested .chain calls
  • Implementation details of the iterative approach for both generation and shrinking
  • A comprehensive changelog of features, fixes, documentation, CI, and test improvements

Checklist

  • I have a full understanding of every line in this PR — whether the code was hand-written, AI-generated, copied from external sources or produced by any other tool
  • I flagged the impact of my change (minor / patch / major) either by running pnpm run bump or by following the instructions from the changeset bot
  • I kept this PR focused on a single concern and did not bundle unrelated changes
  • I followed the gitmoji specification for the name of the PR, including the package scope (e.g. 🐛(vitest) Something...) when the change targets a package other than fast-check
  • I added relevant tests and they would have failed without my PR (when applicable)

https://claude.ai/code/session_01SDHoMrtmB4yec5AWL2E3C7

@changeset-bot

changeset-bot Bot commented Jun 25, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 74c4ea9

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@pkg-pr-new

pkg-pr-new Bot commented Jun 25, 2026

Copy link
Copy Markdown
@fast-check/ava

npm i https://pkg.pr.new/@fast-check/ava@7095

fast-check

npm i https://pkg.pr.new/fast-check@7095

@fast-check/jest

npm i https://pkg.pr.new/@fast-check/jest@7095

@fast-check/packaged

npm i https://pkg.pr.new/@fast-check/packaged@7095

@fast-check/poisoning

npm i https://pkg.pr.new/@fast-check/poisoning@7095

@fast-check/vitest

npm i https://pkg.pr.new/@fast-check/vitest@7095

@fast-check/worker

npm i https://pkg.pr.new/@fast-check/worker@7095

commit: 74c4ea9

@github-actions

github-actions Bot commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

⏱️ Benchmark Results

Click to expand

 RUN  v4.1.8 /home/runner/work/fast-check/fast-check


 ✓  fast-check  test/bench/arbitraries.bench.ts > generate 26248ms
     name                                                      hz      min      max     mean      p75      p99     p995     p999      rme  samples
   · boolean()                                          10,331.19   0.0810   0.6812   0.0968   0.1008   0.2001   0.2259   0.3686   ±0.76%     5166  [0.97x] ⇓
     boolean()                                          10,700.18   0.0806   0.7289   0.0935   0.0988   0.1517   0.1640   0.2685   ±0.57%     5351  (baseline)
   · integer()                                          10,790.25   0.0840   0.5456   0.0927   0.0913   0.1416   0.1458   0.1927   ±0.41%     5396  [0.86x] ⇓
     integer()                                          12,578.59   0.0737   0.4756   0.0795   0.0791   0.0999   0.1142   0.1433   ±0.26%     6290  (baseline)
   · maxSafeInteger()                                    7,841.11   0.1215   0.5639   0.1275   0.1256   0.1843   0.2053   0.5277   ±0.43%     3921  [1.02x] ⇑
     maxSafeInteger()                                    7,670.95   0.1244   0.4125   0.1304   0.1286   0.1535   0.1627   0.3518   ±0.28%     3836  (baseline)
   · bigInt()                                            1,371.69   0.6945   1.0684   0.7290   0.7303   0.9642   0.9861   1.0684   ±0.37%      686  [1.01x] ⇑
     bigInt()                                            1,353.90   0.6881   1.2953   0.7386   0.7394   0.9642   1.2372   1.2953   ±0.53%      677  (baseline)
   · float()                                             5,881.38   0.1577   0.6800   0.1700   0.1758   0.2095   0.2272   0.4826   ±0.41%     2942  [1.02x] ⇑
     float()                                             5,772.70   0.1587   0.4321   0.1732   0.1806   0.2371   0.2749   0.3553   ±0.38%     2887  (baseline)
   · double()                                            1,723.11   0.4867   5.8356   0.5803   0.5128   5.0682   5.2947   5.8356   ±5.95%      862  [1.01x] ⇑
     double()                                            1,698.77   0.4755   8.5443   0.5887   0.5099   4.8500   5.9910   8.5443   ±6.89%      850  (baseline)
   · date()                                              3,656.00   0.2429   5.6504   0.2735   0.2565   0.4553   0.5192   5.6366   ±5.37%     1828  [1.02x] ⇑
     date()                                              3,580.92   0.2475   5.4055   0.2793   0.2631   0.3103   0.4638   5.2604   ±5.15%     1791  (baseline)
   · string()                                              919.03   0.8064  12.2574   1.0881   0.8646   8.0098   8.6579  12.2574   ±9.80%      460  [1.20x] ⇑
     string()                                              767.99   0.8087  12.1828   1.3021   1.2548   9.6835   9.9817  12.1828  ±10.29%      384  (baseline)
   · string({ maxLength: 100, size: 'max' })               173.37   4.9244   8.9838   5.7681   5.4113   8.9838   8.9838   8.9838   ±4.72%       87  [1.07x] ⇑
     string({ maxLength: 100, size: 'max' })               161.34   5.1257  10.2911   6.1981   6.5340  10.2911  10.2911  10.2911   ±5.30%       81  (baseline)
   · string({ unit: 'grapheme' })                          601.19   1.2378  12.7015   1.6634   1.3229  12.3727  12.5381  12.7015  ±12.26%      301  [1.06x] ⇑
     string({ unit: 'grapheme' })                          568.86   1.2466  16.3822   1.7579   1.4217  14.9011  15.3632  16.3822  ±13.56%      285  (baseline)
   · base64String()                                        903.74   0.8362  11.6748   1.1065   0.8843   7.5935   8.6736  11.6748   ±9.84%      452  [0.99x] ⇓
     base64String()                                        909.16   0.8416   9.2377   1.0999   0.8911   7.3465   7.3971   9.2377   ±8.99%      455  (baseline)
   · array(integer())                                    1,601.90   0.4459   9.3576   0.6243   0.4791   7.0457   7.3366   9.3576  ±10.06%      801  [0.94x] ⇓
     array(integer())                                    1,697.85   0.4503   7.0772   0.5890   0.4853   6.7026   6.8174   7.0772   ±9.41%      849  (baseline)
   · array(integer(), { maxLength: 100, size: 'max' })     311.48   2.6010   7.6215   3.2104   2.8302   7.3533   7.6215   7.6215   ±6.33%      156  [1.05x] ⇑
     array(integer(), { maxLength: 100, size: 'max' })     296.61   2.5691  12.8511   3.3715   2.9097   8.2924  12.8511  12.8511   ±7.34%      149  (baseline)
   · uniqueArray(integer())                              1,147.09   0.6536   9.7680   0.8718   0.7066   6.3559   8.0465   9.7680   ±8.90%      574  [0.93x] ⇓
     uniqueArray(integer())                              1,235.97   0.6499   7.2819   0.8091   0.6991   5.6533   5.7499   7.2819   ±7.41%      618  (baseline)
   · set(integer())                                        935.53   0.8362   6.8661   1.0689   0.9402   5.8027   6.1101   6.8661   ±7.07%      468  [0.94x] ⇓
     set(integer())                                        997.88   0.8126   6.5747   1.0021   0.8809   5.1446   5.2334   6.5747   ±6.28%      499  (baseline)
   · tuple(integer())                                    5,699.85   0.1610   0.8382   0.1754   0.1734   0.2673   0.4961   0.6476   ±0.75%     2850  [0.95x] ⇓
     tuple(integer())                                    5,995.28   0.1573   0.5071   0.1668   0.1661   0.2071   0.3258   0.3737   ±0.38%     2998  (baseline)
   · record({ a: integer() })                            1,470.55   0.3626  15.8178   0.6800   0.3853  15.2132  15.4275  15.8178  ±20.29%      740  [0.84x] ⇓
     record({ a: integer() })                            1,757.16   0.3470  12.7315   0.5691   0.3658  11.2445  11.4028  12.7315  ±16.40%      879  (baseline)
   · dictionary(string(), integer())                      77.3980   8.1653  32.8579  12.9202  20.5811  32.8579  32.8579  32.8579  ±17.71%       39  [0.86x] ⇓
     dictionary(string(), integer())                      89.7612   7.8544  22.8448  11.1407  11.0350  22.8448  22.8448  22.8448  ±12.19%       45  (baseline)
   · map(string(), integer())                              114.75   5.3073  58.2323   8.7147   5.7289  58.2323  58.2323  58.2323  ±24.75%       58  [0.90x] ⇓
     map(string(), integer())                              127.45   5.1347  21.0226   7.8464   6.2563  21.0226  21.0226  21.0226  ±14.14%       64  (baseline)
   · constant(1)                                        30,639.95   0.0308   0.3274   0.0326   0.0319   0.0512   0.0549   0.2265   ±0.46%    15326  [1.02x] ⇑
     constant(1)                                        29,925.65   0.0320   0.3013   0.0334   0.0329   0.0449   0.0516   0.1795   ±0.34%    14963  (baseline)
   · constantFrom(1, 2)                                 13,753.02   0.0693   0.4484   0.0727   0.0717   0.0893   0.0927   0.3347   ±0.40%     6877  [1.02x] ⇑
     constantFrom(1, 2)                                 13,502.45   0.0712   0.3750   0.0741   0.0732   0.0862   0.0965   0.2442   ±0.27%     6752  (baseline)
   · oneof(integer(), integer())                         5,642.85   0.1678   0.7384   0.1772   0.1775   0.2034   0.2276   0.5364   ±0.41%     2822  [0.99x] ⇓
     oneof(integer(), integer())                         5,701.73   0.1670   0.5165   0.1754   0.1745   0.1985   0.2261   0.3505   ±0.27%     2851  (baseline)
   · oneof({ weight, arbitrary }, ...)                   5,519.85   0.1643   5.7313   0.1812   0.1748   0.3347   0.3592   0.7838   ±2.35%     2760  [0.95x] ⇓
     oneof({ weight, arbitrary }, ...)                   5,803.76   0.1642   0.4625   0.1723   0.1714   0.1962   0.2643   0.3517   ±0.27%     2902  (baseline)
   · option(integer())                                   4,455.46   0.1636  14.1622   0.2244   0.1744   0.2058   0.2309  12.9666  ±14.98%     2228  [0.75x] ⇓
     option(integer())                                   5,940.87   0.1606   0.4810   0.1683   0.1676   0.1908   0.2202   0.3369   ±0.29%     2971  (baseline)
   · subarray([1, 2, 3, 4, 5])                           2,195.03   0.4033   8.2039   0.4556   0.4365   1.0559   1.2216   1.4632   ±3.32%     1098  [0.94x] ⇓
     subarray([1, 2, 3, 4, 5])                           2,334.59   0.4018   0.7377   0.4283   0.4315   0.5803   0.6029   0.7342   ±0.34%     1168  (baseline)
   · letrec(tree)                                          723.98   0.9420  13.9297   1.3813   1.0594  13.7628  13.8185  13.9297  ±15.41%      362  [1.02x] ⇑
     letrec(tree)                                          711.62   0.8956  13.3553   1.4053   1.0218  13.2578  13.3097  13.3553  ±16.19%      356  (baseline)
   · memo(tree)                                            728.81   0.8929  14.0086   1.3721   0.9956  13.3188  13.5946  14.0086  ±16.13%      365  [0.99x] ⇓
     memo(tree)                                            734.80   0.8713  13.5972   1.3609   0.9694  12.6633  12.9860  13.5972  ±16.23%      368  (baseline)
   · anything()                                           67.3781  11.0218  27.5710  14.8416  13.9264  27.5710  27.5710  27.5710  ±12.13%       34  [1.01x] ⇑
     anything()                                           66.8227  10.5595  23.1481  14.9650  21.2717  23.1481  23.1481  23.1481  ±11.25%       34  (baseline)
   · json()                                               59.1072  12.0897  40.5712  16.9184  21.3745  40.5712  40.5712  40.5712  ±13.84%       30  [0.96x] ⇓
     json()                                               61.3692  11.4848  33.7230  16.2948  22.3524  33.7230  33.7230  33.7230  ±13.16%       31  (baseline)
   · entityGraph(employee -> manager? and team)           10.7740  87.2434   106.09  92.8163   100.61   106.09   106.09   106.09   ±5.53%       10  [0.98x] ⇓
     entityGraph(employee -> manager? and team)           10.9781  85.2982   116.67  91.0906  87.5184   116.67   116.67   116.67   ±8.20%       10  (baseline)
   · emailAddress()                                       69.7688  10.0348  32.4596  14.3331  20.5780  32.4596  32.4596  32.4596  ±13.69%       36  [1.01x] ⇑
     emailAddress()                                       69.3399   9.7474  32.8643  14.4217  19.7938  32.8643  32.8643  32.8643  ±14.13%       36  (baseline)
   · webUrl()                                              121.38   5.3272  25.5869   8.2383   5.6170  25.5869  25.5869  25.5869  ±16.33%       61  [1.01x] ⇑
     webUrl()                                              120.52   5.2003  22.9543   8.2973   6.2179  22.9543  22.9543  22.9543  ±16.29%       61  (baseline)
   · ipV4()                                              1,133.53   0.6620  12.7870   0.8822   0.6867  11.7815  12.1744  12.7870  ±13.84%      567  [0.97x] ⇓
     ipV4()                                              1,171.22   0.6496  12.7290   0.8538   0.6711  11.3224  11.5003  12.7290  ±13.30%      586  (baseline)
   · ipV6()                                                184.30   3.7604  15.9745   5.4260   3.9871  15.9745  15.9745  15.9745  ±13.58%       94  [0.95x] ⇓
     ipV6()                                                193.60   3.7208  13.8598   5.1654   3.8819  13.8598  13.8598  13.8598  ±12.60%       97  (baseline)
   · uuid()                                                566.26   1.2388  15.7390   1.7660   1.2692  15.0730  15.1631  15.7390  ±15.45%      290  [1.01x] ⇑
     uuid()                                                563.37   1.2551  15.6478   1.7750   1.2791  14.5986  14.6863  15.6478  ±15.32%      288  (baseline)
   · stringMatching(/^abc$/)                            29,852.33   0.0316   0.4659   0.0335   0.0327   0.0479   0.0552   0.3093   ±0.58%    14927  [1.02x] ⇑
     stringMatching(/^abc$/)                            29,367.30   0.0325   0.3633   0.0341   0.0334   0.0455   0.0516   0.2251   ±0.43%    14684  (baseline)
   · stringMatching(/^[a-zA-Z0-9]+$/)                      549.81   1.4669   9.3635   1.8188   1.5588   8.4131   8.5670   9.3635   ±7.81%      275  [1.10x] ⇑
     stringMatching(/^[a-zA-Z0-9]+$/)                      498.00   1.4303  12.9128   2.0080   1.5199  11.7055  11.7548  12.9128  ±12.54%      250  (baseline)
   · mixedCase(string())                                   529.55   1.6253   6.4877   1.8884   1.7057   6.1681   6.2046   6.4877   ±5.85%      265  [0.98x] ⇓
     mixedCase(string())                                   538.93   1.5972   5.8811   1.8555   1.6990   5.6316   5.7475   5.8811   ±5.17%      270  (baseline)
   · integer().map(value+1)                              7,957.74   0.1120   4.4782   0.1257   0.1206   0.2428   0.2548   0.6449   ±1.95%     3979  [1.03x] ⇑
     integer().map(value+1)                              7,730.20   0.1172   4.0262   0.1294   0.1246   0.2563   0.2689   0.5107   ±1.68%     3866  (baseline)
   · integer().chain(integer())                          3,881.39   0.2440   0.8211   0.2576   0.2589   0.4544   0.5533   0.7789   ±0.57%     1941  [0.98x] ⇓
     integer().chain(integer())                          3,952.23   0.2418   0.5204   0.2530   0.2559   0.3166   0.4055   0.4876   ±0.31%     1977  (baseline)
   · integer().filter(true)                              9,570.73   0.0975   0.7166   0.1045   0.1042   0.1204   0.1295   0.1939   ±0.41%     4786  [1.00x] ⇑
     integer().filter(true)                              9,523.89   0.0983   0.5015   0.1050   0.1048   0.1201   0.1267   0.1823   ±0.27%     4762  (baseline)

 ✓  fast-check  test/bench/runners.bench.ts > runner 2430ms
     name                                                     hz     min     max    mean     p75     p99    p995    p999     rme  samples
   · assert on sync predicate not returning anything   13,336.05  0.0721  0.3085  0.0750  0.0731  0.1413  0.1611  0.2023  ±0.36%     6669  [1.00x] ⇓
     assert on sync predicate not returning anything   13,351.36  0.0721  0.2800  0.0749  0.0729  0.1458  0.1574  0.1854  ±0.34%     6676  (baseline)
   · assert on sync predicate returning true           13,325.74  0.0718  0.3480  0.0750  0.0729  0.1481  0.1771  0.2274  ±0.41%     6663  [1.00x] ⇑
     assert on sync predicate returning true           13,274.79  0.0719  0.2961  0.0753  0.0733  0.1454  0.1585  0.2400  ±0.40%     6638  (baseline)
   · assert on async predicate not returning anything   8,756.58  0.1067  0.3496  0.1142  0.1115  0.1945  0.2017  0.2322  ±0.42%     4379  [0.98x] ⇓
     assert on async predicate not returning anything   8,930.65  0.1062  0.3265  0.1120  0.1083  0.1906  0.1938  0.2251  ±0.41%     4466  (baseline)
   · check on sync predicate not returning anything    13,146.21  0.0729  0.3155  0.0761  0.0738  0.1499  0.1617  0.2037  ±0.39%     6574  [0.99x] ⇓
     check on sync predicate not returning anything    13,245.00  0.0723  0.3733  0.0755  0.0733  0.1463  0.1541  0.2205  ±0.38%     6623  (baseline)

 BENCH  Summary

   fast-check  constant(1) - test/bench/arbitraries.bench.ts > generate
    1.03x faster than stringMatching(/^abc$/)
    2.23x faster than constantFrom(1, 2)
    2.84x faster than integer()
    2.97x faster than boolean()
    3.20x faster than integer().filter(true)
    3.85x faster than integer().map(value+1)
    3.91x faster than maxSafeInteger()
    5.21x faster than float()
    5.38x faster than tuple(integer())
    5.43x faster than oneof(integer(), integer())
    5.55x faster than oneof({ weight, arbitrary }, ...)
    6.88x faster than option(integer())
    7.89x faster than integer().chain(integer())
    8.38x faster than date()
    13.96x faster than subarray([1, 2, 3, 4, 5])
    17.78x faster than double()
    19.13x faster than array(integer())
    20.84x faster than record({ a: integer() })
    22.34x faster than bigInt()
    26.71x faster than uniqueArray(integer())
    27.03x faster than ipV4()
    32.75x faster than set(integer())
    33.34x faster than string()
    33.90x faster than base64String()
    42.04x faster than memo(tree)
    42.32x faster than letrec(tree)
    50.97x faster than string({ unit: 'grapheme' })
    54.11x faster than uuid()
    55.73x faster than stringMatching(/^[a-zA-Z0-9]+$/)
    57.86x faster than mixedCase(string())
    98.37x faster than array(integer(), { maxLength: 100, size: 'max' })
    166.25x faster than ipV6()
    176.73x faster than string({ maxLength: 100, size: 'max' })
    252.42x faster than webUrl()
    267.02x faster than map(string(), integer())
    395.88x faster than dictionary(string(), integer())
    439.16x faster than emailAddress()
    454.75x faster than anything()
    518.38x faster than json()
    2843.89x faster than entityGraph(employee -> manager? and team)

   fast-check  assert on sync predicate not returning anything - test/bench/runners.bench.ts > runner
    1.00x faster than assert on sync predicate returning true
    1.01x faster than check on sync predicate not returning anything
    1.52x faster than assert on async predicate not returning anything

Benchmark report written to /home/runner/work/fast-check/fast-check/benchmark.json

Commit: 74c4ea9 (merge: 38a7097)

@codecov

codecov Bot commented Jun 25, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 94.89%. Comparing base (c0da76f) to head (74c4ea9).
⚠️ Report is 99 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #7095      +/-   ##
==========================================
+ Coverage   94.78%   94.89%   +0.10%     
==========================================
  Files         212      212              
  Lines        5832     5951     +119     
  Branches     1536     1565      +29     
==========================================
+ Hits         5528     5647     +119     
  Misses        296      296              
  Partials        8        8              
Flag Coverage Δ
tests 94.89% <ø> (+0.10%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@dubzzz
dubzzz enabled auto-merge (squash) June 25, 2026 17:00
@dubzzz
dubzzz merged commit 5647ced into main Jun 25, 2026
52 checks passed
@dubzzz
dubzzz deleted the claude/write-release-blog-post-uV1gT branch June 25, 2026 17:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants