@marigoldlabs/web3-tester 0.1.2 → 0.4.1
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 +167 -41
- 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/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 +17 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -1
- package/dist/index.js.map +1 -1
- package/dist/injected-provider.d.ts.map +1 -1
- package/dist/injected-provider.js +142 -79
- 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 +205 -3
- package/dist/mock-wallet-controller.d.ts.map +1 -1
- package/dist/mock-wallet-controller.js +843 -46
- package/dist/mock-wallet-controller.js.map +1 -1
- package/dist/private-key-rpc-client.d.ts +1730 -0
- package/dist/private-key-rpc-client.d.ts.map +1 -1
- package/dist/private-key-rpc-client.js +105 -12
- package/dist/private-key-rpc-client.js.map +1 -1
- package/dist/real-wallet-cache.d.ts +65 -0
- package/dist/real-wallet-cache.d.ts.map +1 -0
- package/dist/real-wallet-cache.js +245 -0
- package/dist/real-wallet-cache.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 +73 -0
- package/dist/real-wallet-fixtures.js.map +1 -0
- package/dist/real-wallet.d.ts +123 -14
- package/dist/real-wallet.d.ts.map +1 -1
- package/dist/real-wallet.js +1336 -57
- package/dist/real-wallet.js.map +1 -1
- 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 +1 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/walletconnect.d.ts +206 -0
- package/dist/walletconnect.d.ts.map +1 -0
- package/dist/walletconnect.js +359 -0
- package/dist/walletconnect.js.map +1 -0
- package/examples/live-sepolia.spec.ts +20 -1
- package/package.json +62 -6
- 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
package/dist/index.js
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
export { AnvilInstance, ChainController } from './anvil.js';
|
|
2
|
+
export { Erc20DealError, dealErc20, discoverErc20BalanceSlot, getErc20Balance, TEST_ERC20_ABI, TEST_ERC20_BYTECODE, } from './erc20.js';
|
|
3
|
+
export { anyValue, web3Matchers } from './matchers.js';
|
|
4
|
+
export { extractRevertInfo, waitForDecodedTransaction, web3Equals, web3Stringify, } from './transactions.js';
|
|
2
5
|
export { test, expect } from './fixtures.js';
|
|
3
|
-
export { MockWalletController } from './mock-wallet-controller.js';
|
|
6
|
+
export { MockWalletController, httpRpcClient } from './mock-wallet-controller.js';
|
|
4
7
|
export { PrivateKeyRpcClient } from './private-key-rpc-client.js';
|
|
5
8
|
export { launchRealWallet, resolveRealWalletProfile } from './real-wallet.js';
|
|
9
|
+
export { DEFAULT_METAMASK_VERSION, prepareMetaMaskExtension, extensionManifestVersion, } from './metamask-extension.js';
|
|
10
|
+
export { buildWalletProfile, cloneWalletProfile, waitForExtensionStatePersisted, } from './real-wallet-cache.js';
|
|
11
|
+
export { DEFAULT_WALLET_PASSWORD } from './real-wallet-setup.js';
|
|
6
12
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC5D,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC5D,OAAO,EACL,cAAc,EACd,SAAS,EACT,wBAAwB,EACxB,eAAe,EACf,cAAc,EACd,mBAAmB,GACpB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAEvD,OAAO,EACL,iBAAiB,EACjB,yBAAyB,EACzB,UAAU,EACV,aAAa,GACd,MAAM,mBAAmB,CAAC;AAU3B,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,oBAAoB,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAClF,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAAE,gBAAgB,EAAE,wBAAwB,EAAE,MAAM,kBAAkB,CAAC;AAC9E,OAAO,EACL,wBAAwB,EACxB,wBAAwB,EACxB,wBAAwB,GACzB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,kBAAkB,EAClB,kBAAkB,EAClB,8BAA8B,GAC/B,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"injected-provider.d.ts","sourceRoot":"","sources":["../src/injected-provider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAKnD,eAAO,MAAM,aAAa,+BAAc,CAAC;AACzC,eAAO,MAAM,WAAW,0BAAe,CAAC;AAExC,eAAO,MAAM,2BAA2B,GAAI,QAAQ,gBAAgB,KAAG,
|
|
1
|
+
{"version":3,"file":"injected-provider.d.ts","sourceRoot":"","sources":["../src/injected-provider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAKnD,eAAO,MAAM,aAAa,+BAAc,CAAC;AACzC,eAAO,MAAM,WAAW,0BAAe,CAAC;AAExC,eAAO,MAAM,2BAA2B,GAAI,QAAQ,gBAAgB,KAAG,MAsMtE,CAAC"}
|
|
@@ -5,34 +5,22 @@ export const emitterName = EMITTER_NAME;
|
|
|
5
5
|
export const buildInjectedProviderScript = (config) => `
|
|
6
6
|
(() => {
|
|
7
7
|
const config = ${JSON.stringify(config)};
|
|
8
|
-
const listeners = new Map();
|
|
9
8
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
9
|
+
// Origin-scoped wallets never install in out-of-scope frames, so blocked
|
|
10
|
+
// pages cannot even read the account address or chain off the provider.
|
|
11
|
+
// window.origin (unlike location.origin or the frame URL) is the security
|
|
12
|
+
// origin, which about:blank/srcdoc children inherit from their parent —
|
|
13
|
+
// matching the bridge-side ancestor walk.
|
|
14
|
+
if (config.allowedOrigins && !config.allowedOrigins.includes(window.origin || location.origin)) {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
16
17
|
|
|
17
|
-
const
|
|
18
|
-
if (event === 'accountsChanged') {
|
|
19
|
-
provider.selectedAddress = Array.isArray(payload) && payload.length > 0 ? payload[0] : null;
|
|
20
|
-
}
|
|
18
|
+
const toNetworkVersion = (chainId) => String(Number(BigInt(chainId)));
|
|
21
19
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
const callbacks = listeners.get(event);
|
|
28
|
-
if (!callbacks) {
|
|
29
|
-
return;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
for (const callback of [...callbacks]) {
|
|
33
|
-
callback(payload);
|
|
34
|
-
}
|
|
35
|
-
};
|
|
20
|
+
// EIP-1193 connectivity means "can the provider reach the chain", which is
|
|
21
|
+
// independent of account authorization. The controller's disconnect()
|
|
22
|
+
// simulates losing the chain via the 'disconnect' event.
|
|
23
|
+
let chainDisconnected = false;
|
|
36
24
|
|
|
37
25
|
const request = async (args) => {
|
|
38
26
|
if (!args || typeof args.method !== 'string') {
|
|
@@ -56,74 +44,123 @@ export const buildInjectedProviderScript = (config) => `
|
|
|
56
44
|
return response.result;
|
|
57
45
|
};
|
|
58
46
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
if (typeof methodOrPayload === 'string') {
|
|
69
|
-
return request({ method: methodOrPayload, params: paramsOrCallback });
|
|
47
|
+
// One distinct provider object per announced wallet so selector tests can
|
|
48
|
+
// detect a dapp talking to the wrong provider. They share request handling
|
|
49
|
+
// and state, but each has its own identity and listener registry.
|
|
50
|
+
const createProviderEntry = (info) => {
|
|
51
|
+
const listeners = new Map();
|
|
52
|
+
|
|
53
|
+
const getListeners = (event) => {
|
|
54
|
+
if (!listeners.has(event)) {
|
|
55
|
+
listeners.set(event, new Set());
|
|
70
56
|
}
|
|
57
|
+
return listeners.get(event);
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const provider = {
|
|
61
|
+
isMetaMask: true,
|
|
62
|
+
isMock: true,
|
|
63
|
+
selectedAddress: config.connected && config.accounts.length > 0 ? config.accounts[0] : null,
|
|
64
|
+
chainId: config.chainId,
|
|
65
|
+
networkVersion: toNetworkVersion(config.chainId),
|
|
66
|
+
request,
|
|
67
|
+
isConnected: () => !chainDisconnected,
|
|
68
|
+
enable: () => request({ method: 'eth_requestAccounts' }),
|
|
69
|
+
send: (methodOrPayload, paramsOrCallback) => {
|
|
70
|
+
if (typeof methodOrPayload === 'string') {
|
|
71
|
+
return request({ method: methodOrPayload, params: paramsOrCallback });
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const payload = methodOrPayload;
|
|
75
|
+
const callback = paramsOrCallback;
|
|
76
|
+
request(payload)
|
|
77
|
+
.then((result) => callback?.(null, { id: payload.id, jsonrpc: '2.0', result }))
|
|
78
|
+
.catch((error) => callback?.(error, null));
|
|
79
|
+
},
|
|
80
|
+
sendAsync: (payload, callback) => {
|
|
81
|
+
request(payload)
|
|
82
|
+
.then((result) => callback(null, { id: payload.id, jsonrpc: '2.0', result }))
|
|
83
|
+
.catch((error) => callback(error, null));
|
|
84
|
+
},
|
|
85
|
+
on: (event, handler) => {
|
|
86
|
+
getListeners(event).add(handler);
|
|
87
|
+
return provider;
|
|
88
|
+
},
|
|
89
|
+
once: (event, handler) => {
|
|
90
|
+
const wrapped = (payload) => {
|
|
91
|
+
provider.removeListener(event, wrapped);
|
|
92
|
+
handler(payload);
|
|
93
|
+
};
|
|
94
|
+
provider.on(event, wrapped);
|
|
95
|
+
return provider;
|
|
96
|
+
},
|
|
97
|
+
removeListener: (event, handler) => {
|
|
98
|
+
listeners.get(event)?.delete(handler);
|
|
99
|
+
return provider;
|
|
100
|
+
},
|
|
101
|
+
removeAllListeners: (event) => {
|
|
102
|
+
if (event) {
|
|
103
|
+
listeners.delete(event);
|
|
104
|
+
} else {
|
|
105
|
+
listeners.clear();
|
|
106
|
+
}
|
|
107
|
+
return provider;
|
|
108
|
+
},
|
|
109
|
+
_metamask: {
|
|
110
|
+
isUnlocked: async () => true,
|
|
111
|
+
},
|
|
112
|
+
};
|
|
71
113
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
listeners.get(event)
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
listeners.clear();
|
|
114
|
+
return { info, provider, listeners };
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
const entries = config.providers.map(createProviderEntry);
|
|
118
|
+
|
|
119
|
+
const emit = (event, payload) => {
|
|
120
|
+
if (event === 'connect') {
|
|
121
|
+
chainDisconnected = false;
|
|
122
|
+
}
|
|
123
|
+
if (event === 'disconnect') {
|
|
124
|
+
chainDisconnected = true;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
for (const entry of entries) {
|
|
128
|
+
if (event === 'accountsChanged') {
|
|
129
|
+
entry.provider.selectedAddress =
|
|
130
|
+
Array.isArray(payload) && payload.length > 0 ? payload[0] : null;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (event === 'chainChanged') {
|
|
134
|
+
entry.provider.chainId = payload;
|
|
135
|
+
entry.provider.networkVersion = toNetworkVersion(payload);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const callbacks = entry.listeners.get(event);
|
|
139
|
+
if (!callbacks) {
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
for (const callback of [...callbacks]) {
|
|
144
|
+
callback(payload);
|
|
104
145
|
}
|
|
105
|
-
|
|
106
|
-
},
|
|
107
|
-
_metamask: {
|
|
108
|
-
isUnlocked: async () => true,
|
|
109
|
-
},
|
|
146
|
+
}
|
|
110
147
|
};
|
|
111
148
|
|
|
112
149
|
const announceProviders = () => {
|
|
113
|
-
for (const
|
|
150
|
+
for (const entry of entries) {
|
|
114
151
|
window.dispatchEvent(
|
|
115
152
|
new CustomEvent('eip6963:announceProvider', {
|
|
116
|
-
detail: {
|
|
117
|
-
info,
|
|
118
|
-
provider,
|
|
119
|
-
},
|
|
153
|
+
detail: Object.freeze({
|
|
154
|
+
info: Object.freeze({ ...entry.info }),
|
|
155
|
+
provider: entry.provider,
|
|
156
|
+
}),
|
|
120
157
|
}),
|
|
121
158
|
);
|
|
122
159
|
}
|
|
123
160
|
};
|
|
124
161
|
|
|
125
162
|
Object.defineProperty(window, 'ethereum', {
|
|
126
|
-
value: provider,
|
|
163
|
+
value: entries[0].provider,
|
|
127
164
|
configurable: true,
|
|
128
165
|
enumerable: true,
|
|
129
166
|
writable: true,
|
|
@@ -136,6 +173,32 @@ export const buildInjectedProviderScript = (config) => `
|
|
|
136
173
|
|
|
137
174
|
window.addEventListener('eip6963:requestProvider', announceProviders);
|
|
138
175
|
queueMicrotask(announceProviders);
|
|
176
|
+
|
|
177
|
+
// The serialized config snapshot goes stale once the controller mutates
|
|
178
|
+
// accounts or chain and the page navigates; refresh the synchronous mirror
|
|
179
|
+
// properties from the wallet's current state as soon as the bridge is up.
|
|
180
|
+
const refresh = async () => {
|
|
181
|
+
try {
|
|
182
|
+
const response = await window.${BRIDGE_NAME}({
|
|
183
|
+
method: 'metamask_getProviderState',
|
|
184
|
+
params: [],
|
|
185
|
+
});
|
|
186
|
+
if (!response.ok) {
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const state = response.result;
|
|
191
|
+
for (const entry of entries) {
|
|
192
|
+
entry.provider.selectedAddress = state.accounts.length > 0 ? state.accounts[0] : null;
|
|
193
|
+
entry.provider.chainId = state.chainId;
|
|
194
|
+
entry.provider.networkVersion = toNetworkVersion(state.chainId);
|
|
195
|
+
}
|
|
196
|
+
} catch {
|
|
197
|
+
// Bridge not available yet (e.g. detached frame) — sync values fall
|
|
198
|
+
// back to the injected config snapshot.
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
refresh();
|
|
139
202
|
})();
|
|
140
203
|
`;
|
|
141
204
|
//# sourceMappingURL=injected-provider.js.map
|
|
@@ -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;;;;;;;;;;;;;;;;;;;;;;;;;oCAyBL,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mCAyIZ,YAAY;;;;;;;;;;;;;sCAaT,WAAW;;;;;;;;;;;;;;;;;;;;;CAqBhD,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":"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"}
|