diff --git a/.all-contributorsrc b/.all-contributorsrc
index a23adf00..a5a750a9 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -450,6 +450,17 @@
"contributions": [
"code"
]
+ },
+ {
+ "login": "danielpmichalski",
+ "name": "Daniel Michalski",
+ "avatar_url": "https://avatars2.githubusercontent.com/u/5457711?v=4",
+ "profile": "https://twitter.com/crazyPolishDan",
+ "contributions": [
+ "code",
+ "doc",
+ "test"
+ ]
}
],
"repoType": "github"
diff --git a/README.md b/README.md
index 44b8a5e9..1355078a 100644
--- a/README.md
+++ b/README.md
@@ -48,6 +48,7 @@ If you've come here to help contribute - Thanks! Take a look at the [contributin
- [Array](#array)
- [.toBeArray()](#tobearray)
- [.toBeArrayOfSize()](#tobearrayofsize)
+ - [.toBeArrayWithFloats([members], ?precision)](#tobearraywithfloatsmembers-precision)
- [.toIncludeAllMembers([members])](#toincludeallmembersmembers)
- [.toIncludeAnyMembers([members])](#toincludeanymembersmembers)
- [.toIncludeSameMembers([members])](#toincludesamemembersmembers)
@@ -272,6 +273,17 @@ test('passes when value is an array', () => {
});
```
+#### .toBeArrayWithFloats([members], ?precision)
+
+Use `.toBeArrayWithFloats` when comparing arrays of floating-point numbers with chosen precision in the same order.
+
+```js
+test('passes when arrays have same floats', () => {
+ expect([1.11112, 2.22221]).toBeArrayWithFloats([1.11114, 2.22223]); // default 4-digit decimal precision
+ expect([1.112]).not.toBeArrayWithFloats([1.111], 3); // specified 3-digit decimal precision
+});
+```
+
#### .toIncludeAllMembers([members])
Use `.toIncludeAllMembers` when checking if an `Array` contains all of the same members of a given set.
@@ -927,7 +939,7 @@ test('passes when value includes all substrings', () => {
| [
Amish Shah](https://hydrabolt.me/)
[π»](https://github.com/mattphillips/jest-extended/commits?author=hydrabolt "Code") [β οΈ](https://github.com/mattphillips/jest-extended/commits?author=hydrabolt "Tests") | [
Dave Cooper](http://davecooper.org)
[π»](https://github.com/mattphillips/jest-extended/commits?author=grug "Code") [β οΈ](https://github.com/mattphillips/jest-extended/commits?author=grug "Tests") | [
Swann Polydor](https://github.com/soueuls)
[π»](https://github.com/mattphillips/jest-extended/commits?author=soueuls "Code") [β οΈ](https://github.com/mattphillips/jest-extended/commits?author=soueuls "Tests") | [
vikneshwar](https://github.com/vikneshwar)
[π»](https://github.com/mattphillips/jest-extended/commits?author=vikneshwar "Code") [β οΈ](https://github.com/mattphillips/jest-extended/commits?author=vikneshwar "Tests") | [
Budi Irawan](http://budiirawan.com)
[π»](https://github.com/mattphillips/jest-extended/commits?author=deerawan "Code") [β οΈ](https://github.com/mattphillips/jest-extended/commits?author=deerawan "Tests") | [
Tejas Bubane](http://foss-geek.blogspot.com/)
[π»](https://github.com/mattphillips/jest-extended/commits?author=tejasbubane "Code") [β οΈ](https://github.com/mattphillips/jest-extended/commits?author=tejasbubane "Tests") [π](https://github.com/mattphillips/jest-extended/commits?author=tejasbubane "Documentation") | [
Subinoy Ghosh](https://github.com/subinoy7)
[π»](https://github.com/mattphillips/jest-extended/commits?author=subinoy7 "Code") [β οΈ](https://github.com/mattphillips/jest-extended/commits?author=subinoy7 "Tests") |
| [
Simen Bekkhus](https://github.com/SimenB)
[π](https://github.com/mattphillips/jest-extended/commits?author=SimenB "Documentation") | [
Orta](http://orta.io)
[π](https://github.com/mattphillips/jest-extended/commits?author=orta "Documentation") | [
Tom](https://jsdevtom.com)
[π»](https://github.com/mattphillips/jest-extended/commits?author=jsdevtom "Code") [π](https://github.com/mattphillips/jest-extended/commits?author=jsdevtom "Documentation") [π‘](#example-jsdevtom "Examples") [β οΈ](https://github.com/mattphillips/jest-extended/commits?author=jsdevtom "Tests") | [
Lucian Buzzo](https://github.com/LucianBuzzo)
| [
Thiago Delgado Pinto](https://github.com/thiagodp)
[π»](https://github.com/mattphillips/jest-extended/commits?author=thiagodp "Code") [π](https://github.com/mattphillips/jest-extended/commits?author=thiagodp "Documentation") [π‘](#example-thiagodp "Examples") [π€](#ideas-thiagodp "Ideas, Planning, & Feedback") [β οΈ](https://github.com/mattphillips/jest-extended/commits?author=thiagodp "Tests") | [
Ragnar Laud](https://github.com/xprn)
[π»](https://github.com/mattphillips/jest-extended/commits?author=xprn "Code") [π](https://github.com/mattphillips/jest-extended/commits?author=xprn "Documentation") | [
Luiz AmΓ©rico](https://github.com/blikblum)
[π»](https://github.com/mattphillips/jest-extended/commits?author=blikblum "Code") |
| [
Frederick Fogerty](https://github.com/frederickfogerty)
[π»](https://github.com/mattphillips/jest-extended/commits?author=frederickfogerty "Code") [π€](#ideas-frederickfogerty "Ideas, Planning, & Feedback") | [
Benjamin Kay](https://github.com/benjaminkay93)
[π»](https://github.com/mattphillips/jest-extended/commits?author=benjaminkay93 "Code") [π](https://github.com/mattphillips/jest-extended/commits?author=benjaminkay93 "Documentation") | [
Gilles De Mey](https://demey.io)
[π»](https://github.com/mattphillips/jest-extended/commits?author=gillesdemey "Code") [π](https://github.com/mattphillips/jest-extended/commits?author=gillesdemey "Documentation") [β οΈ](https://github.com/mattphillips/jest-extended/commits?author=gillesdemey "Tests") | [
Deniz Dogan](https://github.com/denizdogan)
[π»](https://github.com/mattphillips/jest-extended/commits?author=denizdogan "Code") | [
Mikey Powers](https://github.com/mvpowers)
[π»](https://github.com/mattphillips/jest-extended/commits?author=mvpowers "Code") [π](https://github.com/mattphillips/jest-extended/commits?author=mvpowers "Documentation") [β οΈ](https://github.com/mattphillips/jest-extended/commits?author=mvpowers "Tests") | [
Tony Trinh](https://github.com/tony19)
[π»](https://github.com/mattphillips/jest-extended/commits?author=tony19 "Code") | [
Nikita Kurpas](https://github.com/NikitaKurpas)
[π»](https://github.com/mattphillips/jest-extended/commits?author=NikitaKurpas "Code") |
-| [
Alcedo Nathaniel De Guzman Jr](https://twitter.com/natealcedo)
[π»](https://github.com/mattphillips/jest-extended/commits?author=natealcedo "Code") [π](https://github.com/mattphillips/jest-extended/commits?author=natealcedo "Documentation") [π‘](#example-natealcedo "Examples") [β οΈ](https://github.com/mattphillips/jest-extended/commits?author=natealcedo "Tests") | [
Pete Hodgson](http://thepete.net)
[π»](https://github.com/mattphillips/jest-extended/commits?author=moredip "Code") |
+| [
Alcedo Nathaniel De Guzman Jr](https://twitter.com/natealcedo)
[π»](https://github.com/mattphillips/jest-extended/commits?author=natealcedo "Code") [π](https://github.com/mattphillips/jest-extended/commits?author=natealcedo "Documentation") [π‘](#example-natealcedo "Examples") [β οΈ](https://github.com/mattphillips/jest-extended/commits?author=natealcedo "Tests") | [
Pete Hodgson](http://thepete.net)
[π»](https://github.com/mattphillips/jest-extended/commits?author=moredip "Code") | [
Daniel Michalski](https://twitter.com/crazyPolishDan)
[π»](https://github.com/mattphillips/jest-extended/commits?author=danielpmichalski "Code") [π](https://github.com/mattphillips/jest-extended/commits?author=danielpmichalski "Documentation") [β οΈ](https://github.com/mattphillips/jest-extended/commits?author=danielpmichalski "Tests") |
## LICENSE
diff --git a/src/matchers/toBeArrayWithFloats/index.js b/src/matchers/toBeArrayWithFloats/index.js
new file mode 100644
index 00000000..00028612
--- /dev/null
+++ b/src/matchers/toBeArrayWithFloats/index.js
@@ -0,0 +1,18 @@
+import predicate from './predicate';
+
+export default {
+ toBeArrayWithFloats: (received, expected, precision = 4) => {
+ const pass = predicate(received, expected, precision);
+ if (pass) {
+ return {
+ message: `expected [${received}] not to be equal to [${expected}] with ${precision}-digit precision`,
+ pass: true
+ };
+ } else {
+ return {
+ message: `expected [${received}] to be equal to [${expected}] with ${precision}-digit precision`,
+ pass: false
+ };
+ }
+ }
+};
diff --git a/src/matchers/toBeArrayWithFloats/index.test.js b/src/matchers/toBeArrayWithFloats/index.test.js
new file mode 100644
index 00000000..189beb16
--- /dev/null
+++ b/src/matchers/toBeArrayWithFloats/index.test.js
@@ -0,0 +1,31 @@
+import matcher from './';
+
+expect.extend(matcher);
+
+describe('.toBeArrayWithFloats', () => {
+ test('passes for empty arrays', () => {
+ expect([]).toBeArrayWithFloats([]);
+ });
+
+ test('passes for arrays with same floats with default precision', () => {
+ expect([1.2, 2.45]).toBeArrayWithFloats([1.2, 2.45001]);
+ });
+
+ test('passes for arrays with floats rounded to same value with default precision', () => {
+ expect([0.00011]).toBeArrayWithFloats([0.0001]);
+ });
+
+ test('passes for arrays with same floats with specified precision', () => {
+ expect([1.014, 1.23456]).toBeArrayWithFloats([1.0104, 1.23112], 2);
+ });
+});
+
+describe('.not.toBeArrayWithFloats', () => {
+ test('passes for arrays with different floats', () => {
+ expect([1.0]).not.toBeArrayWithFloats([1.0001]);
+ });
+
+ test('passes for arrays with different floats due to rounding', () => {
+ expect([1.0]).not.toBeArrayWithFloats([1.00005]);
+ });
+});
diff --git a/src/matchers/toBeArrayWithFloats/predicate.js b/src/matchers/toBeArrayWithFloats/predicate.js
new file mode 100644
index 00000000..90de8583
--- /dev/null
+++ b/src/matchers/toBeArrayWithFloats/predicate.js
@@ -0,0 +1,54 @@
+const isUndefined = function(obj) {
+ return typeof obj === 'undefined';
+};
+
+const someUndefined = function(objects) {
+ let check = false;
+ objects.forEach(item => (check = check || isUndefined(item)));
+ return check;
+};
+
+const areArrays = function(...objects) {
+ if (someUndefined(objects)) {
+ return false;
+ }
+
+ let allArrays = true;
+ objects.forEach(item => (allArrays = allArrays && Array.isArray(item)));
+ return allArrays;
+};
+
+const cutDecimals = function(num, precision) {
+ return Number.parseFloat(Number.parseFloat(num).toFixed(precision));
+};
+
+const floatsEqual = function(float1, float2, precision) {
+ let a = cutDecimals(float1, precision);
+ let b = cutDecimals(float2, precision);
+
+ if (a === 0 && b === 0) {
+ return true;
+ } else if (a !== 0 && b === 0) {
+ return false;
+ } else {
+ return a / b === 1;
+ }
+};
+
+const arrayWithFloatsEquals = function(array1, array2, precision) {
+ if (array1.length !== array2.length) {
+ return false;
+ }
+
+ for (let i = 0; i < array1.length; i++) {
+ if (!floatsEqual(array1[i], array2[i], precision)) {
+ return false;
+ }
+ }
+
+ return true;
+};
+
+export default (actual, expected, precision = 4) => {
+ return areArrays(actual, expected) && arrayWithFloatsEquals(actual, expected, precision);
+};
diff --git a/src/matchers/toBeArrayWithFloats/predicate.test.js b/src/matchers/toBeArrayWithFloats/predicate.test.js
new file mode 100644
index 00000000..88a742df
--- /dev/null
+++ b/src/matchers/toBeArrayWithFloats/predicate.test.js
@@ -0,0 +1,74 @@
+import predicate from './predicate';
+
+describe('toBeArrayWithFloats predicate - positive test cases', () => {
+ test('returns true for empty arrays', () => {
+ expect(predicate([], [])).toBe(true);
+ });
+
+ test('returns true for arrays with zeroes', () => {
+ expect(predicate([0.0], [0.0])).toBe(true);
+ });
+
+ test('processes equal arrays with zeroes', () => {
+ expect(predicate([0.0, 1.0], [0.0, 1.0])).toBe(true);
+ });
+
+ test('returns true for arrays with same floats with default precision', () => {
+ expect(predicate([1.0001, 2.123], [1.00011, 2.123])).toBe(true);
+ });
+
+ test('returns true for arrays with same floats with specified precision', () => {
+ expect(predicate([1.231, 2.344], [1.23, 2.34], 2)).toBe(true);
+ });
+
+ test('returns true when floats do not differ after rounding', () => {
+ expect(predicate([1.0001], [1.00014])).toBe(true);
+ });
+});
+
+describe('toBeArrayWithFloats predicate - negative test cases', () => {
+ test('returns false for undefined objects', () => {
+ expect(predicate(undefined, undefined)).toBe(false);
+ });
+
+ test('returns false for comparing an array to undefined objects', () => {
+ expect(predicate([], undefined)).toBe(false);
+ });
+
+ test('returns false for comparing an array to undefined objects no.2', () => {
+ expect(predicate(undefined, [])).toBe(false);
+ });
+
+ test('returns false when one value is non-array', () => {
+ expect(predicate([1.0], 'non-array')).toBe(false);
+ expect(predicate('non-array', [1.0])).toBe(false);
+ });
+
+ test('returns false for non-array values', () => {
+ expect(predicate('string', 5)).toBe(false);
+ });
+
+ test('processes non-equal arrays with zeroes', () => {
+ expect(predicate([0, 1.0], [0, 0])).toBe(false);
+ });
+
+ test('processes non-equal arrays with zeroes in 2nd array', () => {
+ expect(predicate([1.0], [0])).toBe(false);
+ });
+
+ test('returns false when comparing arrays of different size', () => {
+ expect(predicate([1.0], [1.0, 2.0])).toBe(false);
+ });
+
+ test('returns false for arrays with different floats with default precision', () => {
+ expect(predicate([1.1111], [1.1112])).toBe(false);
+ });
+
+ test('returns false for arrays with different floats with specified precision', () => {
+ expect(predicate([1.1334], [1.1234], 2)).toBe(false);
+ });
+
+ test('returns false when floats differ by single digit due to rounding', () => {
+ expect(predicate([1.0001], [1.00015])).toBe(false);
+ });
+});
diff --git a/types/index.d.ts b/types/index.d.ts
index cd4cc1f4..e81141ca 100644
--- a/types/index.d.ts
+++ b/types/index.d.ts
@@ -52,6 +52,13 @@ declare namespace jest {
*/
toBeArrayOfSize(x: number): R;
+ /**
+ * Use `.toBeArrayWithFloats` when checking if a value is an `Array` with floating-point numbers. Equality is checked using default or specified precision.
+ * @param {Array.} expected
+ * @param {Number} precision, i.e. decimal places taken into account during number comparison (1.0001 is not 1.00016, but 1.0001 is 1.00015 for precision = 4)
+ */
+ toBeArrayWithFloats(expected: number[], precision: number = 4): R;
+
/**
* Use `.toBeAfter` when checking if a date occurs after `date`.
* @param {Date} date