Skip to content

Commit 46ed810

Browse files
authored
feat: #591: Add BigInt support to number matchers (#772)
and add new toBeBigInt matcher
1 parent 25bd521 commit 46ed810

32 files changed

+491
-61
lines changed

.changeset/better-lights-lay.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'jest-extended': major
3+
---
4+
5+
Add BigInt support to number matchers
6+
and add new toBeBigInt matchers

all.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
11
// override rule to allow running linting before build (dist directory won't exist yet)
22

3-
// eslint-disable-next-line import/no-unresolved
43
require('./dist/all');

src/matchers/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ export { toBeArrayOfSize } from './toBeArrayOfSize';
77
export { toBeBefore } from './toBeBefore';
88
export { toBeBeforeOrEqualTo } from './toBeBeforeOrEqualTo';
99
export { toBeBetween } from './toBeBetween';
10+
export { toBeBigInt } from './toBeBigInt';
1011
export { toBeBoolean } from './toBeBoolean';
1112
export { toBeDate } from './toBeDate';
1213
export { toBeDateString } from './toBeDateString';

src/matchers/toBeBigInt.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
export function toBeBigInt(actual: unknown) {
2+
// @ts-expect-error OK to have implicit any for this.utils
3+
const { printReceived, matcherHint } = this.utils;
4+
5+
const pass = typeof actual === 'bigint';
6+
7+
return {
8+
pass,
9+
message: () =>
10+
pass
11+
? matcherHint('.not.toBeBigInt', 'received', '') +
12+
'\n\n' +
13+
'Expected value to not be an BigInt received:\n' +
14+
` ${printReceived(actual)}`
15+
: matcherHint('.toBeBigInt', 'received', '') +
16+
'\n\n' +
17+
'Expected value to be a BigInt received:\n' +
18+
` ${printReceived(actual)}`,
19+
};
20+
}

