@marigoldlabs/web3-tester 0.1.2 → 0.4.2
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/.env.example +26 -17
- package/LICENSE +21 -0
- package/README.md +480 -48
- package/dist/anvil.d.ts +90 -2
- package/dist/anvil.d.ts.map +1 -1
- package/dist/anvil.js +215 -13
- package/dist/anvil.js.map +1 -1
- package/dist/benchmark.d.ts +55 -0
- package/dist/benchmark.d.ts.map +1 -0
- package/dist/benchmark.js +168 -0
- package/dist/benchmark.js.map +1 -0
- package/dist/contracts/test-erc20.d.ts +227 -0
- package/dist/contracts/test-erc20.d.ts.map +1 -0
- package/dist/contracts/test-erc20.js +8 -0
- package/dist/contracts/test-erc20.js.map +1 -0
- package/dist/erc20.d.ts +38 -0
- package/dist/erc20.d.ts.map +1 -0
- package/dist/erc20.js +229 -0
- package/dist/erc20.js.map +1 -0
- package/dist/fixtures.d.ts +44 -2
- package/dist/fixtures.d.ts.map +1 -1
- package/dist/fixtures.js +162 -17
- package/dist/fixtures.js.map +1 -1
- package/dist/index.d.ts +26 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -1
- package/dist/index.js.map +1 -1
- package/dist/injected-provider.d.ts.map +1 -1
- package/dist/injected-provider.js +863 -77
- package/dist/injected-provider.js.map +1 -1
- package/dist/live-fixtures.d.ts +32 -3
- package/dist/live-fixtures.d.ts.map +1 -1
- package/dist/live-fixtures.js +64 -27
- package/dist/live-fixtures.js.map +1 -1
- package/dist/matchers.d.ts +90 -0
- package/dist/matchers.d.ts.map +1 -0
- package/dist/matchers.js +268 -0
- package/dist/matchers.js.map +1 -0
- package/dist/metamask-extension.d.ts +34 -0
- package/dist/metamask-extension.d.ts.map +1 -0
- package/dist/metamask-extension.js +97 -0
- package/dist/metamask-extension.js.map +1 -0
- package/dist/mock-wallet-controller.d.ts +354 -4
- package/dist/mock-wallet-controller.d.ts.map +1 -1
- package/dist/mock-wallet-controller.js +1444 -58
- package/dist/mock-wallet-controller.js.map +1 -1
- package/dist/private-key-rpc-client.d.ts +1744 -2
- package/dist/private-key-rpc-client.d.ts.map +1 -1
- package/dist/private-key-rpc-client.js +245 -30
- package/dist/private-key-rpc-client.js.map +1 -1
- package/dist/real-wallet-cache.d.ts +103 -0
- package/dist/real-wallet-cache.d.ts.map +1 -0
- package/dist/real-wallet-cache.js +331 -0
- package/dist/real-wallet-cache.js.map +1 -0
- package/dist/real-wallet-extension-fixtures.d.ts +35 -0
- package/dist/real-wallet-extension-fixtures.d.ts.map +1 -0
- package/dist/real-wallet-extension-fixtures.js +96 -0
- package/dist/real-wallet-extension-fixtures.js.map +1 -0
- package/dist/real-wallet-extension.d.ts +86 -0
- package/dist/real-wallet-extension.d.ts.map +1 -0
- package/dist/real-wallet-extension.js +245 -0
- package/dist/real-wallet-extension.js.map +1 -0
- package/dist/real-wallet-fixtures.d.ts +52 -0
- package/dist/real-wallet-fixtures.d.ts.map +1 -0
- package/dist/real-wallet-fixtures.js +88 -0
- package/dist/real-wallet-fixtures.js.map +1 -0
- package/dist/real-wallet.d.ts +119 -19
- package/dist/real-wallet.d.ts.map +1 -1
- package/dist/real-wallet.js +1656 -144
- package/dist/real-wallet.js.map +1 -1
- package/dist/safe.d.ts +311 -0
- package/dist/safe.d.ts.map +1 -0
- package/dist/safe.js +743 -0
- package/dist/safe.js.map +1 -0
- package/dist/transactions.d.ts +118 -0
- package/dist/transactions.d.ts.map +1 -0
- package/dist/transactions.js +207 -0
- package/dist/transactions.js.map +1 -0
- package/dist/types.d.ts +36 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/wallet-personas.d.ts +99 -0
- package/dist/wallet-personas.d.ts.map +1 -0
- package/dist/wallet-personas.js +666 -0
- package/dist/wallet-personas.js.map +1 -0
- package/dist/walletconnect.d.ts +373 -0
- package/dist/walletconnect.d.ts.map +1 -0
- package/dist/walletconnect.js +799 -0
- package/dist/walletconnect.js.map +1 -0
- package/examples/live-sepolia.spec.ts +20 -1
- package/examples/playwright.config.ts +8 -0
- package/package.json +90 -8
- package/docs/API.md +0 -223
- package/docs/ARCHITECTURE.md +0 -81
- package/docs/CONSUMING_FROM_FJORD.md +0 -123
- package/docs/FJORD_LIVE_QA.md +0 -87
- package/docs/RELEASE_CHECKLIST.md +0 -55
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"injected-provider.js","sourceRoot":"","sources":["../src/injected-provider.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,GAAG,4BAA4B,CAAC;AACjD,MAAM,YAAY,GAAG,uBAAuB,CAAC;AAE7C,MAAM,CAAC,MAAM,aAAa,GAAG,WAAW,CAAC;AACzC,MAAM,CAAC,MAAM,WAAW,GAAG,YAAY,CAAC;AAExC,MAAM,CAAC,MAAM,2BAA2B,GAAG,CAAC,MAAwB,EAAU,EAAE,CAAC;;mBAE9D,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC
|
|
1
|
+
{"version":3,"file":"injected-provider.js","sourceRoot":"","sources":["../src/injected-provider.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,GAAG,4BAA4B,CAAC;AACjD,MAAM,YAAY,GAAG,uBAAuB,CAAC;AAE7C,MAAM,CAAC,MAAM,aAAa,GAAG,WAAW,CAAC;AACzC,MAAM,CAAC,MAAM,WAAW,GAAG,YAAY,CAAC;AAExC,MAAM,CAAC,MAAM,2BAA2B,GAAG,CAAC,MAAwB,EAAU,EAAE,CAAC;;mBAE9D,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;oCAkHL,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mCAkwBZ,YAAY;;;;;;;;;;;;;sCAaT,WAAW;;;;;;;;;;;;;;;;;;;;;;CAsBhD,CAAC"}
|
package/dist/live-fixtures.d.ts
CHANGED
|
@@ -1,9 +1,38 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { Chain } from 'viem';
|
|
2
|
+
import { MockWalletController, type MockWalletControllerOptions } from './mock-wallet-controller.js';
|
|
2
3
|
import { PrivateKeyRpcClient } from './private-key-rpc-client.js';
|
|
4
|
+
export type LiveFixtureOptions = {
|
|
5
|
+
/** Target chain. Defaults to Sepolia. */
|
|
6
|
+
chain?: Chain;
|
|
7
|
+
/**
|
|
8
|
+
* Passed through to PrivateKeyRpcClient for chains that are neither
|
|
9
|
+
* `testnet: true` nor local dev chains. Without it such chains throw at
|
|
10
|
+
* fixture setup.
|
|
11
|
+
*/
|
|
12
|
+
allowMainnet?: boolean;
|
|
13
|
+
/** Env var holding the signing key. Defaults to WEB3_TESTER_PRIVATE_KEY. */
|
|
14
|
+
privateKeyEnv?: string;
|
|
15
|
+
/** Env var holding the RPC URL. Defaults to WEB3_TESTER_RPC_URL. */
|
|
16
|
+
rpcUrlEnv?: string;
|
|
17
|
+
/**
|
|
18
|
+
* Per-test overrides for the injected wallet (provider identity,
|
|
19
|
+
* autoApprove, allowedOrigins, …). Live wallets default to
|
|
20
|
+
* autoApprove: false and origin-scope the provider to baseURL; override
|
|
21
|
+
* here only for keys you are comfortable auto-signing with.
|
|
22
|
+
*/
|
|
23
|
+
walletOptions?: Omit<Partial<MockWalletControllerOptions>, 'accounts' | 'chainId'>;
|
|
24
|
+
};
|
|
3
25
|
export type LiveWeb3Fixtures = {
|
|
4
|
-
|
|
26
|
+
liveOptions: LiveFixtureOptions;
|
|
5
27
|
liveClient: PrivateKeyRpcClient;
|
|
28
|
+
wallet: MockWalletController;
|
|
6
29
|
};
|
|
30
|
+
/**
|
|
31
|
+
* Builds a live-chain fixture family. The defaults read the signing key from
|
|
32
|
+
* WEB3_TESTER_PRIVATE_KEY (with the legacy FJORD_PRIVATE_KEY still honored)
|
|
33
|
+
* and target Sepolia; pass options to bind other chains or env var names.
|
|
34
|
+
*/
|
|
35
|
+
export declare function createLiveFixtures(defaults?: LiveFixtureOptions): import("@playwright/test").TestType<import("@playwright/test").PlaywrightTestArgs & import("@playwright/test").PlaywrightTestOptions & LiveWeb3Fixtures, import("@playwright/test").PlaywrightWorkerArgs & import("@playwright/test").PlaywrightWorkerOptions>;
|
|
7
36
|
export declare const test: import("@playwright/test").TestType<import("@playwright/test").PlaywrightTestArgs & import("@playwright/test").PlaywrightTestOptions & LiveWeb3Fixtures, import("@playwright/test").PlaywrightWorkerArgs & import("@playwright/test").PlaywrightWorkerOptions>;
|
|
8
|
-
export { expect } from '
|
|
37
|
+
export { expect } from './matchers.js';
|
|
9
38
|
//# sourceMappingURL=live-fixtures.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"live-fixtures.d.ts","sourceRoot":"","sources":["../src/live-fixtures.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"live-fixtures.d.ts","sourceRoot":"","sources":["../src/live-fixtures.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,MAAM,CAAC;AAElC,OAAO,EACL,oBAAoB,EACpB,KAAK,2BAA2B,EACjC,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAElE,MAAM,MAAM,kBAAkB,GAAG;IAC/B,yCAAyC;IACzC,KAAK,CAAC,EAAE,KAAK,CAAC;IACd;;;;OAIG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,4EAA4E;IAC5E,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,oEAAoE;IACpE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;OAKG;IACH,aAAa,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,2BAA2B,CAAC,EAAE,UAAU,GAAG,SAAS,CAAC,CAAC;CACpF,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,WAAW,EAAE,kBAAkB,CAAC;IAChC,UAAU,EAAE,mBAAmB,CAAC;IAChC,MAAM,EAAE,oBAAoB,CAAC;CAC9B,CAAC;AAWF;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,GAAE,kBAAuB,kQAuDnE;AAED,eAAO,MAAM,IAAI,gQAAuB,CAAC;AAGzC,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC"}
|
package/dist/live-fixtures.js
CHANGED
|
@@ -1,33 +1,70 @@
|
|
|
1
1
|
import { test as base } from '@playwright/test';
|
|
2
2
|
import { sepolia } from 'viem/chains';
|
|
3
|
-
import { MockWalletController } from './mock-wallet-controller.js';
|
|
3
|
+
import { MockWalletController, } from './mock-wallet-controller.js';
|
|
4
4
|
import { PrivateKeyRpcClient } from './private-key-rpc-client.js';
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
throw new Error('FJORD_PRIVATE_KEY is required for live Sepolia Fjord tests.');
|
|
5
|
+
const resolveEnv = (names) => {
|
|
6
|
+
for (const name of names) {
|
|
7
|
+
if (name && process.env[name]) {
|
|
8
|
+
return process.env[name];
|
|
10
9
|
}
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
name: 'MetaMask',
|
|
25
|
-
rdns: 'io.metamask',
|
|
10
|
+
}
|
|
11
|
+
return undefined;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Builds a live-chain fixture family. The defaults read the signing key from
|
|
15
|
+
* WEB3_TESTER_PRIVATE_KEY (with the legacy FJORD_PRIVATE_KEY still honored)
|
|
16
|
+
* and target Sepolia; pass options to bind other chains or env var names.
|
|
17
|
+
*/
|
|
18
|
+
export function createLiveFixtures(defaults = {}) {
|
|
19
|
+
return base.extend({
|
|
20
|
+
liveOptions: [
|
|
21
|
+
async ({}, use) => {
|
|
22
|
+
await use(defaults);
|
|
26
23
|
},
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
24
|
+
{ option: true },
|
|
25
|
+
],
|
|
26
|
+
liveClient: async ({ liveOptions }, use) => {
|
|
27
|
+
const options = { ...defaults, ...liveOptions };
|
|
28
|
+
const privateKeyEnv = options.privateKeyEnv ?? 'WEB3_TESTER_PRIVATE_KEY';
|
|
29
|
+
const privateKey = resolveEnv([privateKeyEnv, 'FJORD_PRIVATE_KEY']);
|
|
30
|
+
if (!privateKey) {
|
|
31
|
+
throw new Error(`${privateKeyEnv} is required for live-chain tests.`);
|
|
32
|
+
}
|
|
33
|
+
const rpcUrlEnv = options.rpcUrlEnv ?? 'WEB3_TESTER_RPC_URL';
|
|
34
|
+
await use(new PrivateKeyRpcClient({
|
|
35
|
+
privateKey: privateKey,
|
|
36
|
+
chain: options.chain ?? sepolia,
|
|
37
|
+
rpcUrl: resolveEnv([rpcUrlEnv, 'SEPOLIA_RPC_URL']),
|
|
38
|
+
allowMainnet: options.allowMainnet,
|
|
39
|
+
}));
|
|
40
|
+
},
|
|
41
|
+
wallet: async ({ page, liveClient, liveOptions, baseURL }, use) => {
|
|
42
|
+
const options = { ...defaults, ...liveOptions };
|
|
43
|
+
const wallet = new MockWalletController(page, liveClient, {
|
|
44
|
+
accounts: [liveClient.account.address],
|
|
45
|
+
chainId: liveClient.chain.id,
|
|
46
|
+
// A real key sits behind this provider, so nothing signs or connects
|
|
47
|
+
// until the test arms it (wallet.approveNext(...) for one request,
|
|
48
|
+
// wallet.autoApprove(true) or walletOptions for a whole test), and
|
|
49
|
+
// only frames on the dapp's own origin can reach the wallet at all.
|
|
50
|
+
autoApprove: false,
|
|
51
|
+
connected: true,
|
|
52
|
+
// EIP-5792 stays off over a real key: capability-probing dapps keep
|
|
53
|
+
// the eth_sendTransaction fallback with per-transaction arming,
|
|
54
|
+
// capping a bare approveNext() at one real transaction.
|
|
55
|
+
eip5792: false,
|
|
56
|
+
...(baseURL ? { allowedOrigins: [baseURL] } : {}),
|
|
57
|
+
// Masquerade as MetaMask by default so production wallet selectors
|
|
58
|
+
// (wagmi / EIP-6963) detect the injected provider unmodified.
|
|
59
|
+
providerInfo: { name: 'MetaMask', rdns: 'io.metamask' },
|
|
60
|
+
...options.walletOptions,
|
|
61
|
+
});
|
|
62
|
+
await wallet.injectMockProvider();
|
|
63
|
+
await use(wallet);
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
export const test = createLiveFixtures();
|
|
68
|
+
// The web3-extended expect: every matcher from ./matchers.js, zero migration.
|
|
69
|
+
export { expect } from './matchers.js';
|
|
33
70
|
//# sourceMappingURL=live-fixtures.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"live-fixtures.js","sourceRoot":"","sources":["../src/live-fixtures.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,IAAI,IAAI,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"live-fixtures.js","sourceRoot":"","sources":["../src/live-fixtures.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { type ExpectMatcherState } from '@playwright/test';
|
|
2
|
+
import { type Abi, type Address } from 'viem';
|
|
3
|
+
import { type ChainLike, type RevertTarget, type TransactionTarget } from './transactions.js';
|
|
4
|
+
type MatcherResult = {
|
|
5
|
+
pass: boolean;
|
|
6
|
+
message: () => string;
|
|
7
|
+
expected?: unknown;
|
|
8
|
+
actual?: unknown;
|
|
9
|
+
};
|
|
10
|
+
/** Named or positional; positional `undefined` = wildcard; values may be predicates. */
|
|
11
|
+
export type EventArgsExpectation = Record<string, unknown> | readonly unknown[];
|
|
12
|
+
export type EventMatchOptions = {
|
|
13
|
+
args?: EventArgsExpectation;
|
|
14
|
+
/** Restrict to events emitted by this contract. */
|
|
15
|
+
address?: Address;
|
|
16
|
+
/** Exact number of matching events; default passes on >= 1 (and `.not` asserts zero). */
|
|
17
|
+
count?: number;
|
|
18
|
+
timeout?: number;
|
|
19
|
+
};
|
|
20
|
+
export type BalanceChange = {
|
|
21
|
+
address: Address;
|
|
22
|
+
delta: bigint | number | string;
|
|
23
|
+
};
|
|
24
|
+
/** hardhat-chai-matchers `anyValue` parity for arg wildcards. */
|
|
25
|
+
export declare const anyValue: (_value: unknown) => boolean;
|
|
26
|
+
export declare const web3Matchers: {
|
|
27
|
+
toEmitEvent(this: ExpectMatcherState, target: TransactionTarget, chain: ChainLike, abi: Abi, eventName: string, options?: EventMatchOptions): Promise<MatcherResult>;
|
|
28
|
+
toChangeBalance(this: ExpectMatcherState, target: TransactionTarget, chain: ChainLike, address: Address, delta: bigint | number | string, options?: {
|
|
29
|
+
includeFee?: boolean;
|
|
30
|
+
timeout?: number;
|
|
31
|
+
}): Promise<MatcherResult>;
|
|
32
|
+
toChangeBalances(this: ExpectMatcherState, target: TransactionTarget, chain: ChainLike, changes: readonly BalanceChange[], options?: {
|
|
33
|
+
includeFee?: boolean;
|
|
34
|
+
timeout?: number;
|
|
35
|
+
}): Promise<MatcherResult>;
|
|
36
|
+
toChangeTokenBalance(this: ExpectMatcherState, target: TransactionTarget, chain: ChainLike, token: Address, address: Address, delta: bigint | number | string, options?: {
|
|
37
|
+
timeout?: number;
|
|
38
|
+
}): Promise<MatcherResult>;
|
|
39
|
+
toChangeTokenBalances(this: ExpectMatcherState, target: TransactionTarget, chain: ChainLike, token: Address, changes: readonly BalanceChange[], options?: {
|
|
40
|
+
timeout?: number;
|
|
41
|
+
}): Promise<MatcherResult>;
|
|
42
|
+
toBeReverted(this: ExpectMatcherState, target: RevertTarget, chain: ChainLike, options?: {
|
|
43
|
+
timeout?: number;
|
|
44
|
+
}): Promise<MatcherResult>;
|
|
45
|
+
toBeRevertedWith(this: ExpectMatcherState, target: RevertTarget, chain: ChainLike, reason: string | RegExp, options?: {
|
|
46
|
+
timeout?: number;
|
|
47
|
+
}): Promise<MatcherResult>;
|
|
48
|
+
toBeRevertedWithCustomError(this: ExpectMatcherState, target: RevertTarget, chain: ChainLike, abi: Abi, errorName: string, options?: {
|
|
49
|
+
args?: readonly unknown[];
|
|
50
|
+
timeout?: number;
|
|
51
|
+
}): Promise<MatcherResult>;
|
|
52
|
+
toBeRevertedWithPanic(this: ExpectMatcherState, target: RevertTarget, chain: ChainLike, code?: bigint | number, options?: {
|
|
53
|
+
timeout?: number;
|
|
54
|
+
}): Promise<MatcherResult>;
|
|
55
|
+
toHaveTokenBalance(this: ExpectMatcherState, holder: Address, chain: ChainLike, token: Address, expected: bigint | number | string | ((balance: bigint) => boolean)): Promise<MatcherResult>;
|
|
56
|
+
};
|
|
57
|
+
/** Pre-extended expect carrying every web3 matcher, fully typed. */
|
|
58
|
+
export declare const expect: import("@playwright/test").Expect<{
|
|
59
|
+
toEmitEvent(this: ExpectMatcherState, target: TransactionTarget, chain: ChainLike, abi: Abi, eventName: string, options?: EventMatchOptions): Promise<MatcherResult>;
|
|
60
|
+
toChangeBalance(this: ExpectMatcherState, target: TransactionTarget, chain: ChainLike, address: Address, delta: bigint | number | string, options?: {
|
|
61
|
+
includeFee?: boolean;
|
|
62
|
+
timeout?: number;
|
|
63
|
+
}): Promise<MatcherResult>;
|
|
64
|
+
toChangeBalances(this: ExpectMatcherState, target: TransactionTarget, chain: ChainLike, changes: readonly BalanceChange[], options?: {
|
|
65
|
+
includeFee?: boolean;
|
|
66
|
+
timeout?: number;
|
|
67
|
+
}): Promise<MatcherResult>;
|
|
68
|
+
toChangeTokenBalance(this: ExpectMatcherState, target: TransactionTarget, chain: ChainLike, token: Address, address: Address, delta: bigint | number | string, options?: {
|
|
69
|
+
timeout?: number;
|
|
70
|
+
}): Promise<MatcherResult>;
|
|
71
|
+
toChangeTokenBalances(this: ExpectMatcherState, target: TransactionTarget, chain: ChainLike, token: Address, changes: readonly BalanceChange[], options?: {
|
|
72
|
+
timeout?: number;
|
|
73
|
+
}): Promise<MatcherResult>;
|
|
74
|
+
toBeReverted(this: ExpectMatcherState, target: RevertTarget, chain: ChainLike, options?: {
|
|
75
|
+
timeout?: number;
|
|
76
|
+
}): Promise<MatcherResult>;
|
|
77
|
+
toBeRevertedWith(this: ExpectMatcherState, target: RevertTarget, chain: ChainLike, reason: string | RegExp, options?: {
|
|
78
|
+
timeout?: number;
|
|
79
|
+
}): Promise<MatcherResult>;
|
|
80
|
+
toBeRevertedWithCustomError(this: ExpectMatcherState, target: RevertTarget, chain: ChainLike, abi: Abi, errorName: string, options?: {
|
|
81
|
+
args?: readonly unknown[];
|
|
82
|
+
timeout?: number;
|
|
83
|
+
}): Promise<MatcherResult>;
|
|
84
|
+
toBeRevertedWithPanic(this: ExpectMatcherState, target: RevertTarget, chain: ChainLike, code?: bigint | number, options?: {
|
|
85
|
+
timeout?: number;
|
|
86
|
+
}): Promise<MatcherResult>;
|
|
87
|
+
toHaveTokenBalance(this: ExpectMatcherState, holder: Address, chain: ChainLike, token: Address, expected: bigint | number | string | ((balance: bigint) => boolean)): Promise<MatcherResult>;
|
|
88
|
+
}>;
|
|
89
|
+
export {};
|
|
90
|
+
//# sourceMappingURL=matchers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"matchers.d.ts","sourceRoot":"","sources":["../src/matchers.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,kBAAkB,EACxB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAA4B,KAAK,GAAG,EAAE,KAAK,OAAO,EAAY,MAAM,MAAM,CAAC;AAClF,OAAO,EAUL,KAAK,SAAS,EAGd,KAAK,YAAY,EACjB,KAAK,iBAAiB,EACvB,MAAM,mBAAmB,CAAC;AAE3B,KAAK,aAAa,GAAG;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AAEpG,wFAAwF;AACxF,MAAM,MAAM,oBAAoB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,OAAO,EAAE,CAAC;AAChF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,CAAC,EAAE,oBAAoB,CAAC;IAC5B,mDAAmD;IACnD,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,yFAAyF;IACzF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AACF,MAAM,MAAM,aAAa,GAAG;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAAA;CAAE,CAAC;AAElF,iEAAiE;AACjE,eAAO,MAAM,QAAQ,GAAI,QAAQ,OAAO,KAAG,OAAe,CAAC;AAiL3D,eAAO,MAAM,YAAY;sBAEf,kBAAkB,UAChB,iBAAiB,SAClB,SAAS,OACX,GAAG,aACG,MAAM,YACR,iBAAiB,GACzB,OAAO,CAAC,aAAa,CAAC;0BAsDjB,kBAAkB,UAChB,iBAAiB,SAClB,SAAS,WACP,OAAO,SACT,MAAM,GAAG,MAAM,GAAG,MAAM,YACtB;QAAE,UAAU,CAAC,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAClD,OAAO,CAAC,aAAa,CAAC;2BAcjB,kBAAkB,UAChB,iBAAiB,SAClB,SAAS,WACP,SAAS,aAAa,EAAE,YACxB;QAAE,UAAU,CAAC,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAClD,OAAO,CAAC,aAAa,CAAC;+BAcjB,kBAAkB,UAChB,iBAAiB,SAClB,SAAS,SACT,OAAO,WACL,OAAO,SACT,MAAM,GAAG,MAAM,GAAG,MAAM,YACtB;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAC5B,OAAO,CAAC,aAAa,CAAC;gCAcjB,kBAAkB,UAChB,iBAAiB,SAClB,SAAS,SACT,OAAO,WACL,SAAS,aAAa,EAAE,YACxB;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAC5B,OAAO,CAAC,aAAa,CAAC;uBAcjB,kBAAkB,UAChB,YAAY,SACb,SAAS,YACP;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAC5B,OAAO,CAAC,aAAa,CAAC;2BAkBjB,kBAAkB,UAChB,YAAY,SACb,SAAS,UACR,MAAM,GAAG,MAAM,YACd;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAC5B,OAAO,CAAC,aAAa,CAAC;sCA8BjB,kBAAkB,UAChB,YAAY,SACb,SAAS,OACX,GAAG,aACG,MAAM,YACR;QAAE,IAAI,CAAC,EAAE,SAAS,OAAO,EAAE,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GACvD,OAAO,CAAC,aAAa,CAAC;gCAgCjB,kBAAkB,UAChB,YAAY,SACb,SAAS,SACT,MAAM,GAAG,MAAM,YACb;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAC5B,OAAO,CAAC,aAAa,CAAC;6BA2BjB,kBAAkB,UAChB,OAAO,SACR,SAAS,SACT,OAAO,YACJ,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,CAAC,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,GAClE,OAAO,CAAC,aAAa,CAAC;CAgC1B,CAAC;AAEF,oEAAoE;AACpE,eAAO,MAAM,MAAM;sBAnTT,kBAAkB,UAChB,iBAAiB,SAClB,SAAS,OACX,GAAG,aACG,MAAM,YACR,iBAAiB,GACzB,OAAO,CAAC,aAAa,CAAC;0BAsDjB,kBAAkB,UAChB,iBAAiB,SAClB,SAAS,WACP,OAAO,SACT,MAAM,GAAG,MAAM,GAAG,MAAM,YACtB;QAAE,UAAU,CAAC,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAClD,OAAO,CAAC,aAAa,CAAC;2BAcjB,kBAAkB,UAChB,iBAAiB,SAClB,SAAS,WACP,SAAS,aAAa,EAAE,YACxB;QAAE,UAAU,CAAC,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAClD,OAAO,CAAC,aAAa,CAAC;+BAcjB,kBAAkB,UAChB,iBAAiB,SAClB,SAAS,SACT,OAAO,WACL,OAAO,SACT,MAAM,GAAG,MAAM,GAAG,MAAM,YACtB;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAC5B,OAAO,CAAC,aAAa,CAAC;gCAcjB,kBAAkB,UAChB,iBAAiB,SAClB,SAAS,SACT,OAAO,WACL,SAAS,aAAa,EAAE,YACxB;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAC5B,OAAO,CAAC,aAAa,CAAC;uBAcjB,kBAAkB,UAChB,YAAY,SACb,SAAS,YACP;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAC5B,OAAO,CAAC,aAAa,CAAC;2BAkBjB,kBAAkB,UAChB,YAAY,SACb,SAAS,UACR,MAAM,GAAG,MAAM,YACd;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAC5B,OAAO,CAAC,aAAa,CAAC;sCA8BjB,kBAAkB,UAChB,YAAY,SACb,SAAS,OACX,GAAG,aACG,MAAM,YACR;QAAE,IAAI,CAAC,EAAE,SAAS,OAAO,EAAE,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GACvD,OAAO,CAAC,aAAa,CAAC;gCAgCjB,kBAAkB,UAChB,YAAY,SACb,SAAS,SACT,MAAM,GAAG,MAAM,YACb;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAC5B,OAAO,CAAC,aAAa,CAAC;6BA2BjB,kBAAkB,UAChB,OAAO,SACR,SAAS,SACT,OAAO,YACJ,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,CAAC,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,GAClE,OAAO,CAAC,aAAa,CAAC;EAmC0B,CAAC"}
|
package/dist/matchers.js
ADDED
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
import { expect as baseExpect, } from '@playwright/test';
|
|
2
|
+
import { erc20Abi, parseEventLogs } from 'viem';
|
|
3
|
+
import { describePanic, extractRevertInfo, isWalletRejectionError, recoverRevertInfo, renderRevertInfo, resolveClient, resolveTxHash, web3Equals, web3Stringify, } from './transactions.js';
|
|
4
|
+
/** hardhat-chai-matchers `anyValue` parity for arg wildcards. */
|
|
5
|
+
export const anyValue = (_value) => true;
|
|
6
|
+
const ADDRESS_PATTERN = /^0x[0-9a-fA-F]{40}$/;
|
|
7
|
+
const toBigInt = (value) => typeof value === 'bigint' ? value : BigInt(value);
|
|
8
|
+
const badReceiver = (state, name, received) => ({
|
|
9
|
+
pass: false,
|
|
10
|
+
message: () => `${state.utils.matcherHint(name, undefined, undefined, { isNot: state.isNot })}\n\n` +
|
|
11
|
+
`Received value is not a transaction hash (or { hash }): ${web3Stringify(received)}`,
|
|
12
|
+
});
|
|
13
|
+
const eventArgsMatch = (logArgs, expectation, abi, eventName) => {
|
|
14
|
+
if (Array.isArray(expectation)) {
|
|
15
|
+
const positional = Array.isArray(logArgs)
|
|
16
|
+
? [...logArgs]
|
|
17
|
+
: (() => {
|
|
18
|
+
const event = abi.find((entry) => entry.type === 'event' && 'name' in entry && entry.name === eventName);
|
|
19
|
+
return (event?.inputs ?? []).map((input, index) => input.name
|
|
20
|
+
? logArgs[input.name]
|
|
21
|
+
: logArgs[index]);
|
|
22
|
+
})();
|
|
23
|
+
return expectation.every((expected, index) => expected === undefined || web3Equals(expected, positional[index]));
|
|
24
|
+
}
|
|
25
|
+
const named = (logArgs ?? {});
|
|
26
|
+
return Object.entries(expectation).every(([key, expected]) => web3Equals(expected, named[key]));
|
|
27
|
+
};
|
|
28
|
+
// Resolves a revert-family receiver into a uniform shape; wallet approval
|
|
29
|
+
// failures are rethrown with a hint instead of counting as reverts.
|
|
30
|
+
const resolveRevertReceiver = async (target, client, timeout, abi) => {
|
|
31
|
+
let resolved;
|
|
32
|
+
try {
|
|
33
|
+
resolved = typeof target === 'function' ? await target() : await target;
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
if (isWalletRejectionError(error)) {
|
|
37
|
+
throw new Error(`The wallet rejected the request — a wallet approval failure, not a chain revert: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
|
|
38
|
+
}
|
|
39
|
+
const info = extractRevertInfo(error, abi);
|
|
40
|
+
if (!info) {
|
|
41
|
+
throw new Error(`The call rejected with a non-revert error: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
|
|
42
|
+
}
|
|
43
|
+
return { outcome: 'reverted', info };
|
|
44
|
+
}
|
|
45
|
+
const hash = await resolveTxHash(resolved);
|
|
46
|
+
if (!hash) {
|
|
47
|
+
return {
|
|
48
|
+
outcome: 'succeeded',
|
|
49
|
+
detail: `the call succeeded and resolved to ${web3Stringify(resolved)}`,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
const receipt = await client.waitForTransactionReceipt({ hash, timeout });
|
|
53
|
+
if (receipt.status === 'success') {
|
|
54
|
+
return {
|
|
55
|
+
outcome: 'succeeded',
|
|
56
|
+
detail: `transaction ${hash} succeeded (gasUsed ${receipt.gasUsed})`,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
outcome: 'reverted',
|
|
61
|
+
info: await recoverRevertInfo(client, hash, receipt, abi),
|
|
62
|
+
gasUsed: receipt.gasUsed,
|
|
63
|
+
};
|
|
64
|
+
};
|
|
65
|
+
const balanceChangeMatcher = async (state, name, target, chain, changes, options, readBalance, feeAdjustable) => {
|
|
66
|
+
const client = resolveClient(chain);
|
|
67
|
+
const hash = await resolveTxHash(target);
|
|
68
|
+
if (!hash) {
|
|
69
|
+
return badReceiver(state, name, await target);
|
|
70
|
+
}
|
|
71
|
+
const receipt = await client.waitForTransactionReceipt({
|
|
72
|
+
hash,
|
|
73
|
+
timeout: options.timeout ?? state.timeout,
|
|
74
|
+
});
|
|
75
|
+
const observed = [];
|
|
76
|
+
for (const change of changes) {
|
|
77
|
+
const after = await readBalance(client, change.address, receipt.blockNumber);
|
|
78
|
+
const before = await readBalance(client, change.address, receipt.blockNumber - 1n);
|
|
79
|
+
let delta = after - before;
|
|
80
|
+
// hardhat parity: the sender's gas fee is excluded unless includeFee.
|
|
81
|
+
if (feeAdjustable &&
|
|
82
|
+
!options.includeFee &&
|
|
83
|
+
change.address.toLowerCase() === receipt.from.toLowerCase()) {
|
|
84
|
+
delta += receipt.gasUsed * receipt.effectiveGasPrice;
|
|
85
|
+
}
|
|
86
|
+
observed.push({ address: change.address, expected: toBigInt(change.delta), actual: delta });
|
|
87
|
+
}
|
|
88
|
+
const pass = observed.every((entry) => entry.expected === entry.actual);
|
|
89
|
+
const message = async () => {
|
|
90
|
+
const lines = observed.map((entry) => ` ${entry.address}: expected ${entry.expected}, observed ${entry.actual}${entry.expected === entry.actual ? '' : ' ←'}`);
|
|
91
|
+
const block = await client.getBlock({ blockNumber: receipt.blockNumber }).catch(() => undefined);
|
|
92
|
+
const crowded = block && block.transactions.length > 1
|
|
93
|
+
? `\n${block.transactions.length - 1} other transaction(s) share this block and may also have moved balances.`
|
|
94
|
+
: '';
|
|
95
|
+
return (`${state.utils.matcherHint(name, undefined, undefined, { isNot: state.isNot })}\n\n` +
|
|
96
|
+
`Transaction ${hash} (block ${receipt.blockNumber}):\n${lines.join('\n')}${crowded}`);
|
|
97
|
+
};
|
|
98
|
+
const rendered = await message();
|
|
99
|
+
return {
|
|
100
|
+
pass,
|
|
101
|
+
message: () => rendered,
|
|
102
|
+
expected: observed.map((entry) => `${entry.address}: ${entry.expected}`),
|
|
103
|
+
actual: observed.map((entry) => `${entry.address}: ${entry.actual}`),
|
|
104
|
+
};
|
|
105
|
+
};
|
|
106
|
+
const erc20Balance = (token) => async (client, address, blockNumber) => (await client.readContract({
|
|
107
|
+
address: token,
|
|
108
|
+
abi: erc20Abi,
|
|
109
|
+
functionName: 'balanceOf',
|
|
110
|
+
args: [address],
|
|
111
|
+
blockNumber,
|
|
112
|
+
}));
|
|
113
|
+
export const web3Matchers = {
|
|
114
|
+
async toEmitEvent(target, chain, abi, eventName, options = {}) {
|
|
115
|
+
const client = resolveClient(chain);
|
|
116
|
+
const hash = await resolveTxHash(target);
|
|
117
|
+
if (!hash) {
|
|
118
|
+
return badReceiver(this, 'toEmitEvent', await target);
|
|
119
|
+
}
|
|
120
|
+
const receipt = await client.waitForTransactionReceipt({
|
|
121
|
+
hash,
|
|
122
|
+
timeout: options.timeout ?? this.timeout,
|
|
123
|
+
});
|
|
124
|
+
const decoded = parseEventLogs({ abi, logs: receipt.logs, strict: false });
|
|
125
|
+
// parseEventLogs silently drops foreign-topic0 logs; surface them by diff.
|
|
126
|
+
const decodedIndexes = new Set(decoded.map((log) => log.logIndex));
|
|
127
|
+
const undecodable = receipt.logs.filter((log) => !decodedIndexes.has(log.logIndex));
|
|
128
|
+
let candidates = decoded.filter((log) => log.eventName === eventName);
|
|
129
|
+
if (options.address) {
|
|
130
|
+
candidates = candidates.filter((log) => log.address.toLowerCase() === options.address.toLowerCase());
|
|
131
|
+
}
|
|
132
|
+
const matching = options.args === undefined
|
|
133
|
+
? candidates
|
|
134
|
+
: candidates.filter((log) => eventArgsMatch(log.args, options.args, abi, eventName));
|
|
135
|
+
const pass = options.count !== undefined ? matching.length === options.count : matching.length >= 1;
|
|
136
|
+
const emitted = decoded.map((log) => ` ${log.eventName}(${web3Stringify(log.args).replace(/\n\s*/g, ' ')}) @ ${log.address}`);
|
|
137
|
+
const extras = undecodable.map((log) => ` <undecodable> topic0=${log.topics[0]} @ ${log.address}`);
|
|
138
|
+
const revertedNote = receipt.status !== 'success'
|
|
139
|
+
? '\nThe transaction REVERTED — reverted transactions emit no events.'
|
|
140
|
+
: '';
|
|
141
|
+
return {
|
|
142
|
+
pass,
|
|
143
|
+
message: () => `${this.utils.matcherHint('toEmitEvent', undefined, eventName, { isNot: this.isNot })}\n\n` +
|
|
144
|
+
`Expected ${options.count !== undefined ? `exactly ${options.count}` : 'at least one'} ` +
|
|
145
|
+
`"${eventName}" event${options.args ? ` with args ${web3Stringify(options.args)}` : ''}; ` +
|
|
146
|
+
`found ${matching.length}.${revertedNote}\n` +
|
|
147
|
+
`Events in receipt:\n${[...emitted, ...extras].join('\n') || ' (none)'}`,
|
|
148
|
+
expected: options.args,
|
|
149
|
+
actual: candidates.map((log) => log.args),
|
|
150
|
+
};
|
|
151
|
+
},
|
|
152
|
+
async toChangeBalance(target, chain, address, delta, options = {}) {
|
|
153
|
+
return balanceChangeMatcher(this, 'toChangeBalance', target, chain, [{ address, delta }], options, (client, holder, blockNumber) => client.getBalance({ address: holder, blockNumber }), true);
|
|
154
|
+
},
|
|
155
|
+
async toChangeBalances(target, chain, changes, options = {}) {
|
|
156
|
+
return balanceChangeMatcher(this, 'toChangeBalances', target, chain, changes, options, (client, holder, blockNumber) => client.getBalance({ address: holder, blockNumber }), true);
|
|
157
|
+
},
|
|
158
|
+
async toChangeTokenBalance(target, chain, token, address, delta, options = {}) {
|
|
159
|
+
return balanceChangeMatcher(this, 'toChangeTokenBalance', target, chain, [{ address, delta }], options, erc20Balance(token), false);
|
|
160
|
+
},
|
|
161
|
+
async toChangeTokenBalances(target, chain, token, changes, options = {}) {
|
|
162
|
+
return balanceChangeMatcher(this, 'toChangeTokenBalances', target, chain, changes, options, erc20Balance(token), false);
|
|
163
|
+
},
|
|
164
|
+
async toBeReverted(target, chain, options = {}) {
|
|
165
|
+
const result = await resolveRevertReceiver(target, resolveClient(chain), options.timeout ?? this.timeout, undefined);
|
|
166
|
+
return {
|
|
167
|
+
pass: result.outcome === 'reverted',
|
|
168
|
+
message: () => `${this.utils.matcherHint('toBeReverted', undefined, undefined, { isNot: this.isNot })}\n\n` +
|
|
169
|
+
(result.outcome === 'reverted'
|
|
170
|
+
? `Reverted with ${renderRevertInfo(result.info)}.`
|
|
171
|
+
: `Expected a revert, but ${result.detail}.`),
|
|
172
|
+
};
|
|
173
|
+
},
|
|
174
|
+
async toBeRevertedWith(target, chain, reason, options = {}) {
|
|
175
|
+
const result = await resolveRevertReceiver(target, resolveClient(chain), options.timeout ?? this.timeout, undefined);
|
|
176
|
+
let pass = false;
|
|
177
|
+
let detail;
|
|
178
|
+
if (result.outcome === 'succeeded') {
|
|
179
|
+
detail = `Expected a revert, but ${result.detail}.`;
|
|
180
|
+
}
|
|
181
|
+
else if (result.info.kind === 'reason') {
|
|
182
|
+
pass =
|
|
183
|
+
typeof reason === 'string' ? result.info.reason === reason : reason.test(result.info.reason);
|
|
184
|
+
detail = `Reverted with Error("${result.info.reason}").`;
|
|
185
|
+
}
|
|
186
|
+
else {
|
|
187
|
+
detail = `Reverted, but not with an Error(string): ${renderRevertInfo(result.info)}.`;
|
|
188
|
+
}
|
|
189
|
+
return {
|
|
190
|
+
pass,
|
|
191
|
+
message: () => `${this.utils.matcherHint('toBeRevertedWith', undefined, String(reason), { isNot: this.isNot })}\n\n${detail}`,
|
|
192
|
+
expected: String(reason),
|
|
193
|
+
actual: result.outcome === 'reverted' ? renderRevertInfo(result.info) : 'success',
|
|
194
|
+
};
|
|
195
|
+
},
|
|
196
|
+
async toBeRevertedWithCustomError(target, chain, abi, errorName, options = {}) {
|
|
197
|
+
const result = await resolveRevertReceiver(target, resolveClient(chain), options.timeout ?? this.timeout, abi);
|
|
198
|
+
let pass = false;
|
|
199
|
+
let detail;
|
|
200
|
+
if (result.outcome === 'succeeded') {
|
|
201
|
+
detail = `Expected a revert, but ${result.detail}.`;
|
|
202
|
+
}
|
|
203
|
+
else if (result.info.kind === 'custom') {
|
|
204
|
+
pass =
|
|
205
|
+
result.info.errorName === errorName &&
|
|
206
|
+
(options.args === undefined ||
|
|
207
|
+
web3Equals([...options.args], [...(result.info.args ?? [])]));
|
|
208
|
+
detail = `Reverted with ${renderRevertInfo(result.info)}.`;
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
detail = `Reverted, but not with a custom error: ${renderRevertInfo(result.info)}.`;
|
|
212
|
+
}
|
|
213
|
+
return {
|
|
214
|
+
pass,
|
|
215
|
+
message: () => `${this.utils.matcherHint('toBeRevertedWithCustomError', undefined, errorName, { isNot: this.isNot })}\n\n${detail}`,
|
|
216
|
+
expected: `${errorName}(${(options.args ?? []).map(String).join(', ')})`,
|
|
217
|
+
actual: result.outcome === 'reverted' ? renderRevertInfo(result.info) : 'success',
|
|
218
|
+
};
|
|
219
|
+
},
|
|
220
|
+
async toBeRevertedWithPanic(target, chain, code, options = {}) {
|
|
221
|
+
const result = await resolveRevertReceiver(target, resolveClient(chain), options.timeout ?? this.timeout, undefined);
|
|
222
|
+
let pass = false;
|
|
223
|
+
let detail;
|
|
224
|
+
if (result.outcome === 'succeeded') {
|
|
225
|
+
detail = `Expected a panic, but ${result.detail}.`;
|
|
226
|
+
}
|
|
227
|
+
else if (result.info.kind === 'panic') {
|
|
228
|
+
pass = code === undefined || BigInt(code) === result.info.code;
|
|
229
|
+
detail = `Reverted with ${renderRevertInfo(result.info)}.`;
|
|
230
|
+
}
|
|
231
|
+
else {
|
|
232
|
+
detail = `Reverted, but not with a Panic: ${renderRevertInfo(result.info)}.`;
|
|
233
|
+
}
|
|
234
|
+
return {
|
|
235
|
+
pass,
|
|
236
|
+
message: () => `${this.utils.matcherHint('toBeRevertedWithPanic', undefined, code === undefined ? '' : `0x${BigInt(code).toString(16)} (${describePanic(BigInt(code))})`, { isNot: this.isNot })}\n\n${detail}`,
|
|
237
|
+
};
|
|
238
|
+
},
|
|
239
|
+
async toHaveTokenBalance(holder, chain, token, expected) {
|
|
240
|
+
// Address and tx-hash are both `0x${string}` — catch 32-byte receivers.
|
|
241
|
+
if (typeof holder !== 'string' || !ADDRESS_PATTERN.test(holder)) {
|
|
242
|
+
return {
|
|
243
|
+
pass: false,
|
|
244
|
+
message: () => `${this.utils.matcherHint('toHaveTokenBalance', undefined, undefined, { isNot: this.isNot })}\n\n` +
|
|
245
|
+
`Received value is not a 20-byte address: ${web3Stringify(holder)}`,
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
const client = resolveClient(chain);
|
|
249
|
+
const balance = (await client.readContract({
|
|
250
|
+
address: token,
|
|
251
|
+
abi: erc20Abi,
|
|
252
|
+
functionName: 'balanceOf',
|
|
253
|
+
args: [holder],
|
|
254
|
+
}));
|
|
255
|
+
const pass = typeof expected === 'function' ? Boolean(expected(balance)) : toBigInt(expected) === balance;
|
|
256
|
+
return {
|
|
257
|
+
pass,
|
|
258
|
+
message: () => `${this.utils.matcherHint('toHaveTokenBalance', undefined, undefined, { isNot: this.isNot })}\n\n` +
|
|
259
|
+
`Token ${token} balance of ${holder}: ${balance}` +
|
|
260
|
+
(typeof expected === 'function' ? ' (predicate)' : `, expected ${toBigInt(expected)}`),
|
|
261
|
+
expected: typeof expected === 'function' ? 'predicate' : toBigInt(expected).toString(),
|
|
262
|
+
actual: balance.toString(),
|
|
263
|
+
};
|
|
264
|
+
},
|
|
265
|
+
};
|
|
266
|
+
/** Pre-extended expect carrying every web3 matcher, fully typed. */
|
|
267
|
+
export const expect = baseExpect.extend(web3Matchers);
|
|
268
|
+
//# sourceMappingURL=matchers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"matchers.js","sourceRoot":"","sources":["../src/matchers.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The MetaMask build the adapter's selectors are maintained against. Bump
|
|
3
|
+
* deliberately and re-run the real-wallet smoke suite when changing it
|
|
4
|
+
* (`npm run smoke:real-wallet`).
|
|
5
|
+
*
|
|
6
|
+
* The adapter drives one UI generation per launch as explicit configuration
|
|
7
|
+
* (derived from the extension manifest, overridable via the `generation`
|
|
8
|
+
* option): 13.x (the "multichain" UI) is validated end to end and gates
|
|
9
|
+
* releases; the last 12.x line stays supported on a best-effort cadence. Set
|
|
10
|
+
* WEB3_TESTER_METAMASK_VERSION=12.23.1 to drive the older generation.
|
|
11
|
+
*/
|
|
12
|
+
export declare const DEFAULT_METAMASK_VERSION = "13.34.1";
|
|
13
|
+
export type PrepareMetaMaskExtensionOptions = {
|
|
14
|
+
/** Release version, e.g. "13.34.1". Defaults to WEB3_TESTER_METAMASK_VERSION or the pinned default. */
|
|
15
|
+
version?: string;
|
|
16
|
+
/** Directory unpacked extensions are cached in. Defaults to ~/.cache/web3-tester/metamask. */
|
|
17
|
+
cacheDir?: string;
|
|
18
|
+
/** Full download URL override (e.g. an internal mirror). */
|
|
19
|
+
downloadUrl?: string;
|
|
20
|
+
/** Optional sha256 (hex) of the zip for integrity verification. */
|
|
21
|
+
sha256?: string;
|
|
22
|
+
/** Re-download even if a cached copy exists. */
|
|
23
|
+
force?: boolean;
|
|
24
|
+
};
|
|
25
|
+
export declare const defaultExtensionCacheDir: () => string;
|
|
26
|
+
/**
|
|
27
|
+
* Downloads and unpacks a pinned MetaMask release into a local cache and
|
|
28
|
+
* returns the unpacked extension directory, suitable for
|
|
29
|
+
* launchRealWallet({ extensionPath }). Subsequent calls hit the cache.
|
|
30
|
+
*/
|
|
31
|
+
export declare function prepareMetaMaskExtension(options?: PrepareMetaMaskExtensionOptions): Promise<string>;
|
|
32
|
+
/** Reads the version field of an unpacked extension's manifest.json. */
|
|
33
|
+
export declare function extensionManifestVersion(extensionPath: string): string;
|
|
34
|
+
//# sourceMappingURL=metamask-extension.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metamask-extension.d.ts","sourceRoot":"","sources":["../src/metamask-extension.ts"],"names":[],"mappings":"AAOA;;;;;;;;;;GAUG;AACH,eAAO,MAAM,wBAAwB,YAAY,CAAC;AAElD,MAAM,MAAM,+BAA+B,GAAG;IAC5C,uGAAuG;IACvG,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,8FAA8F;IAC9F,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,4DAA4D;IAC5D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mEAAmE;IACnE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gDAAgD;IAChD,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,CAAC;AAEF,eAAO,MAAM,wBAAwB,QAAO,MACkB,CAAC;AA0B/D;;;;GAIG;AACH,wBAAsB,wBAAwB,CAC5C,OAAO,GAAE,+BAAoC,GAC5C,OAAO,CAAC,MAAM,CAAC,CAuDjB;AAED,wEAAwE;AACxE,wBAAgB,wBAAwB,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,CAOtE"}
|