PageSourceSearch

https://fast-check.dev/assets/js/7012430d.f3e77574.js

js fast-check.dev collected 2026-10-02 04:24:10 UTC 10,684 bytes, 1 lines download raw bytes

1"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([["40049"],{11466(e,r,n){n.r(r),n.d(r,{metadata:()=>i,default:()=>h,frontMatter:()=>c,contentTitle:()=>o,toc:()=>l,assets:()=>a});var i=JSON.parse('{"id":"core-blocks/properties","title":"Properties","description":"Define your properties.","source":"@site/docs/core-blocks/properties.md","sourceDirName":"core-blocks","slug":"/core-blocks/properties/","permalink":"/docs/core-blocks/properties/","draft":false,"unlisted":false,"tags":[],"version":"current","lastUpdatedBy":"Nicolas DUBIEN","lastUpdatedAt":1787147242000,"sidebarPosition":2,"frontMatter":{"sidebar_position":2,"slug":"/core-blocks/properties/"},"sidebar":"tutorialSidebar","previous":{"title":"Others","permalink":"/docs/core-blocks/arbitraries/others/"},"next":{"title":"Runners","permalink":"/docs/core-blocks/runners/"}}'),t=n(61058),s=n(24801);let c={sidebar_position:2,slug:"/core-blocks/properties/"},o="Properties",a={},l=[{value:"Introduction",id:"introduction",level:2},{value:"Synchronous properties",id:"synchronous-properties",level:2},{value:"Basic",id:"basic",level:3},{value:"Advanced",id:"advanced",level:3},{value:"Example",id:"example",level:3},{value:"Asynchronous properties",id:"asynchronous-properties",level:2},{value:"Basic",id:"basic-1",level:3},{value:"Advanced",id:"advanced-1",level:3}];function d(e){let r={a:"a",admonition:"admonition",blockquote:"blockquote",br:"br",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",header:"header",li:"li",p:"p",pre:"pre",ul:"ul",...(0,s.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(r.header,{children:(0,t.jsx)(r.h1,{id:"properties",children:"Properties"})}),"\n",(0,t.jsx)(r.p,{children:"Define your properties."}),"\n",(0,t.jsx)(r.h2,{id:"introduction",children:"Introduction"}),"\n",(0,t.jsx)(r.p,{children:"Properties bring together arbitrary generators and predicates. They are a key building block for property based testing frameworks."}),"\n",(0,t.jsx)(r.p,{children:"They can be summarized by:"}),"\n",(0,t.jsxs)(r.blockquote,{children:["\n",(0,t.jsxs)(r.p,{children:["for any (x, y, ...)",(0,t.jsx)(r.br,{}),"\n","such that precondition(x, y, ...) holds",(0,t.jsx)(r.br,{}),"\n","predicate(x, y, ...) is true"]}),"\n"]}),"\n",(0,t.jsxs)(r.admonition,{title:"Equivalence in fast-check",type:"info",children:[(0,t.jsx)(r.p,{children:"Each part of the definition can be achieved directly within fast-check:"}),(0,t.jsxs)(r.ul,{children:["\n",(0,t.jsxs)(r.li,{children:['"',(0,t.jsx)(r.em,{children:"for any (x, y, ...)"}),'" via ',(0,t.jsx)(r.a,{href:"/docs/core-blocks/arbitraries/primitives/number/",children:"arbitraries"})]}),"\n",(0,t.jsxs)(r.li,{children:['"',(0,t.jsx)(r.em,{children:"such that precondition(x, y, ...) holds"}),'" via ',(0,t.jsx)(r.code,{children:"fc.pre"})," or ",(0,t.jsx)(r.code,{children:".filter"})]}),"\n",(0,t.jsxs)(r.li,{children:['"',(0,t.jsx)(r.em,{children:"predicate(x, y, ...) is true"}),'" via the predicate']}),"\n"]})]}),"\n",(0,t.jsx)(r.h2,{id:"synchronous-properties",children:"Synchronous properties"}),"\n",(0,t.jsx)(r.h3,{id:"basic",children:"Basic"}),"\n",(0,t.jsxs)(r.p,{children:["Synchronous properties define synchronous predicates. They can be declared by calling ",(0,t.jsx)(r.code,{children:"fc.property(...arbitraries, predicate)"}),"."]}),"\n",(0,t.jsx)(r.p,{children:"The syntax is the following:"}),"\n",(0,t.jsx)(r.pre,{children:(0,t.jsx)(r.code,{className:"language-js",children:"fc.property(...arbitraries, (...args) => {});\n"})}),"\n",(0,t.jsx)(r.p,{children:"When passing N arbitraries, the predicate will receive N arguments: first argument being produced by the first arbitrary, second argument by the second arbitrary..."}),"\n",(0,t.jsx)(r.p,{children:"The predicate can:"}),"\n",(0,t.jsxs)(r.ul,{children:["\n",(0,t.jsxs)(r.li,{children:["either throw in case of failure by relying on ",(0,t.jsx)(r.code,{children:"assert"}),", ",(0,t.jsx)(r.code,{children:"expect"})," or even directly throwing,"]}),"\n",(0,t.jsxs)(r.li,{children:["or return ",(0,t.jsx)(r.code,{children:"true"})," or ",(0,t.jsx)(r.code,{children:"undefined"})," for success and ",(0,t.jsx)(r.code,{children:"false"})," for failure."]}),"\n"]}),"\n",(0,t.jsx)(r.admonition,{title:"Beware of side effects",type:"warning",children:(0,t.jsx)(r.p,{children:"The predicate function should 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."})}),"\n",(0,t.jsx)(r.h3,{id:"advanced",children:"Advanced"}),"\n",(0,t.jsx)(r.admonition,{title:"Deprecated",type:"warning",children:(0,t.jsxs)(r.p,{children:["The ",(0,t.jsx)(r.code,{children:"beforeEach"})," and ",(0,t.jsx)(r.code,{children:"afterEach"})," methods are deprecated. Prefer the ",(0,t.jsx)(r.a,{href:"/docs/core-blocks/plugins/life-cycle/",children:"life-cycle plugins"}),": ",(0,t.jsx)(r.code,{children:"fc.assert(property, { plugins: [fc.beforeEach(fn), fc.afterEach(fn)] })"}),"."]})}),"\n",(0,t.jsx)(r.p,{children:"The built-in property comes with two methods that can be leveraged whenever you need to run setup or teardown steps."}),"\n",(0,t.jsx)(r.pre,{children:(0,t.jsx)(r.code,{className:"language-js",children:"fc.property(...arbitraries, (...args) => {})\n  .beforeEach((previousBeforeEach) => {})\n  .afterEach((previousAfterEach) => {});\n"})}),"\n",(0,t.jsx)(r.p,{children:"They both only accept synchronous functions and give the user the ability to call the previously defined hook function if any. The before-each (respectively: after-each) function will be launched before (respectively: after) each execution of the predicate."}),"\n",(0,t.jsx)(r.admonition,{title:"Independent",type:"info",children:(0,t.jsxs)(r.p,{children:["No need to define both. You may only call ",(0,t.jsx)(r.code,{children:"beforeEach"})," or ",(0,t.jsx)(r.code,{children:"afterEach"})," without the other."]}
1)}),"\n",(0,t.jsx)(r.admonition,{title:"Share them",type:"tip",children:(0,t.jsxs)(r.p,{children:["Consider using ",(0,t.jsx)(r.code,{children:"fc.installGlobalPlugin(fc.beforeEach(fn))"})," to share your hooks across multiple properties."]})}),"\n",(0,t.jsx)(r.h3,{id:"example",children:"Example"}),"\n",(0,t.jsxs)(r.p,{children:["Let's imagine we have a function called ",(0,t.jsx)(r.code,{children:"crop"})," taking a string and the maximal length we accept. We can write the following property:"]}),"\n",(0,t.jsx)(r.pre,{children:(0,t.jsx)(r.code,{className:"language-js",children:"fc.property(fc.nat(), fc.string(), (maxLength, label) => {\n  fc.pre(label.length <= maxLength); // any label such label.length > maxLength, will be dropped\n  return crop(label, maxLength) === label; // true is success, false is failure\n});\n"})}),"\n",(0,t.jsxs)(r.p,{children:["The property defined above is relying on ",(0,t.jsx)(r.code,{children:"fc.pre"})," to filter out invalid entries and is returning boolean values to indicate failures."]}),"\n",(0,t.jsxs)(r.p,{children:["It can also be written with ",(0,t.jsx)(r.code,{children:".filter"})," and ",(0,t.jsx)(r.code,{children:"expect"}),":"]}),"\n",(0,t.jsx)(r.pre,{children:(0,t.jsx)(r.code,{className:"language-js",children:"fc.property(\n  fc\n    .record({\n      maxLength: fc.nat(),\n      label: fc.string(),\n    })\n    .filter(({ maxLength, label }) => label.length <= maxLength),\n  ({ maxLength, label }) => {\n    expect(crop(label, maxLength)).toBe(label);\n  },\n);\n"})}),"\n",(0,t.jsxs)(r.admonition,{title:"Filtering and performance",type:"info",children:[(0,t.jsxs)(r.p,{children:["Whatever the filtering solution you chose between ",(0,t.jsx)(r.code,{children:"fc.pre"})," or ",(0,t.jsx)(r.code,{children:".filter"}),", they both consist into generating values and then dropping them. When filter is too strict it means that plenty of values could be rejected for only a few kept."]}),(0,t.jsxs)(r.p,{children:["As a consequence, whenever feasible it's recommended to prefer relying on options directly providing by the arbitraries rather than filtering them. For instance, if you want to generate strings having at least two characters you should prefer ",(0,t.jsx)(r.code,{children:"fc.string({ minLength: 2 })"})," over ",(0,t.jsx)(r.code,{children:"fc.string().filter(s => s.length >= 2)"}),"."]})]}),"\n",(0,t.jsx)(r.h2,{id:"asynchronous-properties",children:"Asynchronous properties"}),"\n",(0,t.jsx)(r.h3,{id:"basic-1",children:"Basic"}),"\n",(0,t.jsxs)(r.p,{children:["Similarly to their synchronous counterpart, aynchronous properties define asynchronous predicates. They can be declared by calling ",(0,t.jsx)(r.code,{children:"fc.asyncProperty(...arbitraries, asyncPredicate)"}),"."]}),"\n",(0,t.jsx)(r.p,{children:"The syntax is the following:"}),"\n",(0,t.jsx)(r.pre,{children:(0,t.jsx)(r.code,{className:"language-js",children:"fc.asyncProperty(...arbitraries, async (...args) => {});\n"})}),"\n",(0,t.jsx)(r.h3,{id:"advanced-1",children:"Advanced"}),"\n",(0,t.jsx)(r.admonition,{title:"Deprecated",type:"warning",children:(0,t.jsxs)(r.p,{children:["The ",(0,t.jsx)(r.code,{children:"beforeEach"})," and ",(0,t.jsx)(r.code,{children:"afterEach"})," methods are deprecated. Prefer the ",(0,t.jsx)(r.a,{href:"/docs/core-blocks/plugins/life-cycle/",children:"life-cycle plugins"}),": ",(0,t.jsx)(r.code,{children:"fc.assert(property, { plugins: [fc.beforeEach(fn), fc.afterEach(fn)] })"}),"."]})}),"\n",(0,t.jsxs)(r.p,{children:["They also accept ",(0,t.jsx)(r.code,{children:"beforeEach"})," and ",(0,t.jsx)(r.code,{children:"afterEach"})," functions to be provided: the passed functions can either be synchronous or asynchronous."]}),"\n",(0,t.jsx)(r.admonition,{title:"Lifecycle",type:"info",children:(0,t.jsxs)(r.p,{children:["The ",(0,t.jsx)(r.code,{children:"beforeEach"})," and ",(0,t.jsx)(r.code,{children:"afterEach"})," functions will always be executed, regardless of whether the property times out. It's important to note that the ",(0,t.jsx)(r.code,{children:"timeout"})," option passed to ",(0,t.jsx)(r.code,{children:"fc.assert"})," only measures the time taken by the actual property test, not the setup and teardown phases."]})})]})}function h(e={}){let{wrapper:r}={...(0,s.R)(),...e.components};return r?(0,t.jsx)(r,{...e,children:(0,t.jsx)(d,{...e})}):d(e)}},24801(e,r,n){n.d(r,{R:()=>c,x:()=>o});var i=n(13706);let t={},s=i.createContext(t);function c(e){let r=i.useContext(s);return i.useMemo(function(){return"function"==typeof e?e(r):{...r,...e}},[r,e])}function o(e){let r;return r=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:c(e.components),i.createElement(s.Provider,{value:r},e.children)}}}]);

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.