w3wallets 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -18,6 +18,7 @@ npm install -D w3wallets
18
18
  The `Backpack` and the `Polkadot{.js}` wallets are currently supported.
19
19
 
20
20
  <p align="center">
21
+ <img src="https://images.ctfassets.net/clixtyxoaeas/1ezuBGezqfIeifWdVtwU4c/d970d4cdf13b163efddddd5709164d2e/MetaMask-icon-Fox.svg" alt="Metamask Logo" width="60"/>
21
22
  <img src="https://raw.githubusercontent.com/coral-xyz/backpack/refs/heads/master/assets/backpack.png" alt="Backpack Logo" width="60"/>
22
23
  <img src="https://polkadot.js.org/logo.svg" alt="Polkadot JS Logo" width="60"/>
23
24
  </p>
@@ -39,7 +40,11 @@ Install needed wallets into the chromium using `withWallets`.
39
40
  import { withWallets } from "w3wallets";
40
41
  import { test as base } from "@playwright/test";
41
42
 
42
- export const test = withWallets(base, 'backpack', 'polkadotJS').extend<BaseFixture>({
43
+ export const test = withWallets(
44
+ base,
45
+ "backpack",
46
+ "polkadotJS",
47
+ ).extend<BaseFixture>({
43
48
  magic: (_, use) => use(42),
44
49
  });
45
50
 
@@ -52,6 +57,12 @@ export { expect } from "@playwright/test";
52
57
 
53
58
  #### 3. Use the installed wallets in tests
54
59
 
60
+ Most of the actions will use the following methods:
61
+
62
+ 1. `onboard`: to set up your wallet
63
+ 2. `approve`: for operations that confirm actions
64
+ 3. `deny`: for actions that reject or cancel operations
65
+
55
66
  ```ts
56
67
  import { test } from "./your-fixture";
57
68
 
package/dist/index.d.mts CHANGED
@@ -6,7 +6,7 @@ import { Page, test, BrowserContext } from '@playwright/test';
6
6
  */
7
7
  type BackPackNetwork = "Solana" | "Eclipse" | "Ethereum" | "Polygon" | "Base" | "Arbitrum" | "Optimism";
8
8
 
9
- type WalletName = "backpack" | "polkadotJS";
9
+ type WalletName = "backpack" | "polkadotJS" | "metamask";
10
10
  type NoDuplicates<T extends readonly unknown[], Acc extends readonly unknown[] = []> = T extends [infer Head, ...infer Tail] ? Head extends Acc[number] ? never : [Head, ...NoDuplicates<Tail, [...Acc, Head]>] : T;
11
11
  interface IWallet {
12
12
  gotoOnboardPage(): Promise<void>;
@@ -52,10 +52,32 @@ declare class PolkadotJS extends Wallet {
52
52
  private _getLabeledInput;
53
53
  }
54
54
 
55
+ type NetworkSettings = {
56
+ name: string;
57
+ rpc: string;
58
+ chainId: number;
59
+ currencySymbol: string;
60
+ };
61
+
62
+ declare class Metamask extends Wallet {
63
+ private defaultPassword;
64
+ gotoOnboardPage(): Promise<void>;
65
+ /**
66
+ *
67
+ * @param mnemonic 12-word mnemonic seed phrase
68
+ */
69
+ onboard(mnemonic: string, password?: string): Promise<void>;
70
+ connectToNetwork(settings: NetworkSettings, switchNetwork?: boolean): Promise<void>;
71
+ approve(): Promise<void>;
72
+ deny(): Promise<void>;
73
+ private usingNotificationPage;
74
+ }
75
+
55
76
  declare function withWallets<T extends readonly WalletName[]>(test: typeof test, ...config: NoDuplicates<T>): playwright_test.TestType<playwright_test.PlaywrightTestArgs & playwright_test.PlaywrightTestOptions & {
56
77
  context: BrowserContext;
57
78
  backpack: Backpack;
58
79
  polkadotJS: PolkadotJS;
80
+ metamask: Metamask;
59
81
  }, playwright_test.PlaywrightWorkerArgs & playwright_test.PlaywrightWorkerOptions>;
60
82
 
61
83
  export { withWallets };
package/dist/index.d.ts CHANGED
@@ -6,7 +6,7 @@ import { Page, test, BrowserContext } from '@playwright/test';
6
6
  */
7
7
  type BackPackNetwork = "Solana" | "Eclipse" | "Ethereum" | "Polygon" | "Base" | "Arbitrum" | "Optimism";
8
8
 
9
- type WalletName = "backpack" | "polkadotJS";
9
+ type WalletName = "backpack" | "polkadotJS" | "metamask";
10
10
  type NoDuplicates<T extends readonly unknown[], Acc extends readonly unknown[] = []> = T extends [infer Head, ...infer Tail] ? Head extends Acc[number] ? never : [Head, ...NoDuplicates<Tail, [...Acc, Head]>] : T;
11
11
  interface IWallet {
12
12
  gotoOnboardPage(): Promise<void>;
@@ -52,10 +52,32 @@ declare class PolkadotJS extends Wallet {
52
52
  private _getLabeledInput;
53
53
  }
54
54
 
55
+ type NetworkSettings = {
56
+ name: string;
57
+ rpc: string;
58
+ chainId: number;
59
+ currencySymbol: string;
60
+ };
61
+
62
+ declare class Metamask extends Wallet {
63
+ private defaultPassword;
64
+ gotoOnboardPage(): Promise<void>;
65
+ /**
66
+ *
67
+ * @param mnemonic 12-word mnemonic seed phrase
68
+ */
69
+ onboard(mnemonic: string, password?: string): Promise<void>;
70
+ connectToNetwork(settings: NetworkSettings, switchNetwork?: boolean): Promise<void>;
71
+ approve(): Promise<void>;
72
+ deny(): Promise<void>;
73
+ private usingNotificationPage;
74
+ }
75
+
55
76
  declare function withWallets<T extends readonly WalletName[]>(test: typeof test, ...config: NoDuplicates<T>): playwright_test.TestType<playwright_test.PlaywrightTestArgs & playwright_test.PlaywrightTestOptions & {
56
77
  context: BrowserContext;
57
78
  backpack: Backpack;
58
79
  polkadotJS: PolkadotJS;
80
+ metamask: Metamask;
59
81
  }, playwright_test.PlaywrightWorkerArgs & playwright_test.PlaywrightWorkerOptions>;
60
82
 
61
83
  export { withWallets };
package/dist/index.js CHANGED
@@ -42,7 +42,7 @@ var import_fs = __toESM(require("fs"));
42
42
  var sleep = (ms) => new Promise((r) => setTimeout(r, ms));
43
43
 
44
44
  // src/withWallets.ts
45
- var import_test3 = require("@playwright/test");
45
+ var import_test4 = require("@playwright/test");
46
46
 
47
47
  // src/backpack/backpack.ts
48
48
  var import_test = require("@playwright/test");
@@ -188,13 +188,87 @@ var PolkadotJS = class extends Wallet {
188
188
  }
189
189
  };
190
190
 
191
+ // src/metamask/metamask.ts
192
+ var import_test3 = require("@playwright/test");
193
+ var Metamask = class extends Wallet {
194
+ defaultPassword = "11111111";
195
+ async gotoOnboardPage() {
196
+ await this.page.goto(`chrome-extension://${this.extensionId}/home.html`);
197
+ }
198
+ /**
199
+ *
200
+ * @param mnemonic 12-word mnemonic seed phrase
201
+ */
202
+ async onboard(mnemonic, password = this.defaultPassword) {
203
+ await this.page.getByTestId("onboarding-terms-checkbox").click();
204
+ await this.page.getByTestId("onboarding-import-wallet").click();
205
+ await this.page.getByTestId("metametrics-i-agree").click();
206
+ for (const [i, word] of mnemonic.split(" ").entries())
207
+ await this.page.getByTestId(`import-srp__srp-word-${i}`).fill(word);
208
+ await this.page.getByTestId("import-srp-confirm").click();
209
+ await this.page.getByTestId("create-password-new").fill(password);
210
+ await this.page.getByTestId("create-password-confirm").fill(password);
211
+ await this.page.getByTestId("create-password-terms").click();
212
+ await this.page.getByTestId("create-password-import").click();
213
+ await this.page.getByTestId("onboarding-complete-done").click();
214
+ await this.page.getByTestId("pin-extension-next").click();
215
+ await this.page.getByTestId("pin-extension-done").click();
216
+ }
217
+ async connectToNetwork(settings, switchNetwork = true) {
218
+ await this.page.locator(".mm-picker-network").click();
219
+ await this.page.getByRole("button", { name: "Add a custom network" }).click();
220
+ await this.page.getByTestId("network-form-network-name").fill(settings.name);
221
+ await this.page.getByTestId("network-form-chain-id").fill(settings.chainId.toString());
222
+ await this.page.getByTestId("network-form-ticker-input").fill(settings.currencySymbol);
223
+ await this.page.getByTestId("test-add-rpc-drop-down").click();
224
+ await this.page.getByRole("button", { name: "Add RPC URL" }).click();
225
+ await this.page.getByTestId("rpc-url-input-test").fill(settings.rpc);
226
+ await this.page.getByRole("button", { name: "Add URL" }).click();
227
+ await this.page.getByRole("button", { name: "Save" }).click();
228
+ if (switchNetwork) {
229
+ await this.page.locator(".mm-picker-network").click();
230
+ await this.page.getByTestId(settings.name).click();
231
+ }
232
+ }
233
+ // async approve() {
234
+ // return this.usingNotificationPage((p) =>
235
+ // p
236
+ // .locator(
237
+ // '[data-test-id="confirm-footer-button"], [data-test-id="confirm-btn"]',
238
+ // )
239
+ // .click(),
240
+ // );
241
+ // }
242
+ async approve() {
243
+ const p = await this.page.context().newPage();
244
+ await p.goto(`chrome-extension://${this.extensionId}/notification.html`);
245
+ await p.locator(
246
+ '[data-testid="confirm-footer-button"], [data-testid="confirm-btn"]'
247
+ ).click();
248
+ await p.close();
249
+ }
250
+ async deny() {
251
+ return this.usingNotificationPage(
252
+ (p) => p.getByTestId("cancel-btn").click()
253
+ );
254
+ }
255
+ async usingNotificationPage(action) {
256
+ const p = await this.page.context().newPage();
257
+ await p.goto(`chrome-extension://${this.extensionId}/notification.html`);
258
+ await action(p);
259
+ await p.close();
260
+ }
261
+ };
262
+
191
263
  // src/withWallets.ts