src/matchers/toBeEven.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ export function toBeEven(actual: unknown) {
22
// @ts-expect-error OK to have implicit any for this.utils
33
const { printReceived, matcherHint } = this.utils;
44

5-
const pass = isNumber(actual) && isEven(actual);
5+
const pass =
6+
(typeof actual === 'number' && !isNaN(actual) && actual % 2 === 0) ||
7+
(typeof actual === 'bigint' && actual % BigInt(2) === BigInt(0));
68

79
return {
810
pass,
@@ -18,6 +20,3 @@ export function toBeEven(actual: unknown) {
1820
` ${printReceived(actual)}`,
1921
};
2022
}
21-
22-
const isNumber = (expected: any) => !isNaN(parseInt(expected));
23-
const isEven = (expected: any) => expected % 2 === 0;

src/matchers/toBeFinite.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ export function toBeFinite(actual: unknown) {
22
// @ts-expect-error OK to have implicit any for this.utils
33
const { printReceived, matcherHint } = this.utils;
44

5-
const pass = Number.isFinite(actual);
5+
const pass = Number.isFinite(actual) || typeof actual === 'bigint';
66

77
return {
88
pass,

src/matchers/toBeInRange.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
1-
export function toBeInRange(actual: unknown[], min: number, max: number) {
1+
export function toBeInRange(actual: unknown[], min: number | bigint, max: number | bigint) {
22
// @ts-expect-error OK to have implicit any for this.utils
33
const { printReceived, printExpected, matcherHint } = this.utils;
44

5-
const element = actual.find((option: any) => option < min || option >= max);
5+
const element = actual.find((option: any) => {
6+
if (typeof option === 'bigint' && typeof min === 'bigint' && typeof max === 'bigint') {
7+
return option < min || option >= max;
8+
}
9+
return option < min || option >= max;
10+
});
611

712
const pass = element === undefined;
813

src/matchers/toBeNegative.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ export function toBeNegative(actual: unknown) {
22
// @ts-expect-error OK to have implicit any for this.utils
33
const { printReceived, matcherHint } = this.utils;
44

5-
const pass = isNumber(actual) && isNegative(actual);
5+
const pass =
6+
(typeof actual === 'number' && !isNaN(actual) && actual < 0) || (typeof actual === 'bigint' && actual < BigInt(0));
67

78
return {
89
pass,
@@ -18,6 +19,3 @@ export function toBeNegative(actual: unknown) {
1819
` ${printReceived(actual)}`,
1920
};
2021
}
21-
22-
const isNumber = (value: any) => !isNaN(parseInt(value));
23-
const isNegative = (value: any) => value < 0;

src/matchers/toBeOdd.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ export function toBeOdd(actual: unknown) {
22
// @ts-expect-error OK to have implicit any for this.utils
33
const { printReceived, matcherHint } = this.utils;
44

5-
const pass = isNumber(actual) && isOdd(actual);
5+
const pass = (isNumber(actual) || isBigInt(actual)) && isOdd(actual);
66

77
return {
88
pass,
@@ -19,5 +19,9 @@ export function toBeOdd(actual: unknown) {
1919
};
2020
}
2121

22-
const isNumber = (expected: any) => !isNaN(parseInt(expected));
23-
const isOdd = (expected: any) => expected % 2 === 1;
22+
const isNumber = (expected: any) => typeof expected === 'number' && Number.isFinite(expected);
23+
const isBigInt = (expected: any) => typeof expected === 'bigint';
24+
const isOdd = (expected: any) => {
25+
if (isBigInt(expected)) return expected % 2n === 1n || expected % 2n === -1n;
26+
return Math.abs(expected % 2) === 1;
27+
};

src/matchers/toBePositive.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ export function toBePositive(actual: unknown) {
22
// @ts-expect-error OK to have implicit any for this.utils
33
const { printReceived, matcherHint } = this.utils;
44

5-
const pass = isNumber(actual) && isPositive(actual);
5+
const pass = (isNumber(actual) || isBigInt(actual)) && isPositive(actual);
66

77
return {
88
pass,
@@ -19,5 +19,9 @@ export function toBePositive(actual: unknown) {
1919
};
2020
}
2121

22-
const isNumber = (value: any) => !isNaN(parseInt(value));
23-
const isPositive = (value: any) => value > 0;
22+
const isNumber = (value: any) => typeof value === 'number' && !isNaN(value) && isFinite(value);
23+
const isBigInt = (value: any) => typeof value === 'bigint';
24+
const isPositive = (value: any) => {
25+
if (typeof value === 'bigint') return value > 0n;
26+
return value > 0;
27+
};

src/matchers/toChangeBy.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,20 @@
11
/**
22
* Use `.toChangeBy` when checking if a value changed by an amount.
33
*/
4-
export function toChangeBy(mutator: () => unknown | void, checker: () => number, by: number = 1) {
4+
export function toChangeBy(mutator: () => unknown | void, checker: () => number | bigint, by: number | bigint = 1) {
55
// @ts-expect-error OK to have implicit any for this.utils
66
const { printReceived: print, matcherHint: hint } = this.utils;
77

88
const before = checker();
99
mutator();
10-
const received = checker() - before;
10+
const after = checker();
11+
12+
let received;
13+
if (typeof before === 'bigint' && typeof after === 'bigint') {
14+
received = after - before;
15+
} else {
16+
received = Number(after) - Number(before);
17+
}
1118

1219
const passMessage = `
1320
${hint('.not.toChangeBy', 'received', '')}\n\nExpected value to not change by ${by}, received:\n ${print(received)}

src/matchers/toChangeTo.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/**
22
* Use `.toChangeTo` when checking if a value changed to a specific value.
33
*/
4-
export function toChangeTo(mutator: () => unknown | void, checker: () => number, to: number) {
4+
export function toChangeTo<E = unknown>(mutator: () => unknown | void, checker: () => E, to: E) {
55
// @ts-expect-error OK to have implicit any for this.utils
66
const { printReceived: print, matcherHint: hint } = this.utils;
77

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`.not.toBeInteger fails when given integer 1`] = `
4+
"<dim>expect(</intensity><red>received</color><dim>).not.toBeBigInt()</intensity>
5+
6+
Expected value to not be an BigInt received:
7+
<red>1n</color>"
8+
`;
9+
10+
exports[`.toBeBigInt fails when given fraction 1`] = `
11+
"<dim>expect(</intensity><red>received</color><dim>).toBeBigInt()</intensity>
12+
13+
Expected value to be a BigInt received:
14+
<red>1.5</color>"
15+
`;
16+
17+
exports[`.toBeBigInt fails when given integer 1`] = `
18+
"<dim>expect(</intensity><red>received</color><dim>).toBeBigInt()</intensity>
19+
20+
Expected value to be a BigInt received:
21+
<red>1</color>"
22+
`;

test/matchers/__snapshots__/toBeEven.test.ts.snap

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,33 @@
11
// Jest Snapshot v1, https://goo.gl/fbAQLP
22

3+
exports[`.not.toBeEven fails when given an even BigInt 1`] = `
4+
"<dim>expect(</intensity><red>received</color><dim>).not.toBeEven()</intensity>
5+
6+
Expected value to not be an even number received:
7+
<red>2n</color>"
8+
`;
9+
310
exports[`.not.toBeEven fails when given an even number 1`] = `
411
"<dim>expect(</intensity><red>received</color><dim>).not.toBeEven()</intensity>
512
613
Expected value to not be an even number received:
714
<red>2</color>"
815
`;
916

17+
exports[`.toBeEven fails when given odd BigInt 1`] = `
18+
"<dim>expect(</intensity><red>received</color><dim>).toBeEven()</intensity>
19+
20+
Expected value to be an even number received:
21+
<red>1n</color>"
22+
`;
23+
24+
exports[`.toBeEven fails when given odd BigInt 2`] = `
25+
"<dim>expect(</intensity><red>received</color><dim>).toBeEven()</intensity>
26+
27+
Expected value to be an even number received:
28+
<red>-3n</color>"
29+
`;
30+
1031
exports[`.toBeEven fails when not given an even number 1`] = `
1132
"<dim>expect(</intensity><red>received</color><dim>).toBeEven()</intensity>
1233

test/matchers/__snapshots__/toBeFinite.test.ts.snap

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
// Jest Snapshot v1, https://goo.gl/fbAQLP
22

3+
exports[`.not.toBeFinite fails when given a BigInt value 1`] = `
4+
"<dim>expect(</intensity><red>received</color><dim>).not.toBeFinite()</intensity>
5+
6+
Expected value to not be finite received:
7+
<red>1n</color>"
8+
`;
9+
310
exports[`.not.toBeFinite fails when given a finite number 1`] = `
411
"<dim>expect(</intensity><red>received</color><dim>).not.toBeFinite()</intensity>
512

test/matchers/__snapshots__/toBeInRange.test.ts.snap

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
// Jest Snapshot v1, https://goo.gl/fbAQLP
22

3+
exports[`.not.toBeInRange fails when given BigInt array is in the given range 1`] = `
4+
"<dim>expect(</intensity><red>received</color><dim>).not.toBeInRange(</intensity><green>expected</color><dim>)</intensity>
5+
6+
Expected Array to not be in range <green>4n</color>, <green>10n</color>
7+
Received:
8+
<red>[4n, 5n, 7n, 9n]</color>"
9+
`;
10+
311
exports[`.not.toBeInRange fails when given array is in the given range 1`] = `
412
"<dim>expect(</intensity><red>received</color><dim>).not.toBeInRange(</intensity><green>expected</color><dim>)</intensity>
513
@@ -8,6 +16,13 @@ Received:
816
<red>[4, 5, 7, 9]</color>"
917
`;
1018

19+
exports[`.toBeInRange fails when given BigInt array is not in a given range 1`] = `
20+
"<dim>expect(</intensity><red>received</color><dim>).toBeInRange(</intensity><green>expected</color><dim>)</intensity>
21+
22+
Expected: Array elements to be in range (<green>4n</color>, <green>8n</color>)
23+
Received: Array element out of range <red>9n</color>"
24+
`;
25+
1126
exports[`.toBeInRange fails when given array is not in a given range 1`] = `
1227
"<dim>expect(</intensity><red>received</color><dim>).toBeInRange(</intensity><green>expected</color><dim>)</intensity>
1328

test/matchers/__snapshots__/toBeNegative.test.ts.snap

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
// Jest Snapshot v1, https://goo.gl/fbAQLP
22

3+
exports[`.not.toBeNegative fails when given negative BigInt 1`] = `
4+
"<dim>expect(</intensity><red>received</color><dim>).not.toBeNegative()</intensity>
5+
6+
Expected value to not be a negative number received:
7+
<red>-1n</color>"
8+
`;
9+
310
exports[`.not.toBeNegative fails when given negative number 1`] = `
411
"<dim>expect(</intensity><red>received</color><dim>).not.toBeNegative()</intensity>
512
@@ -14,9 +21,23 @@ Expected value to be a negative number received:
1421
<red>Infinity</color>"
1522
`;
1623

24+
exports[`.toBeNegative fails when given positive BigInt 1`] = `
25+
"<dim>expect(</intensity><red>received</color><dim>).toBeNegative()</intensity>
26+
27+
Expected value to be a negative number received:
28+
<red>1n</color>"
29+
`;
30+
1731
exports[`.toBeNegative fails when given positive number 1`] = `
1832
"<dim>expect(</intensity><red>received</color><dim>).toBeNegative()</intensity>
1933
2034
Expected value to be a negative number received:
2135
<red>1</color>"
2236
`;
37+
38+
exports[`.toBeNegative fails when given zero BigInt 1`] = `
39+
"<dim>expect(</intensity><red>received</color><dim>).toBeNegative()</intensity>
40+
41+
Expected value to be a negative number received:
42+
<red>0n</color>"
43+
`;

test/matchers/__snapshots__/toBeOdd.test.ts.snap

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,33 +39,47 @@ exports[`.toBeOdd fails when given not given an odd number 5`] = `
3939
"<dim>expect(</intensity><red>received</color><dim>).toBeOdd()</intensity>
4040
4141
Expected value to be odd received:
42-
<red>{}</color>"
42+
<red>2n</color>"
4343
`;
4444

4545
exports[`.toBeOdd fails when given not given an odd number 6`] = `
4646
"<dim>expect(</intensity><red>received</color><dim>).toBeOdd()</intensity>
4747
4848
Expected value to be odd received:
49-
<red>[Function anonymous]</color>"
49+
<red>{}</color>"
5050
`;
5151

5252
exports[`.toBeOdd fails when given not given an odd number 7`] = `
5353
"<dim>expect(</intensity><red>received</color><dim>).toBeOdd()</intensity>
5454
5555
Expected value to be odd received:
56-
<red>undefined</color>"
56+
<red>[Function anonymous]</color>"
5757
`;
5858

5959
exports[`.toBeOdd fails when given not given an odd number 8`] = `
6060
"<dim>expect(</intensity><red>received</color><dim>).toBeOdd()</intensity>
6161
6262
Expected value to be odd received:
63-
<red>null</color>"
63+
<red>undefined</color>"
6464
`;
6565

6666
exports[`.toBeOdd fails when given not given an odd number 9`] = `
6767
"<dim>expect(</intensity><red>received</color><dim>).toBeOdd()</intensity>
6868
69+
Expected value to be odd received:
70+
<red>null</color>"
71+
`;
72+
73+
exports[`.toBeOdd fails when given not given an odd number 10`] = `
74+
"<dim>expect(</intensity><red>received</color><dim>).toBeOdd()</intensity>
75+
6976
Expected value to be odd received:
7077
<red>NaN</color>"
7178
`;
79+
80+
exports[`.toBeOdd fails when given not given an odd number 11`] = `
81+
"<dim>expect(</intensity><red>received</color><dim>).toBeOdd()</intensity>
82+
83+
Expected value to be odd received:
84+
<red>Symbol(foo)</color>"
85+
`;

test/matchers/__snapshots__/toBePositive.test.ts.snap

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,26 @@
11
// Jest Snapshot v1, https://goo.gl/fbAQLP
22

3+
exports[`.not.toBePositive fails when given a positive BigInt 1`] = `
4+
"<dim>expect(</intensity><red>received</color><dim>).not.toBePositive()</intensity>
5+
6+
Expected value to not be positive received:
7+
<red>5n</color>"
8+
`;
9+
310
exports[`.not.toBePositive fails when given a positive number 1`] = `
411
"<dim>expect(</intensity><red>received</color><dim>).not.toBePositive()</intensity>
512
613
Expected value to not be positive received:
714
<red>5</color>"
815
`;
916

17+
exports[`.toBePositive fails when not given a positive BigInt 1`] = `
18+
"<dim>expect(</intensity><red>received</color><dim>).toBePositive()</intensity>
19+
20+
Expected value to be positive received:
21+
<red>-1n</color>"
22+
`;
23+
1024
exports[`.toBePositive fails when not given a positive number 1`] = `
1125
"<dim>expect(</intensity><red>received</color><dim>).toBePositive()</intensity>
1226

0 commit comments

Comments
 (0)