@nomicfoundation/hardhat-ethers-chai-matchers 3.0.0-next.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +9 -0
- package/README.md +52 -0
- package/dist/src/index.d.ts +5 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +16 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/internal/add-chai-matchers.d.ts +2 -0
- package/dist/src/internal/add-chai-matchers.d.ts.map +1 -0
- package/dist/src/internal/add-chai-matchers.js +41 -0
- package/dist/src/internal/add-chai-matchers.js.map +1 -0
- package/dist/src/internal/constants.d.ts +13 -0
- package/dist/src/internal/constants.d.ts.map +1 -0
- package/dist/src/internal/constants.js +13 -0
- package/dist/src/internal/constants.js.map +1 -0
- package/dist/src/internal/hook-handlers/network.d.ts +4 -0
- package/dist/src/internal/hook-handlers/network.d.ts.map +1 -0
- package/dist/src/internal/hook-handlers/network.js +15 -0
- package/dist/src/internal/hook-handlers/network.js.map +1 -0
- package/dist/src/internal/matchers/addressable.d.ts +2 -0
- package/dist/src/internal/matchers/addressable.d.ts.map +1 -0
- package/dist/src/internal/matchers/addressable.js +53 -0
- package/dist/src/internal/matchers/addressable.js.map +1 -0
- package/dist/src/internal/matchers/big-number.d.ts +2 -0
- package/dist/src/internal/matchers/big-number.d.ts.map +1 -0
- package/dist/src/internal/matchers/big-number.js +178 -0
- package/dist/src/internal/matchers/big-number.js.map +1 -0
- package/dist/src/internal/matchers/changeEtherBalance.d.ts +7 -0
- package/dist/src/internal/matchers/changeEtherBalance.d.ts.map +1 -0
- package/dist/src/internal/matchers/changeEtherBalance.js +77 -0
- package/dist/src/internal/matchers/changeEtherBalance.js.map +1 -0
- package/dist/src/internal/matchers/changeEtherBalances.d.ts +7 -0
- package/dist/src/internal/matchers/changeEtherBalances.d.ts.map +1 -0
- package/dist/src/internal/matchers/changeEtherBalances.js +96 -0
- package/dist/src/internal/matchers/changeEtherBalances.js.map +1 -0
- package/dist/src/internal/matchers/changeTokenBalance.d.ts +16 -0
- package/dist/src/internal/matchers/changeTokenBalance.d.ts.map +1 -0
- package/dist/src/internal/matchers/changeTokenBalance.js +148 -0
- package/dist/src/internal/matchers/changeTokenBalance.js.map +1 -0
- package/dist/src/internal/matchers/emit.d.ts +5 -0
- package/dist/src/internal/matchers/emit.d.ts.map +1 -0
- package/dist/src/internal/matchers/emit.js +122 -0
- package/dist/src/internal/matchers/emit.js.map +1 -0
- package/dist/src/internal/matchers/hexEqual.d.ts +2 -0
- package/dist/src/internal/matchers/hexEqual.d.ts.map +1 -0
- package/dist/src/internal/matchers/hexEqual.js +19 -0
- package/dist/src/internal/matchers/hexEqual.js.map +1 -0
- package/dist/src/internal/matchers/properAddress.d.ts +2 -0
- package/dist/src/internal/matchers/properAddress.d.ts.map +1 -0
- package/dist/src/internal/matchers/properAddress.js +7 -0
- package/dist/src/internal/matchers/properAddress.js.map +1 -0
- package/dist/src/internal/matchers/properHex.d.ts +2 -0
- package/dist/src/internal/matchers/properHex.d.ts.map +1 -0
- package/dist/src/internal/matchers/properHex.js +13 -0
- package/dist/src/internal/matchers/properHex.js.map +1 -0
- package/dist/src/internal/matchers/properPrivateKey.d.ts +2 -0
- package/dist/src/internal/matchers/properPrivateKey.d.ts.map +1 -0
- package/dist/src/internal/matchers/properPrivateKey.js +7 -0
- package/dist/src/internal/matchers/properPrivateKey.js.map +1 -0
- package/dist/src/internal/matchers/reverted/panic.d.ts +13 -0
- package/dist/src/internal/matchers/reverted/panic.d.ts.map +1 -0
- package/dist/src/internal/matchers/reverted/panic.js +36 -0
- package/dist/src/internal/matchers/reverted/panic.js.map +1 -0
- package/dist/src/internal/matchers/reverted/reverted.d.ts +2 -0
- package/dist/src/internal/matchers/reverted/reverted.d.ts.map +1 -0
- package/dist/src/internal/matchers/reverted/reverted.js +112 -0
- package/dist/src/internal/matchers/reverted/reverted.js.map +1 -0
- package/dist/src/internal/matchers/reverted/revertedWith.d.ts +2 -0
- package/dist/src/internal/matchers/reverted/revertedWith.d.ts.map +1 -0
- package/dist/src/internal/matchers/reverted/revertedWith.js +56 -0
- package/dist/src/internal/matchers/reverted/revertedWith.js.map +1 -0
- package/dist/src/internal/matchers/reverted/revertedWithCustomError.d.ts +5 -0
- package/dist/src/internal/matchers/reverted/revertedWithCustomError.d.ts.map +1 -0
- package/dist/src/internal/matchers/reverted/revertedWithCustomError.js +120 -0
- package/dist/src/internal/matchers/reverted/revertedWithCustomError.js.map +1 -0
- package/dist/src/internal/matchers/reverted/revertedWithPanic.d.ts +2 -0
- package/dist/src/internal/matchers/reverted/revertedWithPanic.d.ts.map +1 -0
- package/dist/src/internal/matchers/reverted/revertedWithPanic.js +74 -0
- package/dist/src/internal/matchers/reverted/revertedWithPanic.js.map +1 -0
- package/dist/src/internal/matchers/reverted/revertedWithoutReason.d.ts +2 -0
- package/dist/src/internal/matchers/reverted/revertedWithoutReason.d.ts.map +1 -0
- package/dist/src/internal/matchers/reverted/revertedWithoutReason.js +41 -0
- package/dist/src/internal/matchers/reverted/revertedWithoutReason.js.map +1 -0
- package/dist/src/internal/matchers/reverted/utils.d.ts +39 -0
- package/dist/src/internal/matchers/reverted/utils.d.ts.map +1 -0
- package/dist/src/internal/matchers/reverted/utils.js +108 -0
- package/dist/src/internal/matchers/reverted/utils.js.map +1 -0
- package/dist/src/internal/matchers/withArgs.d.ts +16 -0
- package/dist/src/internal/matchers/withArgs.d.ts.map +1 -0
- package/dist/src/internal/matchers/withArgs.js +88 -0
- package/dist/src/internal/matchers/withArgs.js.map +1 -0
- package/dist/src/internal/utils/account.d.ts +3 -0
- package/dist/src/internal/utils/account.d.ts.map +1 -0
- package/dist/src/internal/utils/account.js +15 -0
- package/dist/src/internal/utils/account.js.map +1 -0
- package/dist/src/internal/utils/asserts.d.ts +5 -0
- package/dist/src/internal/utils/asserts.d.ts.map +1 -0
- package/dist/src/internal/utils/asserts.js +73 -0
- package/dist/src/internal/utils/asserts.js.map +1 -0
- package/dist/src/internal/utils/balance.d.ts +8 -0
- package/dist/src/internal/utils/balance.d.ts.map +1 -0
- package/dist/src/internal/utils/balance.js +19 -0
- package/dist/src/internal/utils/balance.js.map +1 -0
- package/dist/src/internal/utils/bigint.d.ts +2 -0
- package/dist/src/internal/utils/bigint.d.ts.map +1 -0
- package/dist/src/internal/utils/bigint.js +4 -0
- package/dist/src/internal/utils/bigint.js.map +1 -0
- package/dist/src/internal/utils/build-assert.d.ts +19 -0
- package/dist/src/internal/utils/build-assert.d.ts.map +1 -0
- package/dist/src/internal/utils/build-assert.js +39 -0
- package/dist/src/internal/utils/build-assert.js.map +1 -0
- package/dist/src/internal/utils/ordinal.d.ts +8 -0
- package/dist/src/internal/utils/ordinal.d.ts.map +1 -0
- package/dist/src/internal/utils/ordinal.js +21 -0
- package/dist/src/internal/utils/ordinal.js.map +1 -0
- package/dist/src/internal/utils/prevent-chaining.d.ts +2 -0
- package/dist/src/internal/utils/prevent-chaining.d.ts.map +1 -0
- package/dist/src/internal/utils/prevent-chaining.js +17 -0
- package/dist/src/internal/utils/prevent-chaining.js.map +1 -0
- package/dist/src/internal/utils/ssfi.d.ts +4 -0
- package/dist/src/internal/utils/ssfi.d.ts.map +1 -0
- package/dist/src/internal/utils/ssfi.js +2 -0
- package/dist/src/internal/utils/ssfi.js.map +1 -0
- package/dist/src/internal/utils/typed.d.ts +2 -0
- package/dist/src/internal/utils/typed.d.ts.map +1 -0
- package/dist/src/internal/utils/typed.js +10 -0
- package/dist/src/internal/utils/typed.js.map +1 -0
- package/dist/src/panic.d.ts +2 -0
- package/dist/src/panic.d.ts.map +1 -0
- package/dist/src/panic.js +2 -0
- package/dist/src/panic.js.map +1 -0
- package/dist/src/type-extensions.d.ts +45 -0
- package/dist/src/type-extensions.d.ts.map +1 -0
- package/dist/src/type-extensions.js +2 -0
- package/dist/src/type-extensions.js.map +1 -0
- package/dist/src/withArgs.d.ts +2 -0
- package/dist/src/withArgs.d.ts.map +1 -0
- package/dist/src/withArgs.js +2 -0
- package/dist/src/withArgs.js.map +1 -0
- package/package.json +85 -0
- package/src/index.ts +21 -0
- package/src/internal/add-chai-matchers.ts +46 -0
- package/src/internal/constants.ts +13 -0
- package/src/internal/hook-handlers/network.ts +24 -0
- package/src/internal/matchers/addressable.ts +86 -0
- package/src/internal/matchers/big-number.ts +279 -0
- package/src/internal/matchers/changeEtherBalance.ts +138 -0
- package/src/internal/matchers/changeEtherBalances.ts +188 -0
- package/src/internal/matchers/changeTokenBalance.ts +295 -0
- package/src/internal/matchers/emit.ts +232 -0
- package/src/internal/matchers/hexEqual.ts +29 -0
- package/src/internal/matchers/properAddress.ts +12 -0
- package/src/internal/matchers/properHex.ts +29 -0
- package/src/internal/matchers/properPrivateKey.ts +12 -0
- package/src/internal/matchers/reverted/panic.ts +36 -0
- package/src/internal/matchers/reverted/reverted.ts +165 -0
- package/src/internal/matchers/reverted/revertedWith.ts +100 -0
- package/src/internal/matchers/reverted/revertedWithCustomError.ts +243 -0
- package/src/internal/matchers/reverted/revertedWithPanic.ts +118 -0
- package/src/internal/matchers/reverted/revertedWithoutReason.ts +73 -0
- package/src/internal/matchers/reverted/utils.ts +147 -0
- package/src/internal/matchers/withArgs.ts +139 -0
- package/src/internal/utils/account.ts +24 -0
- package/src/internal/utils/asserts.ts +156 -0
- package/src/internal/utils/balance.ts +39 -0
- package/src/internal/utils/bigint.ts +3 -0
- package/src/internal/utils/build-assert.ts +54 -0
- package/src/internal/utils/ordinal.ts +24 -0
- package/src/internal/utils/prevent-chaining.ts +33 -0
- package/src/internal/utils/ssfi.ts +6 -0
- package/src/internal/utils/typed.ts +9 -0
- package/src/panic.ts +1 -0
- package/src/type-extensions.ts +82 -0
- package/src/withArgs.ts +1 -0
package/package.json
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
{
|
2
|
+
"name": "@nomicfoundation/hardhat-ethers-chai-matchers",
|
3
|
+
"version": "3.0.0-next.0",
|
4
|
+
"description": "Hardhat utils for testing",
|
5
|
+
"homepage": "https://github.com/nomicfoundation/hardhat/tree/v-next/v-next/hardhat-ethers-chai-matchers",
|
6
|
+
"repository": {
|
7
|
+
"type": "git",
|
8
|
+
"url": "https://github.com/NomicFoundation/hardhat",
|
9
|
+
"directory": "v-next/hardhat-ethers-chai-matchers"
|
10
|
+
},
|
11
|
+
"author": "Nomic Foundation",
|
12
|
+
"license": "MIT",
|
13
|
+
"type": "module",
|
14
|
+
"types": "dist/src/index.d.ts",
|
15
|
+
"exports": {
|
16
|
+
".": "./dist/src/index.js",
|
17
|
+
"./panic": "./dist/src/panic.js",
|
18
|
+
"./withArgs": "./dist/src/withArgs.js"
|
19
|
+
},
|
20
|
+
"keywords": [
|
21
|
+
"ethereum",
|
22
|
+
"smart-contracts",
|
23
|
+
"hardhat",
|
24
|
+
"testing"
|
25
|
+
],
|
26
|
+
"files": [
|
27
|
+
"dist/src/",
|
28
|
+
"src/",
|
29
|
+
"CHANGELOG.md",
|
30
|
+
"LICENSE",
|
31
|
+
"README.md"
|
32
|
+
],
|
33
|
+
"devDependencies": {
|
34
|
+
"@eslint-community/eslint-plugin-eslint-comments": "^4.3.0",
|
35
|
+
"@nomicfoundation/hardhat-mocha": "^3.0.0-next.0",
|
36
|
+
"@nomicfoundation/hardhat-node-test-reporter": "^3.0.0-next.0",
|
37
|
+
"@types/chai": "^4.2.0",
|
38
|
+
"@types/debug": "^4.1.7",
|
39
|
+
"@types/deep-eql": "^4.0.2",
|
40
|
+
"@types/mocha": ">=9.1.0",
|
41
|
+
"@types/node": "^20.14.9",
|
42
|
+
"@typescript-eslint/eslint-plugin": "^7.7.1",
|
43
|
+
"@typescript-eslint/parser": "^7.7.1",
|
44
|
+
"c8": "^9.1.0",
|
45
|
+
"eslint": "8.57.0",
|
46
|
+
"eslint-config-prettier": "9.1.0",
|
47
|
+
"eslint-import-resolver-typescript": "^3.6.1",
|
48
|
+
"eslint-plugin-import": "2.29.1",
|
49
|
+
"eslint-plugin-no-only-tests": "3.1.0",
|
50
|
+
"expect-type": "^0.19.0",
|
51
|
+
"mocha": "^10.0.0",
|
52
|
+
"prettier": "3.2.5",
|
53
|
+
"rimraf": "^5.0.5",
|
54
|
+
"tsx": "^4.19.3",
|
55
|
+
"typescript": "~5.5.0",
|
56
|
+
"typescript-eslint": "7.7.1",
|
57
|
+
"@nomicfoundation/hardhat-test-utils": "^3.0.0-next.0"
|
58
|
+
},
|
59
|
+
"dependencies": {
|
60
|
+
"@nomicfoundation/hardhat-errors": "^3.0.0-next.0",
|
61
|
+
"@nomicfoundation/hardhat-utils": "^3.0.0-next.0",
|
62
|
+
"@types/chai-as-promised": "^8.0.1",
|
63
|
+
"chai-as-promised": "^8.0.0",
|
64
|
+
"deep-eql": "^5.0.1"
|
65
|
+
},
|
66
|
+
"peerDependencies": {
|
67
|
+
"hardhat": "^3.0.0-next.0",
|
68
|
+
"@nomicfoundation/hardhat-ethers": "^4.0.0-next.0",
|
69
|
+
"chai": "^5.1.2",
|
70
|
+
"ethers": "^6.13.4"
|
71
|
+
},
|
72
|
+
"scripts": {
|
73
|
+
"lint": "pnpm prettier --check && pnpm eslint",
|
74
|
+
"lint:fix": "pnpm prettier --write && pnpm eslint --fix",
|
75
|
+
"eslint": "eslint \"src/**/*.ts\" \"test/**/*.ts\"",
|
76
|
+
"prettier": "prettier \"**/*.{ts,js,md,json}\"",
|
77
|
+
"test": "node --import tsx/esm --test --test-reporter=@nomicfoundation/hardhat-node-test-reporter \"test/*.ts\" \"test/!(fixture-projects|helpers)/**/*.ts\"",
|
78
|
+
"test:only": "node --import tsx/esm --test --test-only --test-reporter=@nomicfoundation/hardhat-node-test-reporter \"test/*.ts\" \"test/!(fixture-projects|helpers)/**/*.ts\"",
|
79
|
+
"test:coverage": "c8 --reporter html --reporter text --all --exclude test --exclude src/internal/types.ts --exclude src/internal/ui/direct-user-interruption-manager.ts --src src node --import tsx/esm --test --test-reporter=@nomicfoundation/hardhat-node-test-reporter \"test/!(fixture-projects|helpers)/**/*.ts\"",
|
80
|
+
"pretest": "pnpm build && node --import tsx/esm ./test/helpers/pretest.ts",
|
81
|
+
"pretest:only": "pnpm build",
|
82
|
+
"build": "tsc --build .",
|
83
|
+
"clean": "rimraf dist"
|
84
|
+
}
|
85
|
+
}
|
package/src/index.ts
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
import type { HardhatPlugin } from "hardhat/types/plugins";
|
2
|
+
|
3
|
+
import "./type-extensions.js";
|
4
|
+
|
5
|
+
const hardhatChaiMatchersPlugin: HardhatPlugin = {
|
6
|
+
id: "hardhat-ethers-chai-matchers",
|
7
|
+
hookHandlers: {
|
8
|
+
network: import.meta.resolve("./internal/hook-handlers/network.js"),
|
9
|
+
},
|
10
|
+
npmPackage: "@nomicfoundation/hardhat-ethers-chai-matchers",
|
11
|
+
dependencies: [
|
12
|
+
async () => {
|
13
|
+
const { default: hardhatEthersPlugin } = await import(
|
14
|
+
"@nomicfoundation/hardhat-ethers"
|
15
|
+
);
|
16
|
+
return hardhatEthersPlugin;
|
17
|
+
},
|
18
|
+
],
|
19
|
+
};
|
20
|
+
|
21
|
+
export default hardhatChaiMatchersPlugin;
|
@@ -0,0 +1,46 @@
|
|
1
|
+
import { use } from "chai";
|
2
|
+
import chaiAsPromised from "chai-as-promised";
|
3
|
+
|
4
|
+
import { supportAddressable } from "./matchers/addressable.js";
|
5
|
+
import { supportBigNumber } from "./matchers/big-number.js";
|
6
|
+
import { supportChangeEtherBalance } from "./matchers/changeEtherBalance.js";
|
7
|
+
import { supportChangeEtherBalances } from "./matchers/changeEtherBalances.js";
|
8
|
+
import { supportChangeTokenBalance } from "./matchers/changeTokenBalance.js";
|
9
|
+
import { supportEmit } from "./matchers/emit.js";
|
10
|
+
import { supportHexEqual } from "./matchers/hexEqual.js";
|
11
|
+
import { supportProperAddress } from "./matchers/properAddress.js";
|
12
|
+
import { supportProperHex } from "./matchers/properHex.js";
|
13
|
+
import { supportProperPrivateKey } from "./matchers/properPrivateKey.js";
|
14
|
+
import { supportReverted } from "./matchers/reverted/reverted.js";
|
15
|
+
import { supportRevertedWith } from "./matchers/reverted/revertedWith.js";
|
16
|
+
import { supportRevertedWithCustomError } from "./matchers/reverted/revertedWithCustomError.js";
|
17
|
+
import { supportRevertedWithPanic } from "./matchers/reverted/revertedWithPanic.js";
|
18
|
+
import { supportRevertedWithoutReason } from "./matchers/reverted/revertedWithoutReason.js";
|
19
|
+
import { supportWithArgs } from "./matchers/withArgs.js";
|
20
|
+
|
21
|
+
export function addChaiMatchers(): void {
|
22
|
+
use(hardhatChaiMatchers);
|
23
|
+
use(chaiAsPromised);
|
24
|
+
}
|
25
|
+
|
26
|
+
function hardhatChaiMatchers(
|
27
|
+
chai: Chai.ChaiStatic,
|
28
|
+
chaiUtils: Chai.ChaiUtils,
|
29
|
+
): void {
|
30
|
+
supportAddressable(chai.Assertion, chaiUtils);
|
31
|
+
supportBigNumber(chai.Assertion, chaiUtils);
|
32
|
+
supportEmit(chai.Assertion, chaiUtils);
|
33
|
+
supportHexEqual(chai.Assertion);
|
34
|
+
supportProperAddress(chai.Assertion);
|
35
|
+
supportProperHex(chai.Assertion);
|
36
|
+
supportProperPrivateKey(chai.Assertion);
|
37
|
+
supportChangeEtherBalance(chai.Assertion, chaiUtils);
|
38
|
+
supportChangeEtherBalances(chai.Assertion, chaiUtils);
|
39
|
+
supportChangeTokenBalance(chai.Assertion, chaiUtils);
|
40
|
+
supportReverted(chai.Assertion, chaiUtils);
|
41
|
+
supportRevertedWith(chai.Assertion, chaiUtils);
|
42
|
+
supportRevertedWithCustomError(chai.Assertion, chaiUtils);
|
43
|
+
supportRevertedWithPanic(chai.Assertion, chaiUtils);
|
44
|
+
supportRevertedWithoutReason(chai.Assertion, chaiUtils);
|
45
|
+
supportWithArgs(chai.Assertion, chaiUtils);
|
46
|
+
}
|
@@ -0,0 +1,13 @@
|
|
1
|
+
export const ASSERTION_ABORTED = "hh-ethers-chai-matchers-assertion-aborted";
|
2
|
+
export const PREVIOUS_MATCHER_NAME = "previousMatcherName";
|
3
|
+
|
4
|
+
export const CHANGE_ETHER_BALANCE_MATCHER = "changeEtherBalance";
|
5
|
+
export const CHANGE_ETHER_BALANCES_MATCHER = "changeEtherBalances";
|
6
|
+
export const CHANGE_TOKEN_BALANCE_MATCHER = "changeTokenBalance";
|
7
|
+
export const CHANGE_TOKEN_BALANCES_MATCHER = "changeTokenBalances";
|
8
|
+
export const EMIT_MATCHER = "emit";
|
9
|
+
export const REVERTED_MATCHER = "reverted";
|
10
|
+
export const REVERTED_WITH_MATCHER = "revertedWith";
|
11
|
+
export const REVERTED_WITH_CUSTOM_ERROR_MATCHER = "revertedWithCustomError";
|
12
|
+
export const REVERTED_WITH_PANIC_MATCHER = "revertedWithPanic";
|
13
|
+
export const REVERTED_WITHOUT_REASON_MATCHER = "revertedWithoutReason";
|
@@ -0,0 +1,24 @@
|
|
1
|
+
import type { HookContext, NetworkHooks } from "hardhat/types/hooks";
|
2
|
+
import type { ChainType, NetworkConnection } from "hardhat/types/network";
|
3
|
+
|
4
|
+
import { addChaiMatchers } from "../add-chai-matchers.js";
|
5
|
+
|
6
|
+
let isInitialized = false;
|
7
|
+
|
8
|
+
export default async (): Promise<Partial<NetworkHooks>> => {
|
9
|
+
const handlers: Partial<NetworkHooks> = {
|
10
|
+
async newConnection<ChainTypeT extends ChainType | string>(
|
11
|
+
context: HookContext,
|
12
|
+
next: (context: HookContext) => Promise<NetworkConnection<ChainTypeT>>,
|
13
|
+
) {
|
14
|
+
if (!isInitialized) {
|
15
|
+
addChaiMatchers();
|
16
|
+
isInitialized = true;
|
17
|
+
}
|
18
|
+
|
19
|
+
return next(context);
|
20
|
+
},
|
21
|
+
};
|
22
|
+
|
23
|
+
return handlers;
|
24
|
+
};
|
@@ -0,0 +1,86 @@
|
|
1
|
+
import { assertHardhatInvariant } from "@nomicfoundation/hardhat-errors";
|
2
|
+
import { isAddress, isAddressable } from "ethers";
|
3
|
+
|
4
|
+
import { tryDereference } from "../utils/typed.js";
|
5
|
+
|
6
|
+
export function supportAddressable(
|
7
|
+
Assertion: Chai.AssertionStatic,
|
8
|
+
chaiUtils: Chai.ChaiUtils,
|
9
|
+
): void {
|
10
|
+
const equalsFunction = override("eq", "equal", "not equal", chaiUtils);
|
11
|
+
Assertion.overwriteMethod("equals", equalsFunction);
|
12
|
+
Assertion.overwriteMethod("equal", equalsFunction);
|
13
|
+
Assertion.overwriteMethod("eq", equalsFunction);
|
14
|
+
}
|
15
|
+
|
16
|
+
type Methods = "eq";
|
17
|
+
|
18
|
+
function override(
|
19
|
+
method: Methods,
|
20
|
+
name: string,
|
21
|
+
negativeName: string,
|
22
|
+
chaiUtils: Chai.ChaiUtils,
|
23
|
+
) {
|
24
|
+
return (_super: (...args: any[]) => any) =>
|
25
|
+
overwriteAddressableFunction(method, name, negativeName, _super, chaiUtils);
|
26
|
+
}
|
27
|
+
|
28
|
+
// ethers's Addressable have a .getAddress() that returns a Promise<string>. We don't want to deal with async here,
|
29
|
+
// so we are looking for a sync way of getting the address. If an address was recovered, it is returned as a string,
|
30
|
+
// otherwise undefined is returned.
|
31
|
+
function tryGetAddressSync(value: any): string | undefined {
|
32
|
+
value = tryDereference(value, "address");
|
33
|
+
|
34
|
+
if (isAddressable(value)) {
|
35
|
+
if ("address" in value) {
|
36
|
+
value = value.address;
|
37
|
+
} else {
|
38
|
+
assertHardhatInvariant(
|
39
|
+
"target" in value,
|
40
|
+
"target property should exist in value",
|
41
|
+
);
|
42
|
+
value = value.target;
|
43
|
+
}
|
44
|
+
}
|
45
|
+
|
46
|
+
if (isAddress(value)) {
|
47
|
+
return value;
|
48
|
+
} else {
|
49
|
+
return undefined;
|
50
|
+
}
|
51
|
+
}
|
52
|
+
|
53
|
+
function overwriteAddressableFunction(
|
54
|
+
functionName: Methods,
|
55
|
+
readableName: string,
|
56
|
+
readableNegativeName: string,
|
57
|
+
_super: (...args: any[]) => any,
|
58
|
+
chaiUtils: Chai.ChaiUtils,
|
59
|
+
) {
|
60
|
+
return function (this: Chai.AssertionStatic, ...args: any[]) {
|
61
|
+
const [actualArg, message] = args;
|
62
|
+
const expectedFlag = chaiUtils.flag(this, "object");
|
63
|
+
|
64
|
+
if (message !== undefined) {
|
65
|
+
chaiUtils.flag(this, "message", message);
|
66
|
+
}
|
67
|
+
|
68
|
+
const actual = tryGetAddressSync(actualArg);
|
69
|
+
const expected = tryGetAddressSync(expectedFlag);
|
70
|
+
if (
|
71
|
+
functionName === "eq" &&
|
72
|
+
expected !== undefined &&
|
73
|
+
actual !== undefined
|
74
|
+
) {
|
75
|
+
this.assert(
|
76
|
+
expected === actual,
|
77
|
+
`expected '${expected}' to ${readableName} '${actual}'.`,
|
78
|
+
`expected '${expected}' to ${readableNegativeName} '${actual}'.`,
|
79
|
+
actual.toString(),
|
80
|
+
expected.toString(),
|
81
|
+
);
|
82
|
+
} else {
|
83
|
+
_super.apply(this, args);
|
84
|
+
}
|
85
|
+
};
|
86
|
+
}
|
@@ -0,0 +1,279 @@
|
|
1
|
+
import util from "node:util";
|
2
|
+
|
3
|
+
import { HardhatError } from "@nomicfoundation/hardhat-errors";
|
4
|
+
import { toBigInt } from "@nomicfoundation/hardhat-utils/bigint";
|
5
|
+
import { AssertionError } from "chai";
|
6
|
+
import deepEqual from "deep-eql";
|
7
|
+
|
8
|
+
import { isBigInt } from "../utils/bigint.js";
|
9
|
+
|
10
|
+
export function supportBigNumber(
|
11
|
+
Assertion: Chai.AssertionStatic,
|
12
|
+
chaiUtils: Chai.ChaiUtils,
|
13
|
+
): void {
|
14
|
+
const equalsFunction = override("eq", "equal", "not equal", chaiUtils);
|
15
|
+
Assertion.overwriteMethod("equals", equalsFunction);
|
16
|
+
Assertion.overwriteMethod("equal", equalsFunction);
|
17
|
+
Assertion.overwriteMethod("eq", equalsFunction);
|
18
|
+
|
19
|
+
const gtFunction = override("gt", "be above", "be at most", chaiUtils);
|
20
|
+
Assertion.overwriteMethod("above", gtFunction);
|
21
|
+
Assertion.overwriteMethod("gt", gtFunction);
|
22
|
+
Assertion.overwriteMethod("greaterThan", gtFunction);
|
23
|
+
|
24
|
+
const ltFunction = override("lt", "be below", "be at least", chaiUtils);
|
25
|
+
Assertion.overwriteMethod("below", ltFunction);
|
26
|
+
Assertion.overwriteMethod("lt", ltFunction);
|
27
|
+
Assertion.overwriteMethod("lessThan", ltFunction);
|
28
|
+
|
29
|
+
const gteFunction = override("gte", "be at least", "be below", chaiUtils);
|
30
|
+
Assertion.overwriteMethod("least", gteFunction);
|
31
|
+
Assertion.overwriteMethod("gte", gteFunction);
|
32
|
+
Assertion.overwriteMethod("greaterThanOrEqual", gteFunction);
|
33
|
+
|
34
|
+
const lteFunction = override("lte", "be at most", "be above", chaiUtils);
|
35
|
+
Assertion.overwriteMethod("most", lteFunction);
|
36
|
+
Assertion.overwriteMethod("lte", lteFunction);
|
37
|
+
Assertion.overwriteMethod("lessThanOrEqual", lteFunction);
|
38
|
+
|
39
|
+
Assertion.overwriteChainableMethod(...createLengthOverride("length"));
|
40
|
+
Assertion.overwriteChainableMethod(...createLengthOverride("lengthOf"));
|
41
|
+
|
42
|
+
Assertion.overwriteMethod("within", overrideWithin(chaiUtils));
|
43
|
+
|
44
|
+
Assertion.overwriteMethod("closeTo", overrideCloseTo(chaiUtils));
|
45
|
+
Assertion.overwriteMethod("approximately", overrideCloseTo(chaiUtils));
|
46
|
+
}
|
47
|
+
|
48
|
+
function createLengthOverride(
|
49
|
+
method: string,
|
50
|
+
): [string, (...args: any[]) => any, (...args: any[]) => any] {
|
51
|
+
return [
|
52
|
+
method,
|
53
|
+
function (_super: any) {
|
54
|
+
return function (this: Chai.AssertionPrototype, value: any) {
|
55
|
+
const actual = this._obj;
|
56
|
+
|
57
|
+
if (isBigInt(value)) {
|
58
|
+
const sizeOrLength =
|
59
|
+
actual instanceof Map || actual instanceof Set ? "size" : "length";
|
60
|
+
|
61
|
+
const actualLength = toBigInt(actual[sizeOrLength]);
|
62
|
+
const expectedLength = toBigInt(value);
|
63
|
+
|
64
|
+
this.assert(
|
65
|
+
actualLength === expectedLength,
|
66
|
+
`expected #{this} to have a ${sizeOrLength} of ${expectedLength.toString()} but got ${actualLength.toString()}`,
|
67
|
+
`expected #{this} not to have a ${sizeOrLength} of ${expectedLength.toString()} but got ${actualLength.toString()}`,
|
68
|
+
actualLength.toString(),
|
69
|
+
expectedLength.toString(),
|
70
|
+
);
|
71
|
+
} else {
|
72
|
+
_super.apply(this, arguments);
|
73
|
+
}
|
74
|
+
};
|
75
|
+
},
|
76
|
+
function (_super: any) {
|
77
|
+
return function (this: any) {
|
78
|
+
_super.apply(this, arguments);
|
79
|
+
};
|
80
|
+
},
|
81
|
+
];
|
82
|
+
}
|
83
|
+
|
84
|
+
type Methods = "eq" | "gt" | "lt" | "gte" | "lte";
|
85
|
+
|
86
|
+
function override(
|
87
|
+
method: Methods,
|
88
|
+
name: string,
|
89
|
+
negativeName: string,
|
90
|
+
chaiUtils: Chai.ChaiUtils,
|
91
|
+
) {
|
92
|
+
return (_super: (...args: any[]) => any) =>
|
93
|
+
overwriteBigNumberFunction(method, name, negativeName, _super, chaiUtils);
|
94
|
+
}
|
95
|
+
|
96
|
+
function overwriteBigNumberFunction(
|
97
|
+
functionName: Methods,
|
98
|
+
readableName: string,
|
99
|
+
readableNegativeName: string,
|
100
|
+
_super: (...args: any[]) => any,
|
101
|
+
chaiUtils: Chai.ChaiUtils,
|
102
|
+
) {
|
103
|
+
return function (this: Chai.AssertionStatic, ...args: any[]) {
|
104
|
+
const [actualArg, message] = args;
|
105
|
+
const expectedFlag = chaiUtils.flag(this, "object");
|
106
|
+
|
107
|
+
if (message !== undefined) {
|
108
|
+
chaiUtils.flag(this, "message", message);
|
109
|
+
}
|
110
|
+
|
111
|
+
function compare(method: Methods, lhs: bigint, rhs: bigint): boolean {
|
112
|
+
if (method === "eq") {
|
113
|
+
return lhs === rhs;
|
114
|
+
} else if (method === "gt") {
|
115
|
+
return lhs > rhs;
|
116
|
+
} else if (method === "lt") {
|
117
|
+
return lhs < rhs;
|
118
|
+
} else if (method === "gte") {
|
119
|
+
return lhs >= rhs;
|
120
|
+
} else if (method === "lte") {
|
121
|
+
return lhs <= rhs;
|
122
|
+
} else {
|
123
|
+
throw new HardhatError(
|
124
|
+
HardhatError.ERRORS.CHAI_MATCHERS.UNKNOWN_COMPARISON_OPERATION,
|
125
|
+
{
|
126
|
+
method,
|
127
|
+
},
|
128
|
+
);
|
129
|
+
}
|
130
|
+
}
|
131
|
+
|
132
|
+
if (Boolean(chaiUtils.flag(this, "doLength")) && isBigInt(actualArg)) {
|
133
|
+
const sizeOrLength =
|
134
|
+
expectedFlag instanceof Map || expectedFlag instanceof Set
|
135
|
+
? "size"
|
136
|
+
: "length";
|
137
|
+
|
138
|
+
if (expectedFlag[sizeOrLength] === undefined) {
|
139
|
+
_super.apply(this, args);
|
140
|
+
return;
|
141
|
+
}
|
142
|
+
|
143
|
+
const expected = toBigInt(expectedFlag[sizeOrLength]);
|
144
|
+
const actual = toBigInt(actualArg);
|
145
|
+
|
146
|
+
this.assert(
|
147
|
+
compare(functionName, expected, actual),
|
148
|
+
`expected #{this} to have a ${sizeOrLength} ${readableName.replace(
|
149
|
+
"be ",
|
150
|
+
"",
|
151
|
+
)} ${actual.toString()} but got ${expected}`,
|
152
|
+
`expected #{this} to have a ${sizeOrLength} ${readableNegativeName} ${actual.toString()}`,
|
153
|
+
expected,
|
154
|
+
actual,
|
155
|
+
);
|
156
|
+
} else if (functionName === "eq" && Boolean(chaiUtils.flag(this, "deep"))) {
|
157
|
+
// "ssfi" stands for "start stack function indicator", it's a chai concept
|
158
|
+
// used to control which frames are included in the stack trace
|
159
|
+
// this pattern here was taken from chai's implementation of .deep.equal
|
160
|
+
const prevLockSsfi = chaiUtils.flag(this, "lockSsfi");
|
161
|
+
|
162
|
+
chaiUtils.flag(this, "lockSsfi", true);
|
163
|
+
|
164
|
+
this.assert(
|
165
|
+
deepEqual(actualArg, expectedFlag, { comparator: deepEqualComparator }),
|
166
|
+
`expected ${util.inspect(expectedFlag)} to deeply equal ${util.inspect(
|
167
|
+
actualArg,
|
168
|
+
)}`,
|
169
|
+
`expected ${util.inspect(
|
170
|
+
expectedFlag,
|
171
|
+
)} to not deeply equal ${util.inspect(actualArg)}`,
|
172
|
+
null,
|
173
|
+
);
|
174
|
+
|
175
|
+
chaiUtils.flag(this, "lockSsfi", prevLockSsfi);
|
176
|
+
} else if (isBigInt(expectedFlag) || isBigInt(actualArg)) {
|
177
|
+
const expected = toBigInt(expectedFlag);
|
178
|
+
const actual = toBigInt(actualArg);
|
179
|
+
|
180
|
+
this.assert(
|
181
|
+
compare(functionName, expected, actual),
|
182
|
+
`expected ${expected} to ${readableName} ${actual}.`,
|
183
|
+
`expected ${expected} to ${readableNegativeName} ${actual}.`,
|
184
|
+
actual.toString(),
|
185
|
+
expected.toString(),
|
186
|
+
);
|
187
|
+
} else {
|
188
|
+
_super.apply(this, args);
|
189
|
+
}
|
190
|
+
};
|
191
|
+
}
|
192
|
+
|
193
|
+
function overrideWithin(chaiUtils: Chai.ChaiUtils) {
|
194
|
+
return (_super: (...args: any[]) => any) =>
|
195
|
+
overwriteBigNumberWithin(_super, chaiUtils);
|
196
|
+
}
|
197
|
+
|
198
|
+
function overwriteBigNumberWithin(
|
199
|
+
_super: (...args: any[]) => any,
|
200
|
+
chaiUtils: Chai.ChaiUtils,
|
201
|
+
) {
|
202
|
+
return function (this: Chai.AssertionStatic, ...args: any[]) {
|
203
|
+
const [startArg, finishArg] = args;
|
204
|
+
const expectedFlag = chaiUtils.flag(this, "object");
|
205
|
+
|
206
|
+
if (isBigInt(expectedFlag) || isBigInt(startArg) || isBigInt(finishArg)) {
|
207
|
+
const expected = toBigInt(expectedFlag);
|
208
|
+
const start = toBigInt(startArg);
|
209
|
+
const finish = toBigInt(finishArg);
|
210
|
+
this.assert(
|
211
|
+
start <= expected && expected <= finish,
|
212
|
+
`expected ${expected} to be within ${start}..${finish}`,
|
213
|
+
`expected ${expected} to not be within ${start}..${finish}`,
|
214
|
+
expected,
|
215
|
+
[start, finish],
|
216
|
+
);
|
217
|
+
} else {
|
218
|
+
_super.apply(this, args);
|
219
|
+
}
|
220
|
+
};
|
221
|
+
}
|
222
|
+
|
223
|
+
function overrideCloseTo(chaiUtils: Chai.ChaiUtils) {
|
224
|
+
return (_super: (...args: any[]) => any) =>
|
225
|
+
overwriteBigNumberCloseTo(_super, chaiUtils);
|
226
|
+
}
|
227
|
+
|
228
|
+
function overwriteBigNumberCloseTo(
|
229
|
+
_super: (...args: any[]) => any,
|
230
|
+
chaiUtils: Chai.ChaiUtils,
|
231
|
+
) {
|
232
|
+
return function (this: Chai.AssertionStatic, ...args: any[]) {
|
233
|
+
const [actualArg, deltaArg] = args;
|
234
|
+
const expectedFlag = chaiUtils.flag(this, "object");
|
235
|
+
|
236
|
+
if (
|
237
|
+
isBigInt(expectedFlag) ||
|
238
|
+
isBigInt(actualArg) ||
|
239
|
+
isBigInt(deltaArg) ||
|
240
|
+
typeof actualArg === "number"
|
241
|
+
) {
|
242
|
+
if (deltaArg === undefined) {
|
243
|
+
// eslint-disable-next-line no-restricted-syntax -- keep the original chai error structure
|
244
|
+
throw new AssertionError(
|
245
|
+
"the arguments to closeTo or approximately must be numbers, and a delta is required",
|
246
|
+
);
|
247
|
+
}
|
248
|
+
|
249
|
+
const expected = toBigInt(expectedFlag);
|
250
|
+
const actual = toBigInt(actualArg);
|
251
|
+
const delta = toBigInt(deltaArg);
|
252
|
+
|
253
|
+
function abs(i: bigint): bigint {
|
254
|
+
return i < 0 ? BigInt(-1) * i : i;
|
255
|
+
}
|
256
|
+
|
257
|
+
this.assert(
|
258
|
+
abs(expected - actual) <= delta,
|
259
|
+
`expected ${expected} to be close to ${actual} +/- ${delta}`,
|
260
|
+
`expected ${expected} not to be close to ${actual} +/- ${delta}`,
|
261
|
+
expected,
|
262
|
+
`A number between ${actual - delta} and ${actual + delta}`,
|
263
|
+
);
|
264
|
+
} else {
|
265
|
+
_super.apply(this, args);
|
266
|
+
}
|
267
|
+
};
|
268
|
+
}
|
269
|
+
|
270
|
+
function deepEqualComparator(a: any, b: any): boolean | null {
|
271
|
+
try {
|
272
|
+
const normalizedA = toBigInt(a);
|
273
|
+
const normalizedB = toBigInt(b);
|
274
|
+
return normalizedA === normalizedB;
|
275
|
+
} catch (e) {
|
276
|
+
// use default comparator
|
277
|
+
return null;
|
278
|
+
}
|
279
|
+
}
|