192
264
  var w3walletsDir = ".w3wallets";
193
265
  function withWallets(test, ...config) {
194
266
  const withBackpack = config.includes("backpack");
195
267
  const withPolkadotJS = config.includes("polkadotJS");
268
+ const withMetamask = config.includes("metamask");
196
269
  const backpackPath = import_path.default.join(process.cwd(), w3walletsDir, "backpack");
197
270
  const polkadotJSPath = import_path.default.join(process.cwd(), w3walletsDir, "polkadotJS");
271
+ const metamaskPath = import_path.default.join(process.cwd(), w3walletsDir, "metamask");
198
272
  return test.extend({
199
273
  /**
200
274
  * Sets up a persistent browser context with the requested extensions loaded.
@@ -216,7 +290,11 @@ function withWallets(test, ...config) {
216
290
  ensureWalletExtensionExists(polkadotJSPath, "polkadotJS");
217
291
  extensionPaths.push(polkadotJSPath);
218
292
  }
219
- const context = await import_test3.chromium.launchPersistentContext(userDataDir, {
293
+ if (withMetamask) {
294
+ ensureWalletExtensionExists(polkadotJSPath, "metamask");
295
+ extensionPaths.push(metamaskPath);
296
+ }
297
+ const context = await import_test4.chromium.launchPersistentContext(userDataDir, {
220
298
  headless: testInfo.project.use.headless ?? true,
221
299
  channel: "chromium",
222
300
  args: [
@@ -255,6 +333,19 @@ function withWallets(test, ...config) {
255
333
  "Polkadot{.js} is not initialized"
256
334
  );
257
335
  await use(polkadotJS);
336
+ },
337
+ metamask: async ({ context }, use) => {
338
+ if (!withMetamask) {
339
+ throw Error(
340
+ "The Metamask wallet hasn't been loaded. Add it to the withWallets function."
341
+ );
342
+ }
343
+ const metamask = await initializeExtension(
344
+ context,
345
+ Metamask,
346
+ "Metamask is not initialized"
347
+ );
348
+ await use(metamask);
258
349
  }
259
350
  });
260
351
  }
package/dist/index.mjs CHANGED
@@ -154,13 +154,87 @@ var PolkadotJS = class extends Wallet {
154
154
  }
155
155
  };
156
156
 
157
+ // src/metamask/metamask.ts
158
+ import "@playwright/test";
159
+ var Metamask = class extends Wallet {
160
+ defaultPassword = "11111111";
161
+ async gotoOnboardPage() {
162
+ await this.page.goto(`chrome-extension://${this.extensionId}/home.html`);
163
+ }
164
+ /**
165
+ *
166
+ * @param mnemonic 12-word mnemonic seed phrase
167
+ */
168
+ async onboard(mnemonic, password = this.defaultPassword) {
169
+ await this.page.getByTestId("onboarding-terms-checkbox").click();
170
+ await this.page.getByTestId("onboarding-import-wallet").click();
171
+ await this.page.getByTestId("metametrics-i-agree").click();
172
+ for (const [i, word] of mnemonic.split(" ").entries())
173
+ await this.page.getByTestId(`import-srp__srp-word-${i}`).fill(word);
174
+ await this.page.getByTestId("import-srp-confirm").click();
175
+ await this.page.getByTestId("create-password-new").fill(password);
176
+ await this.page.getByTestId("create-password-confirm").fill(password);
177
+ await this.page.getByTestId("create-password-terms").click();
178
+ await this.page.getByTestId("create-password-import").click();
179
+ await this.page.getByTestId("onboarding-complete-done").click();
180
+ await this.page.getByTestId("pin-extension-next").click();
181
+ await this.page.getByTestId("pin-extension-done").click();
182
+ }
183
+ async connectToNetwork(settings, switchNetwork = true) {
184
+ await this.page.locator(".mm-picker-network").click();
185
+ await this.page.getByRole("button", { name: "Add a custom network" }).click();
186
+ await this.page.getByTestId("network-form-network-name").fill(settings.name);
187
+ await this.page.getByTestId("network-form-chain-id").fill(settings.chainId.toString());
188
+ await this.page.getByTestId("network-form-ticker-input").fill(settings.currencySymbol);
189
+ await this.page.getByTestId("test-add-rpc-drop-down").click();
190
+ await this.page.getByRole("button", { name: "Add RPC URL" }).click();
191
+ await this.page.getByTestId("rpc-url-input-test").fill(settings.rpc);
192
+ await this.page.getByRole("button", { name: "Add URL" }).click();
193
+ await this.page.getByRole("button", { name: "Save" }).click();
194
+ if (switchNetwork) {
195
+ await this.page.locator(".mm-picker-network").click();
196
+ await this.page.getByTestId(settings.name).click();
197
+ }
198
+ }
199
+ // async approve() {
200
+ // return this.usingNotificationPage((p) =>
201
+ // p
202
+ // .locator(
203
+ // '[data-test-id="confirm-footer-button"], [data-test-id="confirm-btn"]',
204
+ // )
205
+ // .click(),
206
+ // );
207
+ // }
208
+ async approve() {
209
+ const p = await this.page.context().newPage();
210
+ await p.goto(`chrome-extension://${this.extensionId}/notification.html`);
211
+ await p.locator(
212
+ '[data-testid="confirm-footer-button"], [data-testid="confirm-btn"]'
213
+ ).click();
214
+ await p.close();
215
+ }
216
+ async deny() {
217
+ return this.usingNotificationPage(
218
+ (p) => p.getByTestId("cancel-btn").click()
219
+ );
220
+ }
221
+ async usingNotificationPage(action) {
222
+ const p = await this.page.context().newPage();
223
+ await p.goto(`chrome-extension://${this.extensionId}/notification.html`);
224
+ await action(p);
225
+ await p.close();
226
+ }
227
+ };
228
+
157
229
  // src/withWallets.ts
158
230
  var w3walletsDir = ".w3wallets";
159
231
  function withWallets(test, ...config) {
160
232
  const withBackpack = config.includes("backpack");
161
233
  const withPolkadotJS = config.includes("polkadotJS");
234
+ const withMetamask = config.includes("metamask");
162
235
  const backpackPath = path.join(process.cwd(), w3walletsDir, "backpack");
163
236
  const polkadotJSPath = path.join(process.cwd(), w3walletsDir, "polkadotJS");
237
+ const metamaskPath = path.join(process.cwd(), w3walletsDir, "metamask");
164
238
  return test.extend({
165
239
  /**
166
240
  * Sets up a persistent browser context with the requested extensions loaded.
@@ -182,6 +256,10 @@ function withWallets(test, ...config) {
182
256
  ensureWalletExtensionExists(polkadotJSPath, "polkadotJS");
183
257
  extensionPaths.push(polkadotJSPath);
184
258
  }
259
+ if (withMetamask) {
260
+ ensureWalletExtensionExists(polkadotJSPath, "metamask");
261
+ extensionPaths.push(metamaskPath);
262
+ }
185
263
  const context = await chromium.launchPersistentContext(userDataDir, {
186
264
  headless: testInfo.project.use.headless ?? true,
187
265
  channel: "chromium",
@@ -221,6 +299,19 @@ function withWallets(test, ...config) {
221
299
  "Polkadot{.js} is not initialized"
222
300
  );
223
301
  await use(polkadotJS);
302
+ },
303
+ metamask: async ({ context }, use) => {
304
+ if (!withMetamask) {
305
+ throw Error(
306
+ "The Metamask wallet hasn't been loaded. Add it to the withWallets function."
307
+ );
308
+ }
309
+ const metamask = await initializeExtension(
310
+ context,
311
+ Metamask,
312
+ "Metamask is not initialized"
313
+ );
314
+ await use(metamask);
224
315
  }
225
316
  });
226
317
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "w3wallets",
3
3
  "description": "browser wallets for playwright",
4
- "version": "0.3.0",
4
+ "version": "0.4.0",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
7
  "homepage": "https://github.com/Maksandre/w3wallets",
@@ -17,6 +17,7 @@
17
17
  "e2e",
18
18
  "playwright",
19
19
  "backpack",
20
+ "metamask",
20
21
  "testing",
21
22
  "ethereum",
22
23
  "polkadot",
@@ -32,8 +33,9 @@
32
33
  "bin": "./src/scripts/download.js",
33
34
  "scripts": {
34
35
  "start:ui": "yarn workspace @w3wallets/test-app buildAndStart",
35
- "download-wallets": "npx w3wallets backpack polkadotJS",
36
- "test": "npx playwright test --project=ci",
36
+ "download-wallets": "npx w3wallets backpack polkadotJS metamask",
37
+ "test": "npx playwright test --project=local --workers=2",
38
+ "test:ci": "npx playwright test --project=ci",
37
39
  "build": "tsup",
38
40
  "clean": "rm -rf dist",
39
41
  "check-format": "prettier --check .",