@rocketh/test-utils 0.0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2018-present Ronan Sandford
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,7 @@
1
+ # @rocketh/test-utils
2
+
3
+ Test utilities for rocketh packages, providing helper functions and utilities used across rocketh's test suites.
4
+
5
+ For full documentation, visit [rocketh.dev](https://rocketh.dev).
6
+
7
+ For hardhat-deploy documentation, see [rocketh.dev/hardhat-deploy/](https://rocketh.dev/hardhat-deploy/).
@@ -0,0 +1,185 @@
1
+ /**
2
+ * @rocketh/test-utils
3
+ *
4
+ * Test utilities for rocketh packages. Provides mock environments, providers,
5
+ * and artifacts for testing deployment scenarios.
6
+ */
7
+ import type { Abi, Artifact, Environment } from '@rocketh/core/types';
8
+ import type { EIP1193Provider } from 'eip-1193';
9
+ /**
10
+ * Configuration for mock provider responses.
11
+ * Allows tests to specify custom return values for specific RPC methods.
12
+ */
13
+ export type MockProviderConfig = {
14
+ /**
15
+ * Override responses for specific RPC methods.
16
+ * Can be a static value or a function that receives params and returns a value.
17
+ */
18
+ responses?: {
19
+ [method: string]: unknown | ((params?: unknown[]) => unknown | Promise<unknown>);
20
+ };
21
+ /**
22
+ * Called when an unmocked method is requested.
23
+ * If not provided, returns null and logs a warning.
24
+ */
25
+ onUnmockedMethod?: (method: string, params?: unknown[]) => unknown | Promise<unknown>;
26
+ };
27
+ /**
28
+ * A mock EIP-1193 provider with configurable responses.
29
+ */
30
+ export type MockProvider = EIP1193Provider & {
31
+ /**
32
+ * Update the configuration for the mock provider.
33
+ */
34
+ setConfig: (config: MockProviderConfig) => void;
35
+ /**
36
+ * Update or add a specific response for an RPC method.
37
+ */
38
+ setResponse: (method: string, response: unknown | ((params?: unknown[]) => unknown | Promise<unknown>)) => void;
39
+ /**
40
+ * Get all recorded requests made to the provider.
41
+ */
42
+ getRequests: () => Array<{
43
+ method: string;
44
+ params?: unknown[];
45
+ }>;
46
+ /**
47
+ * Clear recorded requests.
48
+ */
49
+ clearRequests: () => void;
50
+ /**
51
+ * Add an event listener (no-op in mock).
52
+ */
53
+ on: (event: string, listener: (...args: unknown[]) => void) => MockProvider;
54
+ /**
55
+ * Remove an event listener (no-op in mock).
56
+ */
57
+ removeListener: (event: string, listener: (...args: unknown[]) => void) => MockProvider;
58
+ };
59
+ /**
60
+ * Options for creating a mock environment.
61
+ */
62
+ export type MockEnvironmentOptions = {
63
+ /**
64
+ * Custom provider configuration.
65
+ */
66
+ providerConfig?: MockProviderConfig;
67
+ /**
68
+ * Custom named accounts. Defaults to deployer, user1, user2.
69
+ */
70
+ namedAccounts?: Record<string, `0x${string}`>;
71
+ /**
72
+ * Chain ID. Defaults to 31337 (localhost).
73
+ */
74
+ chainId?: number;
75
+ /**
76
+ * Chain name. Defaults to 'localhost'.
77
+ */
78
+ chainName?: string;
79
+ /**
80
+ * Tags to set on the environment.
81
+ */
82
+ tags?: Record<string, boolean>;
83
+ };
84
+ /**
85
+ * Result of creating a mock environment.
86
+ */
87
+ export type MockEnvironmentResult = {
88
+ /**
89
+ * The mock environment.
90
+ */
91
+ env: Environment;
92
+ /**
93
+ * The mock provider (for inspecting/updating responses).
94
+ */
95
+ provider: MockProvider;
96
+ /**
97
+ * The deployments record (for inspecting saved deployments).
98
+ */
99
+ deployments: Record<string, unknown>;
100
+ };
101
+ /**
102
+ * Creates a mock EIP-1193 provider with configurable responses.
103
+ *
104
+ * @param config - Optional configuration for custom responses
105
+ * @returns A mock provider that can be used in tests
106
+ *
107
+ * @example
108
+ * ```typescript
109
+ * const provider = createMockProvider({
110
+ * responses: {
111
+ * eth_getCode: '0x6080...', // Return deployed code
112
+ * eth_getBalance: (params) => {
113
+ * const address = params?.[0];
114
+ * return address === '0x123...' ? '0x0' : '0x1000';
115
+ * },
116
+ * },
117
+ * });
118
+ * ```
119
+ */
120
+ export declare function createMockProvider(config?: MockProviderConfig): MockProvider;
121
+ /**
122
+ * Default ABI for mock artifacts.
123
+ */
124
+ declare const DEFAULT_ABI: Abi;
125
+ /**
126
+ * Creates a mock artifact for testing.
127
+ *
128
+ * @param name - Contract name
129
+ * @param abi - Optional ABI (defaults to a simple contract with constructor and getValue)
130
+ * @returns A mock artifact object
131
+ *
132
+ * @example
133
+ * ```typescript
134
+ * const artifact = createMockArtifact('MyContract', [
135
+ * {
136
+ * type: 'constructor',
137
+ * inputs: [{type: 'address', name: 'owner'}],
138
+ * stateMutability: 'nonpayable',
139
+ * },
140
+ * ]);
141
+ * ```
142
+ */
143
+ export declare function createMockArtifact<TAbi extends Abi = typeof DEFAULT_ABI>(name: string, abi?: TAbi): Artifact<TAbi>;
144
+ export declare function createExampleArtifact(name: string, templateNumber: number): Artifact<Abi>;
145
+ /**
146
+ * Creates a mock artifact with library references.
147
+ *
148
+ * @param name - Contract name
149
+ * @param libraryName - Name of the library to reference
150
+ * @param abi - Optional ABI
151
+ * @returns A mock artifact with library link references
152
+ *
153
+ * @example
154
+ * ```typescript
155
+ * const artifact = createMockArtifactWithLibrary('Calculator', 'MathLib');
156
+ * ```
157
+ */
158
+ export declare function createMockArtifactWithLibrary<TAbi extends Abi = typeof DEFAULT_ABI>(name: string, libraryName: string, abi?: TAbi): Artifact<TAbi>;
159
+ /**
160
+ * Creates a mock environment for testing deployments.
161
+ *
162
+ * @param options - Optional configuration
163
+ * @returns An object containing the environment, provider, and deployments record
164
+ *
165
+ * @example
166
+ * ```typescript
167
+ * // Basic usage
168
+ * const {env, provider} = createMockEnvironment();
169
+ *
170
+ * // With custom provider responses
171
+ * const {env, provider} = createMockEnvironment({
172
+ * providerConfig: {
173
+ * responses: {
174
+ * eth_getCode: '0x6080...', // Simulate deployed contract
175
+ * },
176
+ * },
177
+ * });
178
+ *
179
+ * // Update responses during test
180
+ * provider.setResponse('eth_getCode', '0x'); // Reset to empty
181
+ * ```
182
+ */
183
+ export declare function createMockEnvironment(options?: MockEnvironmentOptions): MockEnvironmentResult;
184
+ export type { Environment } from '@rocketh/core/types';
185
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js ADDED
@@ -0,0 +1,340 @@
1
+ /**
2
+ * @rocketh/test-utils
3
+ *
4
+ * Test utilities for rocketh packages. Provides mock environments, providers,
5
+ * and artifacts for testing deployment scenarios.
6
+ */
7
+ // ============================================================================
8
+ // Mock Provider
9
+ // ============================================================================
10
+ /**
11
+ * Default RPC method responses for a mock provider.
12
+ * These simulate a basic EVM environment.
13
+ */
14
+ function getDefaultResponses(txCounter) {
15
+ return {
16
+ eth_sendTransaction: () => {
17
+ txCounter.value++;
18
+ return `0x${'0'.repeat(63)}${txCounter.value.toString(16)}`;
19
+ },
20
+ eth_sendRawTransaction: () => {
21
+ txCounter.value++;
22
+ return `0x${'1'.repeat(63)}${txCounter.value.toString(16)}`;
23
+ },
24
+ eth_getCode: () => '0x',
25
+ eth_getBalance: () => '0x' + BigInt('1000000000000000000000').toString(16),
26
+ evm_mine: () => null,
27
+ eth_getTransactionReceipt: (params) => ({
28
+ contractAddress: ('0x' + 'a'.repeat(40)),
29
+ status: '0x1',
30
+ blockNumber: '0x1',
31
+ blockHash: `0x${'b'.repeat(64)}`,
32
+ transactionHash: params?.[0] || `0x${'c'.repeat(64)}`,
33
+ gasUsed: '0x5208',
34
+ }),
35
+ eth_chainId: () => '0x7a69', // 31337
36
+ eth_blockNumber: () => '0x1',
37
+ eth_gasPrice: () => '0x3b9aca00', // 1 gwei
38
+ eth_estimateGas: () => '0x5208', // 21000
39
+ eth_getTransactionCount: () => '0x0',
40
+ };
41
+ }
42
+ /**
43
+ * Creates a mock EIP-1193 provider with configurable responses.
44
+ *
45
+ * @param config - Optional configuration for custom responses
46
+ * @returns A mock provider that can be used in tests
47
+ *
48
+ * @example
49
+ * ```typescript
50
+ * const provider = createMockProvider({
51
+ * responses: {
52
+ * eth_getCode: '0x6080...', // Return deployed code
53
+ * eth_getBalance: (params) => {
54
+ * const address = params?.[0];
55
+ * return address === '0x123...' ? '0x0' : '0x1000';
56
+ * },
57
+ * },
58
+ * });
59
+ * ```
60
+ */
61
+ export function createMockProvider(config = {}) {
62
+ const txCounter = { value: 0 };
63
+ const defaultResponses = getDefaultResponses(txCounter);
64
+ let currentConfig = { ...config };
65
+ const requests = [];
66
+ const request = async ({ method, params }) => {
67
+ requests.push({ method, params: params });
68
+ // Check custom responses first
69
+ const customResponse = currentConfig.responses?.[method];
70
+ if (customResponse !== undefined) {
71
+ if (typeof customResponse === 'function') {
72
+ return customResponse(params);
73
+ }
74
+ return customResponse;
75
+ }
76
+ // Check default responses
77
+ const defaultResponse = defaultResponses[method];
78
+ if (defaultResponse !== undefined) {
79
+ if (typeof defaultResponse === 'function') {
80
+ return defaultResponse(params);
81
+ }
82
+ return defaultResponse;
83
+ }
84
+ // Handle unmocked method
85
+ if (currentConfig.onUnmockedMethod) {
86
+ return currentConfig.onUnmockedMethod(method, params);
87
+ }
88
+ console.warn(`Unmocked provider method: ${method}`);
89
+ return null;
90
+ };
91
+ const provider = {
92
+ request: request,
93
+ on: () => provider, // No-op event listener
94
+ removeListener: () => provider, // No-op event listener removal
95
+ setConfig: (newConfig) => {
96
+ currentConfig = { ...newConfig };
97
+ },
98
+ setResponse: (method, response) => {
99
+ if (!currentConfig.responses) {
100
+ currentConfig.responses = {};
101
+ }
102
+ currentConfig.responses[method] = response;
103
+ },
104
+ getRequests: () => [...requests],
105
+ clearRequests: () => {
106
+ requests.length = 0;
107
+ },
108
+ };
109
+ return provider;
110
+ }
111
+ // ============================================================================
112
+ // Mock Artifacts
113
+ // ============================================================================
114
+ /**
115
+ * Default ABI for mock artifacts.
116
+ */
117
+ const DEFAULT_ABI = [
118
+ {
119
+ type: 'function',
120
+ name: 'getValue',
121
+ inputs: [],
122
+ outputs: [{ type: 'uint256' }],
123
+ stateMutability: 'view',
124
+ },
125
+ {
126
+ type: 'constructor',
127
+ inputs: [{ type: 'uint256', name: '_initialValue' }],
128
+ stateMutability: 'nonpayable',
129
+ },
130
+ ];
131
+ /**
132
+ * Creates a mock artifact for testing.
133
+ *
134
+ * @param name - Contract name
135
+ * @param abi - Optional ABI (defaults to a simple contract with constructor and getValue)
136
+ * @returns A mock artifact object
137
+ *
138
+ * @example
139
+ * ```typescript
140
+ * const artifact = createMockArtifact('MyContract', [
141
+ * {
142
+ * type: 'constructor',
143
+ * inputs: [{type: 'address', name: 'owner'}],
144
+ * stateMutability: 'nonpayable',
145
+ * },
146
+ * ]);
147
+ * ```
148
+ */
149
+ export function createMockArtifact(name, abi = DEFAULT_ABI) {
150
+ return {
151
+ contractName: name,
152
+ abi,
153
+ bytecode: '0x6080604052348015600f57600080fd5b50',
154
+ deployedBytecode: '0x6080604052',
155
+ linkReferences: {},
156
+ metadata: JSON.stringify({ compiler: { version: '0.8.20' }, settings: { optimizer: { enabled: true } } }),
157
+ };
158
+ }
159
+ export function createExampleArtifact(name, templateNumber) {
160
+ const mock = createMockArtifact(name);
161
+ if (templateNumber == 0) {
162
+ mock.abi = [
163
+ {
164
+ type: 'function',
165
+ name: 'getValue0',
166
+ inputs: [],
167
+ outputs: [{ type: 'uint256' }],
168
+ stateMutability: 'view',
169
+ },
170
+ {
171
+ type: 'constructor',
172
+ inputs: [{ type: 'uint256', name: '_initialValue' }],
173
+ stateMutability: 'nonpayable',
174
+ },
175
+ ];
176
+ }
177
+ else if (templateNumber == 1) {
178
+ mock.abi = [
179
+ {
180
+ type: 'function',
181
+ name: 'getValue1',
182
+ inputs: [],
183
+ outputs: [{ type: 'uint256' }],
184
+ stateMutability: 'view',
185
+ },
186
+ {
187
+ type: 'constructor',
188
+ inputs: [{ type: 'uint256', name: '_initialValue' }],
189
+ stateMutability: 'nonpayable',
190
+ },
191
+ ];
192
+ }
193
+ else if (templateNumber == 2) {
194
+ mock.abi = [
195
+ {
196
+ type: 'function',
197
+ name: 'getValue2',
198
+ inputs: [],
199
+ outputs: [{ type: 'uint256' }],
200
+ stateMutability: 'view',
201
+ },
202
+ {
203
+ type: 'constructor',
204
+ inputs: [{ type: 'uint256', name: '_initialValue' }],
205
+ stateMutability: 'nonpayable',
206
+ },
207
+ ];
208
+ }
209
+ else {
210
+ throw new Error(`no template ${templateNumber}`);
211
+ }
212
+ return mock;
213
+ }
214
+ /**
215
+ * Creates a mock artifact with library references.
216
+ *
217
+ * @param name - Contract name
218
+ * @param libraryName - Name of the library to reference
219
+ * @param abi - Optional ABI
220
+ * @returns A mock artifact with library link references
221
+ *
222
+ * @example
223
+ * ```typescript
224
+ * const artifact = createMockArtifactWithLibrary('Calculator', 'MathLib');
225
+ * ```
226
+ */
227
+ export function createMockArtifactWithLibrary(name, libraryName, abi = DEFAULT_ABI) {
228
+ return {
229
+ contractName: name,
230
+ abi,
231
+ bytecode: '0x6080604052348015600f57600080fd5b50',
232
+ deployedBytecode: '0x6080604052',
233
+ linkReferences: {
234
+ 'contracts/libraries.sol': {
235
+ [libraryName]: [{ length: 20, start: 50 }],
236
+ },
237
+ },
238
+ metadata: JSON.stringify({ compiler: { version: '0.8.20' }, settings: { optimizer: { enabled: true } } }),
239
+ };
240
+ }
241
+ // ============================================================================
242
+ // Mock Environment
243
+ // ============================================================================
244
+ /**
245
+ * Default named accounts for testing.
246
+ */
247
+ const DEFAULT_NAMED_ACCOUNTS = {
248
+ deployer: '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266',
249
+ user1: '0x70997970C51812dc3A010C7d01b50e0d17dc79C8',
250
+ user2: '0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC',
251
+ };
252
+ /**
253
+ * Creates a mock environment for testing deployments.
254
+ *
255
+ * @param options - Optional configuration
256
+ * @returns An object containing the environment, provider, and deployments record
257
+ *
258
+ * @example
259
+ * ```typescript
260
+ * // Basic usage
261
+ * const {env, provider} = createMockEnvironment();
262
+ *
263
+ * // With custom provider responses
264
+ * const {env, provider} = createMockEnvironment({
265
+ * providerConfig: {
266
+ * responses: {
267
+ * eth_getCode: '0x6080...', // Simulate deployed contract
268
+ * },
269
+ * },
270
+ * });
271
+ *
272
+ * // Update responses during test
273
+ * provider.setResponse('eth_getCode', '0x'); // Reset to empty
274
+ * ```
275
+ */
276
+ export function createMockEnvironment(options = {}) {
277
+ const deployments = {};
278
+ const provider = createMockProvider(options.providerConfig);
279
+ const namedAccounts = options.namedAccounts || DEFAULT_NAMED_ACCOUNTS;
280
+ const chainId = options.chainId ?? 31337;
281
+ const chainName = options.chainName ?? 'localhost';
282
+ const addressSigners = {};
283
+ for (const address of Object.values(namedAccounts)) {
284
+ addressSigners[address] = {
285
+ type: 'remote',
286
+ signer: provider,
287
+ };
288
+ }
289
+ const env = {
290
+ namedAccounts: namedAccounts,
291
+ network: {
292
+ chain: {
293
+ id: chainId,
294
+ name: chainName,
295
+ nativeCurrency: { name: 'Ether', symbol: 'ETH', decimals: 18 },
296
+ },
297
+ provider,
298
+ deterministicDeployment: {
299
+ create2: {
300
+ factory: '0x4e59b44847b379578588920cA78FbF26c0B4956C',
301
+ deployer: '0x3f39e218c8a8b13d2488ccf2a3b7d0e3c0c8e8d9',
302
+ signedTx: '0xf8a5',
303
+ funding: '100000000000000000',
304
+ },
305
+ create3: {
306
+ factory: '0x000000000004d4f168daE7DB3C610F408eE22F57',
307
+ salt: '0x5361109ca02853ca8e22046b7125306d9ec4ae4cdecc393c567b6be861df3db6',
308
+ bytecode: '0x6080604052348015600f57600080fd5b506103ca8061001f6000396000f3fe6080604052600436106100295760003560e01c8063360d0fad1461002e5780639881d19514610077575b600080fd5b34801561003a57600080fd5b5061004e610049366004610228565b61008a565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b61004e61008536600461029c565b6100ee565b6040517fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606084901b166020820152603481018290526000906054016040516020818303038152906040528051906020012091506100e78261014c565b9392505050565b6040517fffffffffffffffffffffffffffffffffffffffff0000000000000000000000003360601b166020820152603481018290526000906054016040516020818303038152906040528051906020012091506100e734848461015e565b600061015882306101ce565b92915050565b60006f67363d3d37363d34f03d5260086018f3600052816010806000f58061018e5763301164256000526004601cfd5b8060145261d69460005260016034536017601e20915060008085516020870188855af1823b026101c65763301164256000526004601cfd5b509392505050565b60006040518260005260ff600b53836020527f21c35dbe1b344a2488cf3321d6ce542f8e9f305544ff09e4993a62319a497c1f6040526055600b20601452806040525061d694600052600160345350506017601e20919050565b6000806040838503121561023b57600080fd5b823573ffffffffffffffffffffffffffffffffffffffff8116811461025f57600080fd5b946020939093013593505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600080604083850312156102af57600080fd5b823567ffffffffffffffff8111156102c657600080fd5b8301601f810185136102d757600080fd5b803567ffffffffffffffff8111156102f1576102f161026d565b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8501160116810181811067ffffffffffffffff8211171561035d5761035d61026d565b60405281815282820160200187101561037557600080fd5b816020840160208301376000602092820183015296940135945050505056fea264697066735822122059dcc5dc6453397d13ff28021e28472a80a45bbd97f3135f69bd2650773aeb0164736f6c634300081a0033',
309
+ proxyBytecode: '0x67363d3d37363d34f03d5260086018f3',
310
+ },
311
+ },
312
+ },
313
+ addressSigners,
314
+ tags: {
315
+ test: true,
316
+ 'auto-mine': true,
317
+ ...(options.tags || {}),
318
+ },
319
+ get: (name) => deployments[name],
320
+ getOrNull: (name) => deployments[name] || null,
321
+ save: async (name, deployment) => {
322
+ deployments[name] = deployment;
323
+ return deployment;
324
+ },
325
+ savePendingDeployment: async (pendingDeployment) => {
326
+ const pd = pendingDeployment;
327
+ return {
328
+ ...pd.partialDeployment,
329
+ address: pd.expectedAddress || ('0x' + '1'.repeat(40)),
330
+ newlyDeployed: true,
331
+ };
332
+ },
333
+ savePendingExecution: async () => { },
334
+ showMessage: (message) => {
335
+ // Could be configured to capture messages for testing
336
+ },
337
+ };
338
+ return { env, provider, deployments };
339
+ }
340
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "@rocketh/test-utils",
3
+ "version": "0.0.2",
4
+ "description": "Test utilities for rocketh packages",
5
+ "publishConfig": {
6
+ "access": "public"
7
+ },
8
+ "type": "module",
9
+ "main": "dist/index.js",
10
+ "module": "dist/index.js",
11
+ "types": "dist/index.d.ts",
12
+ "exports": {
13
+ ".": {
14
+ "import": {
15
+ "types": "./dist/index.d.ts",
16
+ "default": "./dist/index.js"
17
+ }
18
+ }
19
+ },
20
+ "files": [
21
+ "dist",
22
+ "src"
23
+ ],
24
+ "dependencies": {
25
+ "eip-1193": "^0.6.5",
26
+ "viem": "^2.44.4",
27
+ "@rocketh/core": "0.17.9"
28
+ },
29
+ "devDependencies": {
30
+ "as-soon": "^0.1.4",
31
+ "typescript": "^5.9.3"
32
+ },
33
+ "scripts": {
34
+ "build": "tsc --project tsconfig.json",
35
+ "dev": "as-soon -w src pnpm build"
36
+ }
37
+ }
package/src/index.ts ADDED
@@ -0,0 +1,488 @@
1
+ /**
2
+ * @rocketh/test-utils
3
+ *
4
+ * Test utilities for rocketh packages. Provides mock environments, providers,
5
+ * and artifacts for testing deployment scenarios.
6
+ */
7
+
8
+ import type {Abi, Artifact, Environment} from '@rocketh/core/types';
9
+ import type {EIP1193Provider} from 'eip-1193';
10
+
11
+ // ============================================================================
12
+ // Types
13
+ // ============================================================================
14
+
15
+ /**
16
+ * Configuration for mock provider responses.
17
+ * Allows tests to specify custom return values for specific RPC methods.
18
+ */
19
+ export type MockProviderConfig = {
20
+ /**
21
+ * Override responses for specific RPC methods.
22
+ * Can be a static value or a function that receives params and returns a value.
23
+ */
24
+ responses?: {
25
+ [method: string]: unknown | ((params?: unknown[]) => unknown | Promise<unknown>);
26
+ };
27
+
28
+ /**
29
+ * Called when an unmocked method is requested.
30
+ * If not provided, returns null and logs a warning.
31
+ */
32
+ onUnmockedMethod?: (method: string, params?: unknown[]) => unknown | Promise<unknown>;
33
+ };
34
+
35
+ /**
36
+ * A mock EIP-1193 provider with configurable responses.
37
+ */
38
+ export type MockProvider = EIP1193Provider & {
39
+ /**
40
+ * Update the configuration for the mock provider.
41
+ */
42
+ setConfig: (config: MockProviderConfig) => void;
43
+
44
+ /**
45
+ * Update or add a specific response for an RPC method.
46
+ */
47
+ setResponse: (method: string, response: unknown | ((params?: unknown[]) => unknown | Promise<unknown>)) => void;
48
+
49
+ /**
50
+ * Get all recorded requests made to the provider.
51
+ */
52
+ getRequests: () => Array<{method: string; params?: unknown[]}>;
53
+
54
+ /**
55
+ * Clear recorded requests.
56
+ */
57
+ clearRequests: () => void;
58
+
59
+ /**
60
+ * Add an event listener (no-op in mock).
61
+ */
62
+ on: (event: string, listener: (...args: unknown[]) => void) => MockProvider;
63
+
64
+ /**
65
+ * Remove an event listener (no-op in mock).
66
+ */
67
+ removeListener: (event: string, listener: (...args: unknown[]) => void) => MockProvider;
68
+ };
69
+
70
+ /**
71
+ * Options for creating a mock environment.
72
+ */
73
+ export type MockEnvironmentOptions = {
74
+ /**
75
+ * Custom provider configuration.
76
+ */
77
+ providerConfig?: MockProviderConfig;
78
+
79
+ /**
80
+ * Custom named accounts. Defaults to deployer, user1, user2.
81
+ */
82
+ namedAccounts?: Record<string, `0x${string}`>;
83
+
84
+ /**
85
+ * Chain ID. Defaults to 31337 (localhost).
86
+ */
87
+ chainId?: number;
88
+
89
+ /**
90
+ * Chain name. Defaults to 'localhost'.
91
+ */
92
+ chainName?: string;
93
+
94
+ /**
95
+ * Tags to set on the environment.
96
+ */
97
+ tags?: Record<string, boolean>;
98
+ };
99
+
100
+ /**
101
+ * Result of creating a mock environment.
102
+ */
103
+ export type MockEnvironmentResult = {
104
+ /**
105
+ * The mock environment.
106
+ */
107
+ env: Environment;
108
+
109
+ /**
110
+ * The mock provider (for inspecting/updating responses).
111
+ */
112
+ provider: MockProvider;
113
+
114
+ /**
115
+ * The deployments record (for inspecting saved deployments).
116
+ */
117
+ deployments: Record<string, unknown>;
118
+ };
119
+
120
+ // ============================================================================
121
+ // Mock Provider
122
+ // ============================================================================
123
+
124
+ /**
125
+ * Default RPC method responses for a mock provider.
126
+ * These simulate a basic EVM environment.
127
+ */
128
+ function getDefaultResponses(txCounter: {
129
+ value: number;
130
+ }): Record<string, unknown | ((params?: unknown[]) => unknown | Promise<unknown>)> {
131
+ return {
132
+ eth_sendTransaction: () => {
133
+ txCounter.value++;
134
+ return `0x${'0'.repeat(63)}${txCounter.value.toString(16)}` as `0x${string}`;
135
+ },
136
+ eth_sendRawTransaction: () => {
137
+ txCounter.value++;
138
+ return `0x${'1'.repeat(63)}${txCounter.value.toString(16)}` as `0x${string}`;
139
+ },
140
+ eth_getCode: () => '0x',
141
+ eth_getBalance: () => '0x' + BigInt('1000000000000000000000').toString(16),
142
+ evm_mine: () => null,
143
+ eth_getTransactionReceipt: (params?: unknown[]) => ({
144
+ contractAddress: ('0x' + 'a'.repeat(40)) as `0x${string}`,
145
+ status: '0x1',
146
+ blockNumber: '0x1',
147
+ blockHash: `0x${'b'.repeat(64)}`,
148
+ transactionHash: (params?.[0] as string) || `0x${'c'.repeat(64)}`,
149
+ gasUsed: '0x5208',
150
+ }),
151
+ eth_chainId: () => '0x7a69', // 31337
152
+ eth_blockNumber: () => '0x1',
153
+ eth_gasPrice: () => '0x3b9aca00', // 1 gwei
154
+ eth_estimateGas: () => '0x5208', // 21000
155
+ eth_getTransactionCount: () => '0x0',
156
+ };
157
+ }
158
+
159
+ /**
160
+ * Creates a mock EIP-1193 provider with configurable responses.
161
+ *
162
+ * @param config - Optional configuration for custom responses
163
+ * @returns A mock provider that can be used in tests
164
+ *
165
+ * @example
166
+ * ```typescript
167
+ * const provider = createMockProvider({
168
+ * responses: {
169
+ * eth_getCode: '0x6080...', // Return deployed code
170
+ * eth_getBalance: (params) => {
171
+ * const address = params?.[0];
172
+ * return address === '0x123...' ? '0x0' : '0x1000';
173
+ * },
174
+ * },
175
+ * });
176
+ * ```
177
+ */
178
+ export function createMockProvider(config: MockProviderConfig = {}): MockProvider {
179
+ const txCounter = {value: 0};
180
+ const defaultResponses = getDefaultResponses(txCounter);
181
+ let currentConfig = {...config};
182
+ const requests: Array<{method: string; params?: unknown[]}> = [];
183
+
184
+ const request = async ({method, params}: {method: string; params?: unknown[]}): Promise<unknown> => {
185
+ requests.push({method, params: params as unknown[]});
186
+
187
+ // Check custom responses first
188
+ const customResponse = currentConfig.responses?.[method];
189
+ if (customResponse !== undefined) {
190
+ if (typeof customResponse === 'function') {
191
+ return customResponse(params as unknown[]);
192
+ }
193
+ return customResponse;
194
+ }
195
+
196
+ // Check default responses
197
+ const defaultResponse = defaultResponses[method];
198
+ if (defaultResponse !== undefined) {
199
+ if (typeof defaultResponse === 'function') {
200
+ return defaultResponse(params as unknown[]);
201
+ }
202
+ return defaultResponse;
203
+ }
204
+
205
+ // Handle unmocked method
206
+ if (currentConfig.onUnmockedMethod) {
207
+ return currentConfig.onUnmockedMethod(method, params as unknown[]);
208
+ }
209
+
210
+ console.warn(`Unmocked provider method: ${method}`);
211
+ return null;
212
+ };
213
+
214
+ const provider: MockProvider = {
215
+ request: request as EIP1193Provider['request'],
216
+ on: () => provider, // No-op event listener
217
+ removeListener: () => provider, // No-op event listener removal
218
+ setConfig: (newConfig: MockProviderConfig) => {
219
+ currentConfig = {...newConfig};
220
+ },
221
+ setResponse: (method: string, response: unknown | ((params?: unknown[]) => unknown | Promise<unknown>)) => {
222
+ if (!currentConfig.responses) {
223
+ currentConfig.responses = {};
224
+ }
225
+ currentConfig.responses[method] = response;
226
+ },
227
+ getRequests: () => [...requests],
228
+ clearRequests: () => {
229
+ requests.length = 0;
230
+ },
231
+ };
232
+ return provider;
233
+ }
234
+
235
+ // ============================================================================
236
+ // Mock Artifacts
237
+ // ============================================================================
238
+
239
+ /**
240
+ * Default ABI for mock artifacts.
241
+ */
242
+ const DEFAULT_ABI: Abi = [
243
+ {
244
+ type: 'function',
245
+ name: 'getValue',
246
+ inputs: [],
247
+ outputs: [{type: 'uint256'}],
248
+ stateMutability: 'view',
249
+ },
250
+ {
251
+ type: 'constructor',
252
+ inputs: [{type: 'uint256', name: '_initialValue'}],
253
+ stateMutability: 'nonpayable',
254
+ },
255
+ ] as const;
256
+
257
+ /**
258
+ * Creates a mock artifact for testing.
259
+ *
260
+ * @param name - Contract name
261
+ * @param abi - Optional ABI (defaults to a simple contract with constructor and getValue)
262
+ * @returns A mock artifact object
263
+ *
264
+ * @example
265
+ * ```typescript
266
+ * const artifact = createMockArtifact('MyContract', [
267
+ * {
268
+ * type: 'constructor',
269
+ * inputs: [{type: 'address', name: 'owner'}],
270
+ * stateMutability: 'nonpayable',
271
+ * },
272
+ * ]);
273
+ * ```
274
+ */
275
+ export function createMockArtifact<TAbi extends Abi = typeof DEFAULT_ABI>(
276
+ name: string,
277
+ abi: TAbi = DEFAULT_ABI as TAbi,
278
+ ): Artifact<TAbi> {
279
+ return {
280
+ contractName: name,
281
+ abi,
282
+ bytecode: '0x6080604052348015600f57600080fd5b50' as `0x${string}`,
283
+ deployedBytecode: '0x6080604052' as `0x${string}`,
284
+ linkReferences: {},
285
+ metadata: JSON.stringify({compiler: {version: '0.8.20'}, settings: {optimizer: {enabled: true}}}),
286
+ };
287
+ }
288
+
289
+ export function createExampleArtifact(name: string, templateNumber: number): Artifact<Abi> {
290
+ const mock = createMockArtifact(name);
291
+ if (templateNumber == 0) {
292
+ (mock as any).abi = [
293
+ {
294
+ type: 'function',
295
+ name: 'getValue0',
296
+ inputs: [],
297
+ outputs: [{type: 'uint256'}],
298
+ stateMutability: 'view',
299
+ },
300
+ {
301
+ type: 'constructor',
302
+ inputs: [{type: 'uint256', name: '_initialValue'}],
303
+ stateMutability: 'nonpayable',
304
+ },
305
+ ];
306
+ } else if (templateNumber == 1) {
307
+ (mock as any).abi = [
308
+ {
309
+ type: 'function',
310
+ name: 'getValue1',
311
+ inputs: [],
312
+ outputs: [{type: 'uint256'}],
313
+ stateMutability: 'view',
314
+ },
315
+ {
316
+ type: 'constructor',
317
+ inputs: [{type: 'uint256', name: '_initialValue'}],
318
+ stateMutability: 'nonpayable',
319
+ },
320
+ ];
321
+ } else if (templateNumber == 2) {
322
+ (mock as any).abi = [
323
+ {
324
+ type: 'function',
325
+ name: 'getValue2',
326
+ inputs: [],
327
+ outputs: [{type: 'uint256'}],
328
+ stateMutability: 'view',
329
+ },
330
+ {
331
+ type: 'constructor',
332
+ inputs: [{type: 'uint256', name: '_initialValue'}],
333
+ stateMutability: 'nonpayable',
334
+ },
335
+ ];
336
+ } else {
337
+ throw new Error(`no template ${templateNumber}`);
338
+ }
339
+
340
+ return mock;
341
+ }
342
+
343
+ /**
344
+ * Creates a mock artifact with library references.
345
+ *
346
+ * @param name - Contract name
347
+ * @param libraryName - Name of the library to reference
348
+ * @param abi - Optional ABI
349
+ * @returns A mock artifact with library link references
350
+ *
351
+ * @example
352
+ * ```typescript
353
+ * const artifact = createMockArtifactWithLibrary('Calculator', 'MathLib');
354
+ * ```
355
+ */
356
+ export function createMockArtifactWithLibrary<TAbi extends Abi = typeof DEFAULT_ABI>(
357
+ name: string,
358
+ libraryName: string,
359
+ abi: TAbi = DEFAULT_ABI as TAbi,
360
+ ): Artifact<TAbi> {
361
+ return {
362
+ contractName: name,
363
+ abi,
364
+ bytecode: '0x6080604052348015600f57600080fd5b50' as `0x${string}`,
365
+ deployedBytecode: '0x6080604052' as `0x${string}`,
366
+ linkReferences: {
367
+ 'contracts/libraries.sol': {
368
+ [libraryName]: [{length: 20, start: 50}],
369
+ },
370
+ },
371
+ metadata: JSON.stringify({compiler: {version: '0.8.20'}, settings: {optimizer: {enabled: true}}}),
372
+ };
373
+ }
374
+
375
+ // ============================================================================
376
+ // Mock Environment
377
+ // ============================================================================
378
+
379
+ /**
380
+ * Default named accounts for testing.
381
+ */
382
+ const DEFAULT_NAMED_ACCOUNTS: Record<string, `0x${string}`> = {
383
+ deployer: '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266',
384
+ user1: '0x70997970C51812dc3A010C7d01b50e0d17dc79C8',
385
+ user2: '0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC',
386
+ };
387
+
388
+ /**
389
+ * Creates a mock environment for testing deployments.
390
+ *
391
+ * @param options - Optional configuration
392
+ * @returns An object containing the environment, provider, and deployments record
393
+ *
394
+ * @example
395
+ * ```typescript
396
+ * // Basic usage
397
+ * const {env, provider} = createMockEnvironment();
398
+ *
399
+ * // With custom provider responses
400
+ * const {env, provider} = createMockEnvironment({
401
+ * providerConfig: {
402
+ * responses: {
403
+ * eth_getCode: '0x6080...', // Simulate deployed contract
404
+ * },
405
+ * },
406
+ * });
407
+ *
408
+ * // Update responses during test
409
+ * provider.setResponse('eth_getCode', '0x'); // Reset to empty
410
+ * ```
411
+ */
412
+ export function createMockEnvironment(options: MockEnvironmentOptions = {}): MockEnvironmentResult {
413
+ const deployments: Record<string, unknown> = {};
414
+ const provider = createMockProvider(options.providerConfig);
415
+ const namedAccounts = options.namedAccounts || DEFAULT_NAMED_ACCOUNTS;
416
+ const chainId = options.chainId ?? 31337;
417
+ const chainName = options.chainName ?? 'localhost';
418
+
419
+ const addressSigners: Record<string, {type: 'remote'; signer: MockProvider}> = {};
420
+ for (const address of Object.values(namedAccounts)) {
421
+ addressSigners[address] = {
422
+ type: 'remote',
423
+ signer: provider,
424
+ };
425
+ }
426
+
427
+ const env: Environment = {
428
+ namedAccounts: namedAccounts as Record<string, `0x${string}`>,
429
+ network: {
430
+ chain: {
431
+ id: chainId,
432
+ name: chainName,
433
+ nativeCurrency: {name: 'Ether', symbol: 'ETH', decimals: 18},
434
+ },
435
+ provider,
436
+ deterministicDeployment: {
437
+ create2: {
438
+ factory: '0x4e59b44847b379578588920cA78FbF26c0B4956C' as `0x${string}`,
439
+ deployer: '0x3f39e218c8a8b13d2488ccf2a3b7d0e3c0c8e8d9' as `0x${string}`,
440
+ signedTx: '0xf8a5' as `0x${string}`,
441
+ funding: '100000000000000000',
442
+ },
443
+ create3: {
444
+ factory: '0x000000000004d4f168daE7DB3C610F408eE22F57',
445
+ salt: '0x5361109ca02853ca8e22046b7125306d9ec4ae4cdecc393c567b6be861df3db6',
446
+ bytecode:
447
+ '0x6080604052348015600f57600080fd5b506103ca8061001f6000396000f3fe6080604052600436106100295760003560e01c8063360d0fad1461002e5780639881d19514610077575b600080fd5b34801561003a57600080fd5b5061004e610049366004610228565b61008a565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b61004e61008536600461029c565b6100ee565b6040517fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606084901b166020820152603481018290526000906054016040516020818303038152906040528051906020012091506100e78261014c565b9392505050565b6040517fffffffffffffffffffffffffffffffffffffffff0000000000000000000000003360601b166020820152603481018290526000906054016040516020818303038152906040528051906020012091506100e734848461015e565b600061015882306101ce565b92915050565b60006f67363d3d37363d34f03d5260086018f3600052816010806000f58061018e5763301164256000526004601cfd5b8060145261d69460005260016034536017601e20915060008085516020870188855af1823b026101c65763301164256000526004601cfd5b509392505050565b60006040518260005260ff600b53836020527f21c35dbe1b344a2488cf3321d6ce542f8e9f305544ff09e4993a62319a497c1f6040526055600b20601452806040525061d694600052600160345350506017601e20919050565b6000806040838503121561023b57600080fd5b823573ffffffffffffffffffffffffffffffffffffffff8116811461025f57600080fd5b946020939093013593505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600080604083850312156102af57600080fd5b823567ffffffffffffffff8111156102c657600080fd5b8301601f810185136102d757600080fd5b803567ffffffffffffffff8111156102f1576102f161026d565b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8501160116810181811067ffffffffffffffff8211171561035d5761035d61026d565b60405281815282820160200187101561037557600080fd5b816020840160208301376000602092820183015296940135945050505056fea264697066735822122059dcc5dc6453397d13ff28021e28472a80a45bbd97f3135f69bd2650773aeb0164736f6c634300081a0033',
448
+ proxyBytecode: '0x67363d3d37363d34f03d5260086018f3',
449
+ },
450
+ },
451
+ },
452
+ addressSigners,
453
+ tags: {
454
+ test: true,
455
+ 'auto-mine': true,
456
+ ...(options.tags || {}),
457
+ },
458
+ get: <T>(name: string) => deployments[name] as T,
459
+ getOrNull: <T>(name: string) => (deployments[name] as T) || null,
460
+ save: async <T>(name: string, deployment: T) => {
461
+ deployments[name] = deployment;
462
+ return deployment as T;
463
+ },
464
+ savePendingDeployment: async (pendingDeployment: unknown) => {
465
+ const pd = pendingDeployment as {
466
+ partialDeployment: Record<string, unknown>;
467
+ expectedAddress?: `0x${string}`;
468
+ };
469
+ return {
470
+ ...pd.partialDeployment,
471
+ address: pd.expectedAddress || (('0x' + '1'.repeat(40)) as `0x${string}`),
472
+ newlyDeployed: true,
473
+ };
474
+ },
475
+ savePendingExecution: async () => {},
476
+ showMessage: (message: string) => {
477
+ // Could be configured to capture messages for testing
478
+ },
479
+ } as unknown as Environment;
480
+
481
+ return {env, provider, deployments};
482
+ }
483
+
484
+ // ============================================================================
485
+ // Re-exports
486
+ // ============================================================================
487
+
488
+ export type {Environment} from '@rocketh/core/types';