@fast-check/jest
Advanced tools
Comparing version 1.3.2 to 1.4.0
@@ -1,13 +0,37 @@ | ||
# 1.3.1 | ||
# 1.4.0 | ||
_Better typings for `{it,test}Prop`_ | ||
[[Code](https://github.com/dubzzz/fast-check/tree/jest%2Fv1.3.1)][[Diff](https://github.com/dubzzz/fast-check/compare/jest%2Fv1.3.0...jest%2Fv1.3.1)] | ||
_Introduce new `it.prop` and `test.prop` APIs_ | ||
[[Code](https://github.com/dubzzz/fast-check/tree/jest%2Fv1.4.0)][[Diff](https://github.com/dubzzz/fast-check/compare/jest%2Fv1.3.1...jest%2Fv1.4.0)] | ||
## Features | ||
- ([PR#3349](https://github.com/dubzzz/fast-check/pull/3349)) Wrongly typed `itProp` when receiving `examples` | ||
- ([PR#3339](https://github.com/dubzzz/fast-check/pull/3339)) Add new `it.prop` and related | ||
- ([PR#3366](https://github.com/dubzzz/fast-check/pull/3366)) Add support for record-based `it.prop` | ||
## Fixes | ||
- ([PR#3383](https://github.com/dubzzz/fast-check/pull/3383)) Bug: Fix types not being properly exported for ESM | ||
- ([PR#3352](https://github.com/dubzzz/fast-check/pull/3352)) Doc: Add missing 'Typing' on PRs in changelog | ||
- ([PR#3389](https://github.com/dubzzz/fast-check/pull/3389)) Doc: Adapt documentation for new API based on `it`/`test` | ||
--- | ||
# 1.3.2 | ||
_Properly define types for TypeScript_ | ||
[[Code](https://github.com/dubzzz/fast-check/tree/jest%2Fv1.3.2)][[Diff](https://github.com/dubzzz/fast-check/compare/jest%2Fv1.3.1...jest%2Fv1.3.2)] | ||
## Fixes | ||
- ([PR#3383](https://github.com/dubzzz/fast-check/pull/3383)) Bug: Fix types not being properly exported for ESM | ||
# 1.3.1 | ||
_Better typings for `{it,test}Prop`_ | ||
[[Code](https://github.com/dubzzz/fast-check/tree/jest%2Fv1.3.1)][[Diff](https://github.com/dubzzz/fast-check/compare/jest%2Fv1.3.0...jest%2Fv1.3.1)] | ||
## Fixes | ||
- ([PR#3345](https://github.com/dubzzz/fast-check/pull/3345)) Doc: Fix dead link in readme | ||
- ([PR#3349](https://github.com/dubzzz/fast-check/pull/3349)) Typing: Wrongly typed `itProp` when receiving `examples` | ||
@@ -31,2 +55,20 @@ # 1.3.0 | ||
# 1.2.2 | ||
_Properly define types for TypeScript_ | ||
[[Code](https://github.com/dubzzz/fast-check/tree/jest%2Fv1.2.2)][[Diff](https://github.com/dubzzz/fast-check/compare/jest%2Fv1.2.1...jest%2Fv1.2.2)] | ||
## Fixes | ||
- ([PR#3383](https://github.com/dubzzz/fast-check/pull/3383)) Bug: Fix types not being properly exported for ESM | ||
# 1.2.1 | ||
_Better typings for `{it,test}Prop`_ | ||
[[Code](https://github.com/dubzzz/fast-check/tree/jest%2Fv1.2.1)][[Diff](https://github.com/dubzzz/fast-check/compare/jest%2Fv1.2.0...jest%2Fv1.2.1)] | ||
## Fixes | ||
- ([PR#3349](https://github.com/dubzzz/fast-check/pull/3349)) Typing: Wrongly typed `itProp` when receiving `examples` | ||
# 1.2.0 | ||
@@ -50,2 +92,22 @@ | ||
# 1.1.2 | ||
_Properly define types for TypeScript_ | ||
[[Code](https://github.com/dubzzz/fast-check/tree/jest%2Fv1.1.2)][[Diff](https://github.com/dubzzz/fast-check/compare/jest%2Fv1.1.1...jest%2Fv1.1.2)] | ||
## Fixes | ||
- ([PR#3383](https://github.com/dubzzz/fast-check/pull/3383)) Bug: Fix types not being properly exported for ESM | ||
# 1.1.1 | ||
_Various fixes_ | ||
[[Code](https://github.com/dubzzz/fast-check/tree/jest%2Fv1.1.1)][[Diff](https://github.com/dubzzz/fast-check/compare/jest%2Fv1.1.0...jest%2Fv1.1.1)] | ||
## Fixes | ||
- ([PR#3279](https://github.com/dubzzz/fast-check/pull/3279)) Bug: Pass the forged seed to the runner | ||
- ([PR#3281](https://github.com/dubzzz/fast-check/pull/3281)) Bug: Fallback on the seed coming from globals if any | ||
- ([PR#3349](https://github.com/dubzzz/fast-check/pull/3349)) Typing: Wrongly typed `itProp` when receiving `examples` | ||
# 1.1.0 | ||
@@ -70,2 +132,22 @@ | ||
# 1.0.3 | ||
_Properly define types for TypeScript_ | ||
[[Code](https://github.com/dubzzz/fast-check/tree/jest%2Fv1.0.3)][[Diff](https://github.com/dubzzz/fast-check/compare/jest%2Fv1.0.2...jest%2Fv1.0.3)] | ||
## Fixes | ||
- ([PR#3383](https://github.com/dubzzz/fast-check/pull/3383)) Bug: Fix types not being properly exported for ESM | ||
# 1.0.2 | ||
_Various fixes_ | ||
[[Code](https://github.com/dubzzz/fast-check/tree/jest%2Fv1.0.2)][[Diff](https://github.com/dubzzz/fast-check/compare/jest%2Fv1.0.1...jest%2Fv1.0.2)] | ||
## Fixes | ||
- ([PR#3279](https://github.com/dubzzz/fast-check/pull/3279)) Bug: Pass the forged seed to the runner | ||
- ([PR#3281](https://github.com/dubzzz/fast-check/pull/3281)) Bug: Fallback on the seed coming from globals if any | ||
- ([PR#3349](https://github.com/dubzzz/fast-check/pull/3349)) Typing: Wrongly typed `itProp` when receiving `examples` | ||
# 1.0.1 | ||
@@ -72,0 +154,0 @@ |
@@ -1,2 +0,2 @@ | ||
import { it, test, jest } from '@jest/globals'; | ||
import { it as itJest, test as testJest, jest } from '@jest/globals'; | ||
import * as fc from 'fast-check'; | ||
@@ -6,3 +6,3 @@ function wrapProp(prop) { | ||
} | ||
function internalTestPropExecute(testFn, label, arbitraries, prop, params) { | ||
function internalTestPropExecute(testFn, label, arbitraries, prop, params, timeout) { | ||
const customParams = Object.assign({}, params); | ||
@@ -27,7 +27,7 @@ if (customParams.seed === undefined) { | ||
await fc.assert(fc.asyncProperty(...arbitraries, promiseProp), customParams); | ||
}); | ||
}, timeout); | ||
} | ||
function internalTestPropFailing(testFn) { | ||
function base(label, arbitraries, prop, params) { | ||
internalTestPropExecute(testFn, label, arbitraries, prop, params); | ||
internalTestPropExecute(testFn, label, arbitraries, prop, params, undefined); | ||
} | ||
@@ -39,3 +39,3 @@ const extras = {}; | ||
function base(label, arbitraries, prop, params) { | ||
internalTestPropExecute(testFn, label, arbitraries, prop, params); | ||
internalTestPropExecute(testFn, label, arbitraries, prop, params, undefined); | ||
} | ||
@@ -49,3 +49,3 @@ const extras = { | ||
function base(label, arbitraries, prop, params) { | ||
internalTestPropExecute(testFn, label, arbitraries, prop, params); | ||
internalTestPropExecute(testFn, label, arbitraries, prop, params, undefined); | ||
} | ||
@@ -67,4 +67,53 @@ const extras = { | ||
} | ||
export const testProp = internalTestProp(test); | ||
export const itProp = internalTestProp(it); | ||
function adaptParametersForRecord(parameters, originalParamaters) { | ||
return Object.assign(Object.assign({}, parameters), { examples: parameters.examples !== undefined ? parameters.examples.map((example) => example[0]) : undefined, reporter: originalParamaters.reporter, asyncReporter: originalParamaters.asyncReporter }); | ||
} | ||
function adaptExecutionTreeForRecord(executionSummary) { | ||
return executionSummary.map((summary) => (Object.assign(Object.assign({}, summary), { value: summary.value[0], children: adaptExecutionTreeForRecord(summary.children) }))); | ||
} | ||
function adaptRunDetailsForRecord(runDetails, originalParamaters) { | ||
const adaptedRunDetailsCommon = Object.assign(Object.assign({}, runDetails), { counterexample: runDetails.counterexample !== null ? runDetails.counterexample[0] : null, failures: runDetails.failures.map((failure) => failure[0]), executionSummary: adaptExecutionTreeForRecord(runDetails.executionSummary), runConfiguration: adaptParametersForRecord(runDetails.runConfiguration, originalParamaters) }); | ||
return adaptedRunDetailsCommon; | ||
} | ||
function buildTestProp(testFn) { | ||
return (arbitraries, params) => { | ||
if (Array.isArray(arbitraries)) { | ||
return (testName, prop, timeout) => internalTestPropExecute(testFn, testName, arbitraries, prop, params, timeout); | ||
} | ||
return (testName, prop, timeout) => { | ||
const recordArb = fc.record(arbitraries); | ||
const recordParams = params !== undefined | ||
? Object.assign(Object.assign({}, params), { examples: params.examples !== undefined ? params.examples.map((example) => [example]) : undefined, reporter: params.reporter !== undefined | ||
? | ||
(runDetails) => params.reporter(adaptRunDetailsForRecord(runDetails, params)) | ||
: undefined, asyncReporter: params.asyncReporter !== undefined | ||
? | ||
(runDetails) => params.asyncReporter(adaptRunDetailsForRecord(runDetails, params)) | ||
: undefined }) : undefined; | ||
internalTestPropExecute(testFn, testName, [recordArb], (value) => prop(value), recordParams, timeout); | ||
}; | ||
}; | ||
} | ||
function enrichWithTestProp(testFn) { | ||
let atLeastOneExtra = false; | ||
const extraKeys = {}; | ||
for (const key in testFn) { | ||
if (typeof testFn[key] === 'function') { | ||
atLeastOneExtra = true; | ||
extraKeys[key] = key !== 'each' ? enrichWithTestProp(testFn[key]) : testFn[key]; | ||
} | ||
} | ||
if (!atLeastOneExtra) { | ||
return testFn; | ||
} | ||
const enrichedTestFn = (...args) => testFn(...args); | ||
if ('each' in testFn) { | ||
extraKeys['prop'] = buildTestProp(testFn); | ||
} | ||
return Object.assign(enrichedTestFn, extraKeys); | ||
} | ||
export const test = enrichWithTestProp(testJest); | ||
export const it = enrichWithTestProp(itJest); | ||
export const testProp = internalTestProp(testJest); | ||
export const itProp = internalTestProp(itJest); | ||
export { fc }; |
@@ -0,6 +1,27 @@ | ||
import { it as itJest } from '@jest/globals'; | ||
import * as fc from 'fast-check'; | ||
declare type It = typeof itJest; | ||
declare type ArbitraryTuple<Ts extends [any] | any[]> = { | ||
[P in keyof Ts]: fc.Arbitrary<Ts[P]>; | ||
}; | ||
declare type ArbitraryRecord<Ts> = { | ||
[P in keyof Ts]: fc.Arbitrary<Ts[P]>; | ||
}; | ||
declare type Prop<Ts extends [any] | any[]> = (...args: Ts) => boolean | void | PromiseLike<boolean | void>; | ||
declare type PropRecord<Ts> = (arg: Ts) => boolean | void | PromiseLike<boolean | void>; | ||
/** | ||
* prop has just been declared for typing reasons, ideally TestProp should be enough | ||
* and should be used to replace `{ prop: typeof prop }` by `{ prop: TestProp<???> }` | ||
*/ | ||
declare const prop: <Ts, TsParameters extends Ts = Ts>(arbitraries: Ts extends [any] | any[] ? ArbitraryTuple<Ts> : ArbitraryRecord<Ts>, params?: fc.Parameters<TsParameters>) => (testName: string, prop: Ts extends [any] | any[] ? Prop<Ts> : PropRecord<Ts>, timeout?: number | undefined) => void; | ||
/** | ||
* Revamped {it,test} with added `.prop` | ||
*/ | ||
declare type FastCheckItBuilder<T> = T & ('each' extends keyof T ? T & { | ||
prop: typeof prop; | ||
} : T) & { | ||
[K in keyof Omit<T, 'each'>]: FastCheckItBuilder<T[K]>; | ||
}; | ||
export declare const test: FastCheckItBuilder<It>; | ||
export declare const it: FastCheckItBuilder<It>; | ||
export declare const testProp: (<Ts extends any[] | [any], TsParameters extends Ts = Ts>(label: string, arbitraries: ArbitraryTuple<Ts>, prop: Prop<Ts>, params?: fc.Parameters<TsParameters> | undefined) => void) & { | ||
@@ -7,0 +28,0 @@ only: (<Ts_1 extends any[] | [any], TsParameters_1 extends Ts_1 = Ts_1>(label: string, arbitraries: ArbitraryTuple<Ts_1>, prop: Prop<Ts_1>, params?: fc.Parameters<TsParameters_1> | undefined) => void) & { |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.fc = exports.itProp = exports.testProp = void 0; | ||
exports.fc = exports.itProp = exports.testProp = exports.it = exports.test = void 0; | ||
const globals_1 = require("@jest/globals"); | ||
@@ -10,3 +10,3 @@ const fc = require("fast-check"); | ||
} | ||
function internalTestPropExecute(testFn, label, arbitraries, prop, params) { | ||
function internalTestPropExecute(testFn, label, arbitraries, prop, params, timeout) { | ||
const customParams = Object.assign({}, params); | ||
@@ -31,7 +31,7 @@ if (customParams.seed === undefined) { | ||
await fc.assert(fc.asyncProperty(...arbitraries, promiseProp), customParams); | ||
}); | ||
}, timeout); | ||
} | ||
function internalTestPropFailing(testFn) { | ||
function base(label, arbitraries, prop, params) { | ||
internalTestPropExecute(testFn, label, arbitraries, prop, params); | ||
internalTestPropExecute(testFn, label, arbitraries, prop, params, undefined); | ||
} | ||
@@ -43,3 +43,3 @@ const extras = {}; | ||
function base(label, arbitraries, prop, params) { | ||
internalTestPropExecute(testFn, label, arbitraries, prop, params); | ||
internalTestPropExecute(testFn, label, arbitraries, prop, params, undefined); | ||
} | ||
@@ -53,3 +53,3 @@ const extras = { | ||
function base(label, arbitraries, prop, params) { | ||
internalTestPropExecute(testFn, label, arbitraries, prop, params); | ||
internalTestPropExecute(testFn, label, arbitraries, prop, params, undefined); | ||
} | ||
@@ -71,3 +71,52 @@ const extras = { | ||
} | ||
function adaptParametersForRecord(parameters, originalParamaters) { | ||
return Object.assign(Object.assign({}, parameters), { examples: parameters.examples !== undefined ? parameters.examples.map((example) => example[0]) : undefined, reporter: originalParamaters.reporter, asyncReporter: originalParamaters.asyncReporter }); | ||
} | ||
function adaptExecutionTreeForRecord(executionSummary) { | ||
return executionSummary.map((summary) => (Object.assign(Object.assign({}, summary), { value: summary.value[0], children: adaptExecutionTreeForRecord(summary.children) }))); | ||
} | ||
function adaptRunDetailsForRecord(runDetails, originalParamaters) { | ||
const adaptedRunDetailsCommon = Object.assign(Object.assign({}, runDetails), { counterexample: runDetails.counterexample !== null ? runDetails.counterexample[0] : null, failures: runDetails.failures.map((failure) => failure[0]), executionSummary: adaptExecutionTreeForRecord(runDetails.executionSummary), runConfiguration: adaptParametersForRecord(runDetails.runConfiguration, originalParamaters) }); | ||
return adaptedRunDetailsCommon; | ||
} | ||
function buildTestProp(testFn) { | ||
return (arbitraries, params) => { | ||
if (Array.isArray(arbitraries)) { | ||
return (testName, prop, timeout) => internalTestPropExecute(testFn, testName, arbitraries, prop, params, timeout); | ||
} | ||
return (testName, prop, timeout) => { | ||
const recordArb = fc.record(arbitraries); | ||
const recordParams = params !== undefined | ||
? Object.assign(Object.assign({}, params), { examples: params.examples !== undefined ? params.examples.map((example) => [example]) : undefined, reporter: params.reporter !== undefined | ||
? | ||
(runDetails) => params.reporter(adaptRunDetailsForRecord(runDetails, params)) | ||
: undefined, asyncReporter: params.asyncReporter !== undefined | ||
? | ||
(runDetails) => params.asyncReporter(adaptRunDetailsForRecord(runDetails, params)) | ||
: undefined }) : undefined; | ||
internalTestPropExecute(testFn, testName, [recordArb], (value) => prop(value), recordParams, timeout); | ||
}; | ||
}; | ||
} | ||
function enrichWithTestProp(testFn) { | ||
let atLeastOneExtra = false; | ||
const extraKeys = {}; | ||
for (const key in testFn) { | ||
if (typeof testFn[key] === 'function') { | ||
atLeastOneExtra = true; | ||
extraKeys[key] = key !== 'each' ? enrichWithTestProp(testFn[key]) : testFn[key]; | ||
} | ||
} | ||
if (!atLeastOneExtra) { | ||
return testFn; | ||
} | ||
const enrichedTestFn = (...args) => testFn(...args); | ||
if ('each' in testFn) { | ||
extraKeys['prop'] = buildTestProp(testFn); | ||
} | ||
return Object.assign(enrichedTestFn, extraKeys); | ||
} | ||
exports.test = enrichWithTestProp(globals_1.test); | ||
exports.it = enrichWithTestProp(globals_1.it); | ||
exports.testProp = internalTestProp(globals_1.test); | ||
exports.itProp = internalTestProp(globals_1.it); |
{ | ||
"name": "@fast-check/jest", | ||
"description": "Property based testing for Jest based on fast-check", | ||
"version": "1.3.2", | ||
"version": "1.4.0", | ||
"type": "commonjs", | ||
@@ -51,6 +51,6 @@ "main": "lib/jest-fast-check.js", | ||
"devDependencies": { | ||
"@jest/globals": "^29.2.1", | ||
"@types/node": "^17.0.44", | ||
"@jest/globals": "^29.2.2", | ||
"@types/node": "^18.11.9", | ||
"fast-check": "3.3.0", | ||
"jest": "^29.2.1", | ||
"jest": "^29.2.2", | ||
"ts-jest": "^29.0.3", | ||
@@ -57,0 +57,0 @@ "typescript": "^4.8.4" |
@@ -33,37 +33,44 @@ # `@fast-check/jest` | ||
```javascript | ||
import { testProp, fc } from '@fast-check/jest'; | ||
import { test, fc } from '@fast-check/jest'; | ||
// for all a, b, c strings | ||
// b is a substring of a + b + c | ||
testProp('should detect the substring', [fc.string(), fc.string(), fc.string()], (a, b, c) => { | ||
test.prop([fc.string(), fc.string(), fc.string()])('should detect the substring', (a, b, c) => { | ||
return (a + b + c).includes(b); | ||
}); | ||
// Or the exact same test but based on named parameters | ||
test.prop({ a: fc.string(), b: fc.string(), c: fc.string() })('should detect the substring', ({ a, b, c }) => { | ||
return (a + b + c).includes(b); | ||
}); | ||
``` | ||
Please note that the properties accepted by `@fast-check/jest` as input can either be synchronous or asynchronous (even just `PromiseLike` instances). | ||
The `it` and `test` functions returned by `@fast-check/jest` are just enriched versions of the ones coming from `jest` itself. They both come with `.prop`. | ||
Please note that the properties accepted by `@fast-check/jest` as input can either be synchronous or asynchronous (even just `PromiseLike` instances). In other words, the predicate passed as the last argument can be asynchronous. | ||
**Remark:** `it` and `test` have been introduced in 1.4.0. You have to refer to [Deprecated API](#deprecated-api) if you are using a version of `@fast-check/jest` <1.4.0. | ||
## Advanced | ||
If you want to forward custom parameters to fast-check, `testProp` accepts an optional `fc.Parameters` ([more](https://github.com/dubzzz/fast-check/blob/main/packages/fast-check/documentation/Runners.md#runners)). | ||
If you want to forward custom parameters to `fast-check`, `test.prop` and its variants accept an optional `fc.Parameters` ([more](https://github.com/dubzzz/fast-check/blob/main/packages/fast-check/documentation/Runners.md#runners)). | ||
`@fast-check/jest` also comes with `.only`, `.skip`, `.todo` and `.concurrent` from jest. It also accepts more complex ones such as `.concurrent.failing` or `.concurrent.only.failing`. | ||
`@fast-check/jest` also comes with support for `.only`, `.skip`, `.todo` and `.concurrent` from `jest`. It also accepts more complex ones such as `.concurrent.failing` or `.concurrent.only.failing`. | ||
```javascript | ||
import { itProp, testProp, fc } from '@fast-check/jest'; | ||
import { it, test, fc } from '@fast-check/jest'; | ||
testProp( | ||
'should replay the test for the seed 4242', | ||
[fc.nat(), fc.nat()], | ||
(a, b) => { | ||
return a + b === b + a; | ||
}, | ||
{ seed: 4242 } | ||
); | ||
// With custom `fc.Parameters`, here { seed: 4242 } | ||
test.prop([fc.nat(), fc.nat()], { seed: 4242 })('should replay the test for the seed 4242', (a, b) => { | ||
return a + b === b + a; | ||
}); | ||
testProp.skip('should be skipped', [fc.fullUnicodeString()], (text) => { | ||
// With .skip | ||
test.skip.prop([fc.fullUnicodeString()])('should be skipped', (text) => { | ||
return text.length === [...text].length; | ||
}); | ||
// With it version | ||
describe('with it', () => { | ||
itProp('should run too', [fc.nat(), fc.nat()], (a, b) => { | ||
it.prop([fc.nat(), fc.nat()])('should run too', (a, b) => { | ||
return a + b === b + a; | ||
@@ -74,2 +81,16 @@ }); | ||
## Deprecated API | ||
Our old API was not as close from `jest` as the current one is. Writing a property was done via: | ||
```ts | ||
import { testProp, fc } from '@fast-check/jest'; | ||
testProp('should detect the substring', [fc.string(), fc.string(), fc.string()], (a, b, c) => { | ||
return (a + b + c).includes(b); | ||
}); | ||
``` | ||
This API is available in all 1.x versions but may not exist anymore starting at 2.x. | ||
## Minimal requirements | ||
@@ -76,0 +97,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
31806
301
102