@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
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { chromium } from '@playwright/test';
|
|
4
|
+
export function resolveRealWalletProfile(profileDir) {
|
|
5
|
+
const resolved = path.resolve(profileDir);
|
|
6
|
+
const profileDirectory = path.basename(resolved);
|
|
7
|
+
const userDataDir = path.dirname(resolved);
|
|
8
|
+
const looksLikeChromeProfile = /^(?:Default|Profile \d+)$/.test(profileDirectory);
|
|
9
|
+
if (looksLikeChromeProfile && fs.existsSync(path.join(userDataDir, 'Local State'))) {
|
|
10
|
+
return { profileDirectory, userDataDir };
|
|
11
|
+
}
|
|
12
|
+
return { userDataDir: resolved };
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Resolves the headed/headless choice for real-wallet extension launches.
|
|
16
|
+
* The explicit option wins over the environment.
|
|
17
|
+
*/
|
|
18
|
+
export function resolveRealWalletHeadless(explicit) {
|
|
19
|
+
if (explicit !== undefined)
|
|
20
|
+
return explicit;
|
|
21
|
+
const env = process.env.WEB3_TESTER_REAL_WALLET_HEADLESS;
|
|
22
|
+
if (env === 'true')
|
|
23
|
+
return true;
|
|
24
|
+
if (env === 'false')
|
|
25
|
+
return false;
|
|
26
|
+
if (env) {
|
|
27
|
+
throw new Error(`WEB3_TESTER_REAL_WALLET_HEADLESS must be "true" or "false", got "${env}".`);
|
|
28
|
+
}
|
|
29
|
+
throw new Error('Real-wallet launches need an explicit headed/headless choice: pass headless: true|false ' +
|
|
30
|
+
'(launchRealWalletExtension / launchRealWallet / buildWalletProfile / realWalletOptions) or set ' +
|
|
31
|
+
'WEB3_TESTER_REAL_WALLET_HEADLESS=true|false. Headed is the fully validated mode; ' +
|
|
32
|
+
'headless needs the full Chromium build (npx playwright install chromium).');
|
|
33
|
+
}
|
|
34
|
+
export function readExtensionManifest(extensionPath) {
|
|
35
|
+
const manifestPath = path.join(extensionPath, 'manifest.json');
|
|
36
|
+
let raw;
|
|
37
|
+
try {
|
|
38
|
+
raw = fs.readFileSync(manifestPath, 'utf8');
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
42
|
+
throw new Error(`Unable to read extension manifest at ${manifestPath}: ${message}`);
|
|
43
|
+
}
|
|
44
|
+
try {
|
|
45
|
+
const parsed = JSON.parse(raw);
|
|
46
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
47
|
+
throw new Error('manifest is not an object');
|
|
48
|
+
}
|
|
49
|
+
return parsed;
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
53
|
+
throw new Error(`Unable to parse extension manifest at ${manifestPath}: ${message}`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
function usableManifestString(value) {
|
|
57
|
+
if (typeof value !== 'string')
|
|
58
|
+
return undefined;
|
|
59
|
+
const trimmed = value.trim();
|
|
60
|
+
if (!trimmed || /^__MSG_[^_]+__$/.test(trimmed))
|
|
61
|
+
return undefined;
|
|
62
|
+
return trimmed;
|
|
63
|
+
}
|
|
64
|
+
export function extensionManifestName(extensionPath) {
|
|
65
|
+
return usableManifestString(readExtensionManifest(extensionPath).name);
|
|
66
|
+
}
|
|
67
|
+
export function extensionManifestDefaultPage(manifest) {
|
|
68
|
+
return (usableManifestString(manifest.action?.default_popup) ??
|
|
69
|
+
usableManifestString(manifest.browser_action?.default_popup) ??
|
|
70
|
+
usableManifestString(manifest.options_ui?.page) ??
|
|
71
|
+
usableManifestString(manifest.side_panel?.default_path));
|
|
72
|
+
}
|
|
73
|
+
function normalizeExtensionPage(page = '') {
|
|
74
|
+
return page.replace(/^\/+/, '');
|
|
75
|
+
}
|
|
76
|
+
export function extensionPageUrl(extensionId, page = '') {
|
|
77
|
+
const normalized = normalizeExtensionPage(page);
|
|
78
|
+
return `chrome-extension://${extensionId}/${normalized}`;
|
|
79
|
+
}
|
|
80
|
+
export function resolveExtensionPageUrl(extensionId, page = '') {
|
|
81
|
+
if (/^chrome-extension:\/\//.test(page))
|
|
82
|
+
return page;
|
|
83
|
+
return extensionPageUrl(extensionId, page);
|
|
84
|
+
}
|
|
85
|
+
export function extensionIdFromUrl(url) {
|
|
86
|
+
return /^chrome-extension:\/\/([^/]+)\//.exec(url)?.[1];
|
|
87
|
+
}
|
|
88
|
+
function wait(ms) {
|
|
89
|
+
return new Promise((resolve) => {
|
|
90
|
+
setTimeout(resolve, ms);
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
function isRecoverableExtensionPageOpenError(error) {
|
|
94
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
95
|
+
return /ERR_BLOCKED_BY_CLIENT|page crashed|target page, context or browser has been closed/i.test(message);
|
|
96
|
+
}
|
|
97
|
+
async function discoverExtensionIdFromRuntime(context, timeoutMs) {
|
|
98
|
+
const workerId = context.serviceWorkers().map((worker) => extensionIdFromUrl(worker.url())).find(Boolean);
|
|
99
|
+
if (workerId)
|
|
100
|
+
return workerId;
|
|
101
|
+
const pageId = context.pages().map((page) => extensionIdFromUrl(page.url())).find(Boolean);
|
|
102
|
+
if (pageId)
|
|
103
|
+
return pageId;
|
|
104
|
+
const worker = await context.waitForEvent('serviceworker', { timeout: timeoutMs }).catch(() => undefined);
|
|
105
|
+
if (worker) {
|
|
106
|
+
const extensionId = extensionIdFromUrl(worker.url());
|
|
107
|
+
if (extensionId)
|
|
108
|
+
return extensionId;
|
|
109
|
+
}
|
|
110
|
+
return undefined;
|
|
111
|
+
}
|
|
112
|
+
async function discoverExtensionIdFromManagementApi(context, extensionName) {
|
|
113
|
+
const page = await context.newPage();
|
|
114
|
+
try {
|
|
115
|
+
await page.goto('chrome://extensions', { waitUntil: 'domcontentloaded' });
|
|
116
|
+
const extensions = await page.evaluate(() => {
|
|
117
|
+
const chromeApi = globalThis;
|
|
118
|
+
return new Promise((resolve, reject) => {
|
|
119
|
+
if (!chromeApi.chrome?.management?.getAll) {
|
|
120
|
+
reject(new Error('chrome.management.getAll is not available on chrome://extensions.'));
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
chromeApi.chrome.management.getAll((items) => {
|
|
124
|
+
const error = chromeApi.chrome?.runtime?.lastError;
|
|
125
|
+
if (error)
|
|
126
|
+
reject(new Error(error.message ?? 'Unable to enumerate Chrome extensions.'));
|
|
127
|
+
else
|
|
128
|
+
resolve(items);
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
const exact = extensions.find((extension) => extension.name.toLowerCase() === extensionName.toLowerCase());
|
|
133
|
+
if (exact)
|
|
134
|
+
return exact.id;
|
|
135
|
+
const available = extensions.map((extension) => extension.name).sort().join(', ');
|
|
136
|
+
throw new Error(`Unable to find extension "${extensionName}". Installed extensions: ${available || 'none'}.`);
|
|
137
|
+
}
|
|
138
|
+
finally {
|
|
139
|
+
await page.close().catch(() => undefined);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
export async function discoverRealWalletExtensionId(context, options = {}) {
|
|
143
|
+
const timeoutMs = options.timeoutMs ?? 10_000;
|
|
144
|
+
const runtimeId = await discoverExtensionIdFromRuntime(context, timeoutMs);
|
|
145
|
+
if (runtimeId)
|
|
146
|
+
return runtimeId;
|
|
147
|
+
if (!options.extensionName) {
|
|
148
|
+
throw new Error('Unable to discover extension ID from runtime pages/service workers. Pass extensionName or extensionId.');
|
|
149
|
+
}
|
|
150
|
+
return discoverExtensionIdFromManagementApi(context, options.extensionName);
|
|
151
|
+
}
|
|
152
|
+
export async function openRealWalletExtensionPage(context, extensionId, page = '') {
|
|
153
|
+
const url = resolveExtensionPageUrl(extensionId, page);
|
|
154
|
+
const acceptsHashRoute = !url.includes('#');
|
|
155
|
+
let lastError;
|
|
156
|
+
for (let attempt = 0; attempt < 6; attempt += 1) {
|
|
157
|
+
const existing = context
|
|
158
|
+
.pages()
|
|
159
|
+
.find((candidate) => {
|
|
160
|
+
if (candidate.isClosed())
|
|
161
|
+
return false;
|
|
162
|
+
const candidateUrl = candidate.url();
|
|
163
|
+
return candidateUrl === url || (acceptsHashRoute && candidateUrl.startsWith(`${url}#`));
|
|
164
|
+
});
|
|
165
|
+
const target = existing ?? (await context.newPage());
|
|
166
|
+
try {
|
|
167
|
+
if (target.url() !== url)
|
|
168
|
+
await target.goto(url, { waitUntil: 'domcontentloaded' });
|
|
169
|
+
await target.waitForLoadState('domcontentloaded').catch(() => undefined);
|
|
170
|
+
return target;
|
|
171
|
+
}
|
|
172
|
+
catch (error) {
|
|
173
|
+
lastError = error;
|
|
174
|
+
if (attempt === 5 || !isRecoverableExtensionPageOpenError(error))
|
|
175
|
+
throw error;
|
|
176
|
+
await target.close().catch(() => undefined);
|
|
177
|
+
await wait(750 + attempt * 750);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
throw lastError;
|
|
181
|
+
}
|
|
182
|
+
export async function launchRealWalletExtension(options) {
|
|
183
|
+
const extensionPath = path.resolve(options.extensionPath);
|
|
184
|
+
if (!fs.existsSync(extensionPath)) {
|
|
185
|
+
throw new Error(`Wallet extension path does not exist: ${extensionPath}`);
|
|
186
|
+
}
|
|
187
|
+
const manifest = readExtensionManifest(extensionPath);
|
|
188
|
+
const extensionName = options.extensionName ?? usableManifestString(manifest.name);
|
|
189
|
+
const headless = resolveRealWalletHeadless(options.headless);
|
|
190
|
+
const profile = resolveRealWalletProfile(options.profileDir);
|
|
191
|
+
const context = await chromium
|
|
192
|
+
.launchPersistentContext(profile.userDataDir, {
|
|
193
|
+
args: [
|
|
194
|
+
...(profile.profileDirectory ? [`--profile-directory=${profile.profileDirectory}`] : []),
|
|
195
|
+
`--disable-extensions-except=${extensionPath}`,
|
|
196
|
+
`--load-extension=${extensionPath}`,
|
|
197
|
+
...(options.launchArgs ?? []),
|
|
198
|
+
],
|
|
199
|
+
baseURL: options.baseURL,
|
|
200
|
+
channel: 'chromium',
|
|
201
|
+
headless,
|
|
202
|
+
locale: options.locale ?? 'en-US',
|
|
203
|
+
slowMo: options.slowMo,
|
|
204
|
+
})
|
|
205
|
+
.catch((error) => {
|
|
206
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
207
|
+
if (/executable doesn't exist/i.test(message)) {
|
|
208
|
+
throw new Error("Real-wallet extension mode needs the full Chromium build for channel 'chromium' — a " +
|
|
209
|
+
'chromium_headless_shell-only install cannot load extensions. ' +
|
|
210
|
+
'Run: npx playwright install chromium\n' +
|
|
211
|
+
message);
|
|
212
|
+
}
|
|
213
|
+
throw error;
|
|
214
|
+
});
|
|
215
|
+
let extensionId;
|
|
216
|
+
let page;
|
|
217
|
+
try {
|
|
218
|
+
extensionId =
|
|
219
|
+
options.extensionId ??
|
|
220
|
+
(await discoverRealWalletExtensionId(context, {
|
|
221
|
+
extensionName,
|
|
222
|
+
}));
|
|
223
|
+
const initialPage = options.initialPage === undefined ? extensionManifestDefaultPage(manifest) : options.initialPage;
|
|
224
|
+
page =
|
|
225
|
+
initialPage === false || initialPage === undefined
|
|
226
|
+
? undefined
|
|
227
|
+
: await openRealWalletExtensionPage(context, extensionId, initialPage);
|
|
228
|
+
}
|
|
229
|
+
catch (error) {
|
|
230
|
+
await context.close().catch(() => undefined);
|
|
231
|
+
throw error;
|
|
232
|
+
}
|
|
233
|
+
return {
|
|
234
|
+
close: () => context.close(),
|
|
235
|
+
context,
|
|
236
|
+
extensionId,
|
|
237
|
+
extensionPath,
|
|
238
|
+
manifest,
|
|
239
|
+
page,
|
|
240
|
+
profile,
|
|
241
|
+
extensionUrl: (targetPage = '') => extensionPageUrl(extensionId, targetPage),
|
|
242
|
+
openPage: (targetPage = '') => openRealWalletExtensionPage(context, extensionId, targetPage),
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
//# sourceMappingURL=real-wallet-extension.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"real-wallet-extension.js","sourceRoot":"","sources":["../src/real-wallet-extension.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { type BuildWalletProfileOptions } from './real-wallet-cache.js';
|
|
2
|
+
import { type RealWalletSession, type RealWalletSetup, type WalletGeneration } from './real-wallet.js';
|
|
3
|
+
export type RealWalletFixtureOptions = {
|
|
4
|
+
/** Wallet setup. Defaults to WEB3_TESTER_REAL_WALLET_SECRET_RECOVERY_PHRASE / _PASSWORD. */
|
|
5
|
+
setup?: RealWalletSetup;
|
|
6
|
+
/**
|
|
7
|
+
* Unpacked MetaMask directory. Defaults to
|
|
8
|
+
* WEB3_TESTER_REAL_WALLET_EXTENSION_PATH, or downloads the pinned release.
|
|
9
|
+
*/
|
|
10
|
+
extensionPath?: string;
|
|
11
|
+
/** MetaMask version to download when extensionPath is not given. */
|
|
12
|
+
metamaskVersion?: string;
|
|
13
|
+
/**
|
|
14
|
+
* Explicit persistent profile directory. Disables the profile cache; the
|
|
15
|
+
* test reuses (and mutates) this profile directly, so parallel tests must
|
|
16
|
+
* not share it.
|
|
17
|
+
*/
|
|
18
|
+
profileDir?: string;
|
|
19
|
+
baseURL?: string;
|
|
20
|
+
expectedAddress?: string;
|
|
21
|
+
/**
|
|
22
|
+
* MetaMask UI generation to drive ('12x' | '13x'). Defaults to the major
|
|
23
|
+
* version in the extension's manifest; set explicitly for custom builds.
|
|
24
|
+
*/
|
|
25
|
+
generation?: WalletGeneration;
|
|
26
|
+
/**
|
|
27
|
+
* Run the browser headless. No default — choose explicitly here or via
|
|
28
|
+
* WEB3_TESTER_REAL_WALLET_HEADLESS=true|false. Headed is the fully
|
|
29
|
+
* validated mode.
|
|
30
|
+
*/
|
|
31
|
+
headless?: boolean;
|
|
32
|
+
/**
|
|
33
|
+
* One-time profile customization baked into the cached profile (import
|
|
34
|
+
* keys, add accounts/networks/tokens) — Synpress defineWalletSetup-style.
|
|
35
|
+
* Ignored when an explicit profileDir bypasses the cache.
|
|
36
|
+
*/
|
|
37
|
+
profileSetup?: BuildWalletProfileOptions['customize'];
|
|
38
|
+
};
|
|
39
|
+
export type RealWalletFixtures = {
|
|
40
|
+
realWalletOptions: RealWalletFixtureOptions;
|
|
41
|
+
realWallet: RealWalletSession;
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Playwright fixtures for real-MetaMask tests. Each test gets a disposable
|
|
45
|
+
* clone of a cached, pre-onboarded profile (built once per seed phrase +
|
|
46
|
+
* extension version), so tests are isolated, parallel-safe, and skip
|
|
47
|
+
* onboarding cost after the first run. `context` and `page` are rebound to
|
|
48
|
+
* the persistent extension context.
|
|
49
|
+
*/
|
|
50
|
+
export declare const test: import("@playwright/test").TestType<import("@playwright/test").PlaywrightTestArgs & import("@playwright/test").PlaywrightTestOptions & RealWalletFixtures, import("@playwright/test").PlaywrightWorkerArgs & import("@playwright/test").PlaywrightWorkerOptions>;
|
|
51
|
+
export { expect } from './matchers.js';
|
|
52
|
+
//# sourceMappingURL=real-wallet-fixtures.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"real-wallet-fixtures.d.ts","sourceRoot":"","sources":["../src/real-wallet-fixtures.ts"],"names":[],"mappings":"AAGA,OAAO,EAGL,KAAK,yBAAyB,EAC/B,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EAEL,KAAK,iBAAiB,EACtB,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACtB,MAAM,kBAAkB,CAAC;AAE1B,MAAM,MAAM,wBAAwB,GAAG;IACrC,4FAA4F;IAC5F,KAAK,CAAC,EAAE,eAAe,CAAC;IACxB;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,oEAAoE;IACpE,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;OAGG;IACH,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B;;;;OAIG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;;OAIG;IACH,YAAY,CAAC,EAAE,yBAAyB,CAAC,WAAW,CAAC,CAAC;CACvD,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,iBAAiB,EAAE,wBAAwB,CAAC;IAC5C,UAAU,EAAE,iBAAiB,CAAC;CAC/B,CAAC;AAiBF;;;;;;GAMG;AACH,eAAO,MAAM,IAAI,kQAoFf,CAAC;AAGH,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { test as base } from '@playwright/test';
|
|
3
|
+
import { prepareMetaMaskExtension } from './metamask-extension.js';
|
|
4
|
+
import { buildWalletProfile, cloneWalletProfile, } from './real-wallet-cache.js';
|
|
5
|
+
import { benchmarkForTest, benchmarkObjectMethods } from './benchmark.js';
|
|
6
|
+
import { launchRealWallet, } from './real-wallet.js';
|
|
7
|
+
const setupFromEnv = () => ({
|
|
8
|
+
password: process.env.WEB3_TESTER_REAL_WALLET_PASSWORD || undefined,
|
|
9
|
+
seedPhrase: process.env.WEB3_TESTER_REAL_WALLET_SECRET_RECOVERY_PHRASE || undefined,
|
|
10
|
+
});
|
|
11
|
+
const assertChromiumProject = (browserName) => {
|
|
12
|
+
if (browserName !== 'chromium') {
|
|
13
|
+
throw new Error('@marigoldlabs/web3-tester/real-wallet-fixtures launch a Chromium extension context. ' +
|
|
14
|
+
`The current Playwright project uses "${browserName}". Exclude real-wallet tests from non-Chromium ` +
|
|
15
|
+
'projects, or run them in a dedicated Chromium project.');
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Playwright fixtures for real-MetaMask tests. Each test gets a disposable
|
|
20
|
+
* clone of a cached, pre-onboarded profile (built once per seed phrase +
|
|
21
|
+
* extension version), so tests are isolated, parallel-safe, and skip
|
|
22
|
+
* onboarding cost after the first run. `context` and `page` are rebound to
|
|
23
|
+
* the persistent extension context.
|
|
24
|
+
*/
|
|
25
|
+
export const test = base.extend({
|
|
26
|
+
realWalletOptions: [
|
|
27
|
+
async ({}, use) => {
|
|
28
|
+
await use({});
|
|
29
|
+
},
|
|
30
|
+
{ option: true },
|
|
31
|
+
],
|
|
32
|
+
realWallet: async ({ realWalletOptions, browserName }, use, testInfo) => {
|
|
33
|
+
assertChromiumProject(browserName);
|
|
34
|
+
const benchmark = benchmarkForTest(testInfo, { suite: 'real-wallet' });
|
|
35
|
+
let session;
|
|
36
|
+
try {
|
|
37
|
+
const options = realWalletOptions;
|
|
38
|
+
const setup = options.setup ?? setupFromEnv();
|
|
39
|
+
const extensionPath = options.extensionPath ??
|
|
40
|
+
process.env.WEB3_TESTER_REAL_WALLET_EXTENSION_PATH ??
|
|
41
|
+
(await benchmark.measure('realWallet.prepareMetaMaskExtension', () => prepareMetaMaskExtension({ version: options.metamaskVersion })));
|
|
42
|
+
let profileDir = options.profileDir ?? process.env.WEB3_TESTER_REAL_WALLET_PROFILE_DIR;
|
|
43
|
+
if (!profileDir) {
|
|
44
|
+
if (!setup.seedPhrase) {
|
|
45
|
+
throw new Error('Real-wallet fixtures need a seed phrase (realWalletOptions.setup.seedPhrase or ' +
|
|
46
|
+
'WEB3_TESTER_REAL_WALLET_SECRET_RECOVERY_PHRASE) to build a cached profile, ' +
|
|
47
|
+
'or an explicit profileDir pointing at a prepared MetaMask profile.');
|
|
48
|
+
}
|
|
49
|
+
const cachedProfile = await benchmark.measure('realWallet.buildWalletProfile', () => buildWalletProfile({
|
|
50
|
+
extensionPath,
|
|
51
|
+
setup,
|
|
52
|
+
headless: options.headless,
|
|
53
|
+
generation: options.generation,
|
|
54
|
+
customize: options.profileSetup,
|
|
55
|
+
}));
|
|
56
|
+
profileDir = await benchmark.measure('realWallet.cloneWalletProfile', () => cloneWalletProfile(cachedProfile, path.join(testInfo.outputDir, 'metamask-profile')));
|
|
57
|
+
}
|
|
58
|
+
session = await benchmark.measure('realWallet.launchRealWallet', () => launchRealWallet({
|
|
59
|
+
baseURL: options.baseURL,
|
|
60
|
+
expectedAddress: options.expectedAddress,
|
|
61
|
+
extensionPath,
|
|
62
|
+
generation: options.generation,
|
|
63
|
+
headless: options.headless,
|
|
64
|
+
profileDir,
|
|
65
|
+
setup,
|
|
66
|
+
}));
|
|
67
|
+
await use(benchmarkObjectMethods(session, benchmark, { prefix: 'realWallet', exclude: ['close'] }));
|
|
68
|
+
}
|
|
69
|
+
finally {
|
|
70
|
+
if (session) {
|
|
71
|
+
const activeSession = session;
|
|
72
|
+
await benchmark.measure('realWallet.close', () => activeSession.close().catch(() => undefined));
|
|
73
|
+
}
|
|
74
|
+
await benchmark.flush();
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
context: async ({ realWallet }, use) => {
|
|
78
|
+
await use(realWallet.context);
|
|
79
|
+
},
|
|
80
|
+
page: async ({ context }, use) => {
|
|
81
|
+
const page = await context.newPage();
|
|
82
|
+
await use(page);
|
|
83
|
+
await page.close().catch(() => undefined);
|
|
84
|
+
},
|
|
85
|
+
});
|
|
86
|
+
// The web3-extended expect: every matcher from ./matchers.js, zero migration.
|
|
87
|
+
export { expect } from './matchers.js';
|
|
88
|
+
//# sourceMappingURL=real-wallet-fixtures.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"real-wallet-fixtures.js","sourceRoot":"","sources":["../src/real-wallet-fixtures.ts"],"names":[],"mappings":"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"}
|
package/dist/real-wallet.d.ts
CHANGED
|
@@ -1,8 +1,15 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import type { BrowserContext, Locator } from '@playwright/test';
|
|
2
|
+
export { resolveRealWalletHeadless, resolveRealWalletProfile } from './real-wallet-extension.js';
|
|
3
|
+
export type { RealWalletProfile } from './real-wallet-extension.js';
|
|
4
|
+
/**
|
|
5
|
+
* MetaMask UI generation the selector surface drives. '13x' is the
|
|
6
|
+
* multichain UI (validated against 13.34.1, the pinned default); '12x' is
|
|
7
|
+
* the classic UI (last validated against 12.23.1). Both are first-class
|
|
8
|
+
* configuration: the generation is derived from the extension manifest at
|
|
9
|
+
* launch and selects which generation's selectors run — the other
|
|
10
|
+
* generation's selectors are not probed as fallbacks.
|
|
11
|
+
*/
|
|
12
|
+
export type WalletGeneration = '12x' | '13x';
|
|
6
13
|
export type RealWalletSetup = {
|
|
7
14
|
password?: string;
|
|
8
15
|
seedPhrase?: string;
|
|
@@ -17,12 +24,49 @@ export type RealWalletLaunchOptions = {
|
|
|
17
24
|
expectedAddress?: string;
|
|
18
25
|
extensionName?: string;
|
|
19
26
|
extensionPath: string;
|
|
27
|
+
/**
|
|
28
|
+
* UI generation to drive. Defaults to the major version in the extension's
|
|
29
|
+
* manifest (>= 13 → '13x'). Set explicitly for custom builds whose
|
|
30
|
+
* manifest version does not reflect their UI generation.
|
|
31
|
+
*/
|
|
32
|
+
generation?: WalletGeneration;
|
|
33
|
+
/**
|
|
34
|
+
* Run the browser headless. There is deliberately no default — choose
|
|
35
|
+
* explicitly here or via WEB3_TESTER_REAL_WALLET_HEADLESS=true|false.
|
|
36
|
+
* Headed is the fully validated mode; headless loads the extension through
|
|
37
|
+
* the full Chromium build (channel 'chromium') and is validated for
|
|
38
|
+
* extension load + clipboard, but the full confirmation journey is not
|
|
39
|
+
* proven headless yet.
|
|
40
|
+
*/
|
|
20
41
|
headless?: boolean;
|
|
21
42
|
profileDir: string;
|
|
22
43
|
setup?: RealWalletSetup;
|
|
23
44
|
slowMo?: number;
|
|
24
45
|
};
|
|
46
|
+
export type RealWalletNetwork = {
|
|
47
|
+
name: string;
|
|
48
|
+
rpcUrl: string;
|
|
49
|
+
chainId: number;
|
|
50
|
+
symbol: string;
|
|
51
|
+
blockExplorerUrl?: string;
|
|
52
|
+
};
|
|
53
|
+
export type RealWalletToken = {
|
|
54
|
+
/** ERC-20 contract address (0x + 40 hex). */
|
|
55
|
+
address: string;
|
|
56
|
+
/** Optional symbol override; MetaMask usually autofills from the contract. */
|
|
57
|
+
symbol?: string;
|
|
58
|
+
/** Optional decimals override. */
|
|
59
|
+
decimals?: number;
|
|
60
|
+
/**
|
|
61
|
+
* 13.x only: network to import the token on (name as shown in the import
|
|
62
|
+
* modal's network selector). Defaults to the wallet's active network.
|
|
63
|
+
*/
|
|
64
|
+
networkName?: string;
|
|
65
|
+
};
|
|
25
66
|
export type RealWalletController = {
|
|
67
|
+
addNetwork(network: RealWalletNetwork): Promise<void>;
|
|
68
|
+
approveNewNetwork(): Promise<void>;
|
|
69
|
+
approveSwitchNetwork(): Promise<void>;
|
|
26
70
|
approveTokenPermission(options?: {
|
|
27
71
|
gasSetting?: RealWalletGasSettings;
|
|
28
72
|
spendLimit?: 'max' | number;
|
|
@@ -33,27 +77,83 @@ export type RealWalletController = {
|
|
|
33
77
|
}): Promise<void>;
|
|
34
78
|
connectToDapp(accounts?: string[]): Promise<void>;
|
|
35
79
|
getAccountAddress(): Promise<string>;
|
|
80
|
+
rejectNewNetwork(): Promise<void>;
|
|
36
81
|
rejectSignature(): Promise<void>;
|
|
82
|
+
rejectSwitchNetwork(): Promise<void>;
|
|
83
|
+
rejectTokenPermission(): Promise<void>;
|
|
37
84
|
rejectTransaction(): Promise<void>;
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
approveTokenPermission(options?: {
|
|
41
|
-
gasSetting?: RealWalletGasSettings;
|
|
42
|
-
spendLimit?: 'max' | number;
|
|
85
|
+
switchNetwork(name: string, options?: {
|
|
86
|
+
chainId?: number;
|
|
43
87
|
}): Promise<void>;
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
88
|
+
/** Creates the next derived account on the active SRP, optionally named. */
|
|
89
|
+
addNewAccount(name?: string): Promise<void>;
|
|
90
|
+
/** Synpress-parity alias for approveAddToken(). */
|
|
91
|
+
addNewToken(): Promise<void>;
|
|
92
|
+
/** Approves a pending wallet_watchAsset ("Add suggested tokens") prompt. */
|
|
93
|
+
approveAddToken(): Promise<void>;
|
|
94
|
+
rejectAddToken(): Promise<void>;
|
|
95
|
+
/**
|
|
96
|
+
* confirmTransaction, then watch the newest activity row until confirmed.
|
|
97
|
+
* The hash is read best-effort via "Copy transaction ID" — undefined when
|
|
98
|
+
* the clipboard read fails (the mining wait still completes).
|
|
99
|
+
*/
|
|
100
|
+
confirmTransactionAndWaitForMining(options?: {
|
|
47
101
|
gasSetting?: RealWalletGasSettings;
|
|
48
|
-
|
|
49
|
-
|
|
102
|
+
/** Wait budget for the activity row to reach confirmed. Default 60_000. */
|
|
103
|
+
timeoutMs?: number;
|
|
104
|
+
}): Promise<{
|
|
105
|
+
txHash?: `0x${string}`;
|
|
106
|
+
}>;
|
|
107
|
+
/** Manual token import: tokens tab → Import tokens → Custom token form. */
|
|
108
|
+
importToken(token: RealWalletToken): Promise<void>;
|
|
109
|
+
/** Imports a private-key account ("Imported" keyring); throws on MetaMask errors (e.g. duplicates). */
|
|
110
|
+
importWalletFromPrivateKey(privateKey: string): Promise<void>;
|
|
111
|
+
/** Global menu → Lock; resolves once the unlock screen is visible. */
|
|
112
|
+
lock(): Promise<void>;
|
|
113
|
+
renameAccount(currentName: string, newName: string): Promise<void>;
|
|
114
|
+
/** Clears activity/nonce data (12.x: Advanced; 13.x: Developer tools). */
|
|
115
|
+
resetAccount(): Promise<void>;
|
|
116
|
+
/** Selects an account in the picker by display name or (best-effort on 13.x) address. */
|
|
117
|
+
switchAccount(nameOrAddress: string): Promise<void>;
|
|
118
|
+
/** Idempotent when `on` is given (reads the toggle first); blind toggle when omitted. */
|
|
119
|
+
toggleShowTestNetworks(on?: boolean): Promise<void>;
|
|
120
|
+
/** Unlocks with the given password or the password from launch setup. */
|
|
121
|
+
unlock(password?: string): Promise<void>;
|
|
122
|
+
/** Resolves once MetaMask is no longer showing the locked screen. */
|
|
123
|
+
waitForUnlocked(): Promise<void>;
|
|
124
|
+
};
|
|
125
|
+
export type RealWalletSession = RealWalletController & {
|
|
126
|
+
close(): Promise<void>;
|
|
50
127
|
context: BrowserContext;
|
|
51
128
|
extensionId: string;
|
|
52
|
-
getAccountAddress(): Promise<string>;
|
|
53
|
-
rejectSignature(): Promise<void>;
|
|
54
|
-
rejectTransaction(): Promise<void>;
|
|
55
129
|
wallet: RealWalletController;
|
|
56
130
|
};
|
|
57
|
-
|
|
131
|
+
/**
|
|
132
|
+
* A selector-stack entry optionally scoped to one UI generation. Bare
|
|
133
|
+
* locators apply to both generations; tagged entries are dropped — not
|
|
134
|
+
* probed — when the wallet is configured for the other generation, so a
|
|
135
|
+
* wrong-generation selector can never burn its probe budget.
|
|
136
|
+
*/
|
|
137
|
+
type GenLocator = Locator | {
|
|
138
|
+
gen: WalletGeneration;
|
|
139
|
+
loc: Locator;
|
|
140
|
+
};
|
|
141
|
+
/**
|
|
142
|
+
* @internal Resolves a generation-annotated selector stack against the
|
|
143
|
+
* configured generation: tagged entries of the other generation are dropped,
|
|
144
|
+
* bare entries pass through, and relative order is preserved.
|
|
145
|
+
*/
|
|
146
|
+
export declare function resolveGenLocators(locators: readonly GenLocator[], generation: WalletGeneration): Locator[];
|
|
147
|
+
/** @internal Maps an extension manifest version to the UI generation it ships. */
|
|
148
|
+
export declare function walletGenerationForVersion(version: string): WalletGeneration;
|
|
149
|
+
/** @internal Validates and trims a 32-byte hex private key (0x optional). */
|
|
150
|
+
export declare function normalizePrivateKey(privateKey: string): string;
|
|
151
|
+
/** @internal */
|
|
152
|
+
export declare function isFullTxHash(value: string | undefined): value is `0x${string}`;
|
|
153
|
+
/**
|
|
154
|
+
* @internal Matches an account picker row by display name, or by full /
|
|
155
|
+
* shortened address when the identifier is an address.
|
|
156
|
+
*/
|
|
157
|
+
export declare function accountRowMatcher(identifier: string): RegExp;
|
|
58
158
|
export declare function launchRealWallet(options: RealWalletLaunchOptions): Promise<RealWalletSession>;
|
|
59
159
|
//# sourceMappingURL=real-wallet.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"real-wallet.d.ts","sourceRoot":"","sources":["../src/real-wallet.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"real-wallet.d.ts","sourceRoot":"","sources":["../src/real-wallet.ts"],"names":[],"mappings":"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"}
|