Skip to content

Commit

Permalink
Add fuzzing based tests in Jest (retry PR8012) (#8164)
Browse files Browse the repository at this point in the history
  • Loading branch information
dubzzz authored and SimenB committed Apr 2, 2019
1 parent 2bc6280 commit 9c5c449
Show file tree
Hide file tree
Showing 8 changed files with 239 additions and 0 deletions.
1 change: 1 addition & 0 deletions jest.config.js
Expand Up @@ -31,6 +31,7 @@ module.exports = {
],
testEnvironment: './packages/jest-environment-node',
testPathIgnorePatterns: [
'/__arbitraries__/',
'/node_modules/',
'/examples/',
'/e2e/.*/__tests__',
Expand Down
1 change: 1 addition & 0 deletions package.json
Expand Up @@ -39,6 +39,7 @@
"eslint-plugin-react": "^7.1.0",
"eslint-plugin-relay": "~0.0.19",
"execa": "^1.0.0",
"fast-check": "^1.13.0",
"glob": "^7.1.1",
"graceful-fs": "^4.1.15",
"isbinaryfile": "^4.0.0",
Expand Down
24 changes: 24 additions & 0 deletions packages/expect/src/__tests__/__arbitraries__/sharedSettings.ts
@@ -0,0 +1,24 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/

import fc from 'fast-check';

// settings for anything arbitrary
export const anythingSettings = {
key: fc.oneof(fc.string(), fc.constantFrom('k1', 'k2', 'k3')),
maxDepth: 2, // Limit object depth (default: 2)
maxKeys: 5, // Limit number of keys per object (default: 5)
withBoxedValues: true,
// Issue #7975 have to be fixed before enabling the generation of Map
withMap: false,
// Issue #7975 have to be fixed before enabling the generation of Set
withSet: false,
};

// assertion settings
export const assertSettings = {}; // eg.: {numRuns: 10000}
48 changes: 48 additions & 0 deletions packages/expect/src/__tests__/matchers-toContain.property.test.ts
@@ -0,0 +1,48 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/

import fc from 'fast-check';
import {
anythingSettings,
assertSettings,
} from './__arbitraries__/sharedSettings';

describe('toContain', () => {
it('should always find the value when inside the array', () => {
fc.assert(
fc.property(
fc.array(fc.anything(anythingSettings)),
fc.array(fc.anything(anythingSettings)),
fc.anything(anythingSettings).filter(v => !Number.isNaN(v)),
(startValues, endValues, v) => {
// Given: startValues, endValues arrays and v value (not NaN)
expect([...startValues, v, ...endValues]).toContain(v);
},
),
assertSettings,
);
});

it('should not find the value if it has been cloned into the array', () => {
fc.assert(
fc.property(
fc.array(fc.anything(anythingSettings)),
fc.array(fc.anything(anythingSettings)),
fc.dedup(fc.anything(anythingSettings), 2),
(startValues, endValues, [a, b]) => {
// Given: startValues, endValues arrays
// and [a, b] equal, but not the same values
// with `typeof a === 'object && a !== null`
fc.pre(typeof a === 'object' && a !== null);
expect([...startValues, a, ...endValues]).not.toContain(b);
},
),
assertSettings,
);
});
});
@@ -0,0 +1,46 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/

import fc from 'fast-check';
import {
anythingSettings,
assertSettings,
} from './__arbitraries__/sharedSettings';

describe('toContainEqual', () => {
it('should always find the value when inside the array', () => {
fc.assert(
fc.property(
fc.array(fc.anything(anythingSettings)),
fc.array(fc.anything(anythingSettings)),
fc.anything(anythingSettings),
(startValues, endValues, v) => {
// Given: startValues, endValues arrays and v any value
expect([...startValues, v, ...endValues]).toContainEqual(v);
},
),
assertSettings,
);
});

it('should always find the value when cloned inside the array', () => {
fc.assert(
fc.property(
fc.array(fc.anything(anythingSettings)),
fc.array(fc.anything(anythingSettings)),
fc.dedup(fc.anything(anythingSettings), 2),
(startValues, endValues, [a, b]) => {
// Given: startValues, endValues arrays
// and [a, b] identical values
expect([...startValues, a, ...endValues]).toContainEqual(b);
},
),
assertSettings,
);
});
});
58 changes: 58 additions & 0 deletions packages/expect/src/__tests__/matchers-toEqual.property.test.ts
@@ -0,0 +1,58 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/

import fc from 'fast-check';
import {
anythingSettings,
assertSettings,
} from './__arbitraries__/sharedSettings';

describe('toEqual', () => {
it('should be reflexive', () => {
fc.assert(
fc.property(fc.dedup(fc.anything(anythingSettings), 2), ([a, b]) => {
// Given: a and b identical values
expect(a).toEqual(b);
}),
assertSettings,
);
});

it('should be symmetric', () => {
const safeExpectEqual = (a, b) => {
try {
expect(a).toEqual(b);
return true;
} catch (err) {
return false;
}
};
fc.assert(
fc.property(
fc.anything(anythingSettings),
fc.anything(anythingSettings),
(a, b) => {
// Given: a and b values
// Assert: We expect `expect(a).toEqual(b)`
// to be equivalent to `expect(b).toEqual(a)`
expect(safeExpectEqual(a, b)).toBe(safeExpectEqual(b, a));
},
),
{
...assertSettings,
examples: [
[0, 5e-324], // Issue #7941
// [
// new Set([false, true]),
// new Set([new Boolean(true), new Boolean(true)]),
// ], // Issue #7975
],
},
);
});
});
@@ -0,0 +1,49 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/

import fc from 'fast-check';
import {
anythingSettings,
assertSettings,
} from './__arbitraries__/sharedSettings';

describe('toStrictEqual', () => {
it('should be reflexive', () => {
fc.assert(
fc.property(fc.dedup(fc.anything(anythingSettings), 2), ([a, b]) => {
// Given: a and b identical values
expect(a).toStrictEqual(b);
}),
assertSettings,
);
});

it('should be symmetric', () => {
const safeExpectStrictEqual = (a, b) => {
try {
expect(a).toStrictEqual(b);
return true;
} catch (err) {
return false;
}
};
fc.assert(
fc.property(
fc.anything(anythingSettings),
fc.anything(anythingSettings),
(a, b) => {
// Given: a and b values
// Assert: We expect `expect(a).toStrictEqual(b)`
// to be equivalent to `expect(b).toStrictEqual(a)`
expect(safeExpectStrictEqual(a, b)).toBe(safeExpectStrictEqual(b, a));
},
),
assertSettings,
);
});
});
12 changes: 12 additions & 0 deletions yarn.lock
Expand Up @@ -5641,6 +5641,13 @@ fancy-log@^1.3.2:
parse-node-version "^1.0.0"
time-stamp "^1.0.0"

fast-check@^1.13.0:
version "1.13.0"
resolved "https://registry.yarnpkg.com/fast-check/-/fast-check-1.13.0.tgz#0f418efb7a8a1fc3f2371f9113b00c2605711e60"
integrity sha512-GlpwnO0mgNV5L5WqU6xGAURw9MMhePLCNfPXgG7hDyABl8obqCK03auKZArBPbybzuYFSKQ2wBMonnf1tbelkw==
dependencies:
pure-rand "^1.6.2"

fast-deep-equal@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49"
Expand Down Expand Up @@ -10694,6 +10701,11 @@ punycode@^2.1.0, punycode@^2.1.1:
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==

pure-rand@^1.6.2:
version "1.6.2"
resolved "https://registry.yarnpkg.com/pure-rand/-/pure-rand-1.6.2.tgz#90b3ae78efe36f7e6e27bfffedf934f77382e6e6"
integrity sha512-HNwHOH63m7kCxe0kWEe5jSLwJiL2N83RUUN8POniFuZS+OsbFcMWlvXgxIU2nwKy2zYG2bQan40WBNK4biYPRg==

q@0.9.7:
version "0.9.7"
resolved "https://registry.yarnpkg.com/q/-/q-0.9.7.tgz#4de2e6cb3b29088c9e4cbc03bf9d42fb96ce2f75"
Expand Down

0 comments on commit 9c5c449

Please sign in to comment.