w3wallets 0.2.2 → 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>;
@@ -21,14 +21,23 @@ declare abstract class Wallet implements IWallet {
21
21
 
22
22
  declare class Backpack extends Wallet {
23
23
  private defaultPassword;
24
+ private currentAccountId;
25
+ private maxAccountId;
24
26
  gotoOnboardPage(): Promise<void>;
25
27
  onboard(network: BackPackNetwork, privateKey: string): Promise<void>;
28
+ addAccount(network: BackPackNetwork, privateKey: string): Promise<void>;
29
+ /**
30
+ * Switch account
31
+ * @param id The first added account has id 1, the second – 2, and so on
32
+ */
33
+ switchAccount(id: number): Promise<void>;
26
34
  unlock(): Promise<void>;
27
- goToSettings(accountName?: string): Promise<void>;
28
35
  setRPC(network: BackPackNetwork, rpc: string): Promise<void>;
29
36
  ignoreAndProceed(): Promise<void>;
30
37
  approve(): Promise<void>;
31
38
  deny(): Promise<void>;
39
+ private _clickOnAccount;
40
+ private _importAccount;
32
41
  }
33
42
 
34
43
  declare class PolkadotJS extends Wallet {
@@ -43,10 +52,32 @@ declare class PolkadotJS extends Wallet {
43
52
  private _getLabeledInput;
44
53
  }
45
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
+
46
76
  declare function withWallets<T extends readonly WalletName[]>(test: typeof test, ...config: NoDuplicates<T>): playwright_test.TestType<playwright_test.PlaywrightTestArgs & playwright_test.PlaywrightTestOptions & {
47
77
  context: BrowserContext;
48
78
  backpack: Backpack;
49
79
  polkadotJS: PolkadotJS;
80
+ metamask: Metamask;
50
81
  }, playwright_test.PlaywrightWorkerArgs & playwright_test.PlaywrightWorkerOptions>;
51
82
 
52
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>;
@@ -21,14 +21,23 @@ declare abstract class Wallet implements IWallet {
21
21
 
22
22
  declare class Backpack extends Wallet {
23
23
  private defaultPassword;
24
+ private currentAccountId;
25
+ private maxAccountId;
24
26
  gotoOnboardPage(): Promise<void>;
25
27
  onboard(network: BackPackNetwork, privateKey: string): Promise<void>;
28
+ addAccount(network: BackPackNetwork, privateKey: string): Promise<void>;
29
+ /**
30
+ * Switch account
31
+ * @param id The first added account has id 1, the second – 2, and so on
32
+ */
33
+ switchAccount(id: number): Promise<void>;
26
34
  unlock(): Promise<void>;
27
- goToSettings(accountName?: string): Promise<void>;
28
35
  setRPC(network: BackPackNetwork, rpc: string): Promise<void>;
29
36
  ignoreAndProceed(): Promise<void>;
30
37
  approve(): Promise<void>;
31
38
  deny(): Promise<void>;
39
+ private _clickOnAccount;
40
+ private _importAccount;
32
41
  }
33
42
 
34
43
  declare class PolkadotJS extends Wallet {
@@ -43,10 +52,32 @@ declare class PolkadotJS extends Wallet {
43
52
  private _getLabeledInput;
44
53
  }
45
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
+
46
76
  declare function withWallets<T extends readonly WalletName[]>(test: typeof test, ...config: NoDuplicates<T>): playwright_test.TestType<playwright_test.PlaywrightTestArgs & playwright_test.PlaywrightTestOptions & {
47
77
  context: BrowserContext;
48
78
  backpack: Backpack;
49
79
  polkadotJS: PolkadotJS;
80
+ metamask: Metamask;
50
81
  }, playwright_test.PlaywrightWorkerArgs & playwright_test.PlaywrightWorkerOptions>;
51
82
 
52
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");
@@ -58,6 +58,8 @@ var Wallet = class {
58
58
  // src/backpack/backpack.ts
59
59
  var Backpack = class extends Wallet {
60
60
  defaultPassword = "11111111";
61
+ currentAccountId = 0;
62
+ maxAccountId = 0;
61
63
  async gotoOnboardPage() {
62
64
  await this.page.goto(
63
65
  `chrome-extension://${this.extensionId}/options.html?onboarding=true`
@@ -65,28 +67,34 @@ var Backpack = class extends Wallet {
65
67
  await (0, import_test.expect)(this.page.getByText("Welcome to Backpack")).toBeVisible();
66
68
  }
67
69
  async onboard(network, privateKey) {
68
- await this.page.getByRole("button", { name: "Import wallet" }).click();
69
- await this.page.getByRole("button", { name: network }).click();
70
- await this.page.getByRole("button", { name: "Import private key" }).click();
71
- await this.page.getByPlaceholder("Enter private key").fill(privateKey);
72
- await this.page.getByRole("button", { name: "Import" }).click();
73
- await this.page.getByPlaceholder("Password", { exact: true }).fill(this.defaultPassword);
74
- await this.page.getByPlaceholder("Confirm Password").fill(this.defaultPassword);
75
- await this.page.getByRole("checkbox").click();
76
- await this.page.getByRole("button", { name: "Next" }).click();
77
- await (0, import_test.expect)(this.page.getByText("You're all good!")).toBeVisible();
78
- await this.page.goto(`chrome-extension://${this.extensionId}/popup.html`);
70
+ this.currentAccountId++;
71
+ this.maxAccountId++;
72
+ return this._importAccount(network, privateKey, true);
73
+ }
74
+ async addAccount(network, privateKey) {
75
+ this.maxAccountId++;
76
+ this.currentAccountId = this.maxAccountId;
77
+ await this.page.goto(
78
+ `chrome-extension://${this.extensionId}/options.html?add-user-account=true`
79
+ );
80
+ await this._importAccount(network, privateKey, false);
81
+ }
82
+ /**
83
+ * Switch account
84
+ * @param id The first added account has id 1, the second – 2, and so on
85
+ */
86
+ async switchAccount(id) {
87
+ await this.page.getByRole("button", { name: `A${this.currentAccountId}` }).click();
88
+ await this.page.getByRole("button", { name: `Account ${id}` }).click();
89
+ this.currentAccountId = id;
79
90
  }
80
91
  async unlock() {
81
92
  await this.page.getByPlaceholder("Password").fill(this.defaultPassword);
82
93
  await this.page.getByRole("button", { name: "Unlock" }).click();
83
94
  }
84
- async goToSettings(accountName) {
85
- await this.page.getByRole("button", { name: accountName ?? "A1" }).click();
86
- await this.page.getByRole("button", { name: "Settings" }).click();
87
- }
88
95
  async setRPC(network, rpc) {
89
- await this.goToSettings();
96
+ await this._clickOnAccount();
97
+ await this.page.getByRole("button", { name: "Settings" }).click();
90
98
  await this.page.getByRole("button", { name: network }).click();
91
99
  await this.page.getByRole("button", { name: "RPC Connection" }).click();
92
100
  await this.page.getByRole("button", { name: "Custom" }).click();
@@ -103,6 +111,24 @@ var Backpack = class extends Wallet {
103
111
  async deny() {
104
112
  await this.page.getByText("Deny", { exact: true }).click();
105
113
  }
114
+ async _clickOnAccount() {
115
+ return this.page.getByRole("button", { name: `A${this.currentAccountId}`, exact: true }).click();
116
+ }
117
+ async _importAccount(network, privateKey, isOnboard) {
118
+ await this.page.getByRole("button", { name: "Import wallet" }).click();
119
+ await this.page.getByRole("button", { name: network }).click();
120
+ await this.page.getByRole("button", { name: "Import private key" }).click();
121
+ await this.page.getByPlaceholder("Enter private key").fill(privateKey);
122
+ await this.page.getByRole("button", { name: "Import" }).click();
123
+ if (isOnboard) {
124
+ await this.page.getByPlaceholder("Password", { exact: true }).fill(this.defaultPassword);
125
+ await this.page.getByPlaceholder("Confirm Password").fill(this.defaultPassword);
126
+ await this.page.getByRole("checkbox").click();
127
+ await this.page.getByRole("button", { name: "Next" }).click();
128
+ }
129
+ await (0, import_test.expect)(this.page.getByText("You're all good!")).toBeVisible();
130
+ await this.page.goto(`chrome-extension://${this.extensionId}/popup.html`);
131
+ }
106
132
  };
107
133
 
108
134
  // src/polkadotJS/polkadotJS.ts
@@ -162,13 +188,87 @@ var PolkadotJS = class extends Wallet {
162
188
  }
163
189
  };
164
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
+
165
263
  // src/withWallets.ts
166
264
  var w3walletsDir = ".w3wallets";
167
265
  function withWallets(test, ...config) {
168
266
  const withBackpack = config.includes("backpack");
169
267
  const withPolkadotJS = config.includes("polkadotJS");
268
+ const withMetamask = config.includes("metamask");
170
269
  const backpackPath = import_path.default.join(process.cwd(), w3walletsDir, "backpack");
171
270
  const polkadotJSPath = import_path.default.join(process.cwd(), w3walletsDir, "polkadotJS");
271
+ const metamaskPath = import_path.default.join(process.cwd(), w3walletsDir, "metamask");
172
272
  return test.extend({
173
273
  /**
174
274
  * Sets up a persistent browser context with the requested extensions loaded.
@@ -190,7 +290,11 @@ function withWallets(test, ...config) {
190
290
  ensureWalletExtensionExists(polkadotJSPath, "polkadotJS");
191
291
  extensionPaths.push(polkadotJSPath);
192
292
  }
193
- 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, {
194
298
  headless: testInfo.project.use.headless ?? true,
195
299
  channel: "chromium",
196
300
  args: [
@@ -229,6 +333,19 @@ function withWallets(test, ...config) {
229
333
  "Polkadot{.js} is not initialized"
230
334
  );
231
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);
232
349
  }
233
350
  });
234
351
  }
package/dist/index.mjs CHANGED
@@ -24,6 +24,8 @@ var Wallet = class {
24
24
  // src/backpack/backpack.ts
25
25
  var Backpack = class extends Wallet {
26
26
  defaultPassword = "11111111";
27
+ currentAccountId = 0;
28
+ maxAccountId = 0;
27
29
  async gotoOnboardPage() {
28
30
  await this.page.goto(
29
31
  `chrome-extension://${this.extensionId}/options.html?onboarding=true`
@@ -31,28 +33,34 @@ var Backpack = class extends Wallet {
31
33
  await expect(this.page.getByText("Welcome to Backpack")).toBeVisible();
32
34
  }
33
35
  async onboard(network, privateKey) {
34
- await this.page.getByRole("button", { name: "Import wallet" }).click();
35
- await this.page.getByRole("button", { name: network }).click();
36
- await this.page.getByRole("button", { name: "Import private key" }).click();
37
- await this.page.getByPlaceholder("Enter private key").fill(privateKey);
38
- await this.page.getByRole("button", { name: "Import" }).click();
39
- await this.page.getByPlaceholder("Password", { exact: true }).fill(this.defaultPassword);
40
- await this.page.getByPlaceholder("Confirm Password").fill(this.defaultPassword);
41
- await this.page.getByRole("checkbox").click();
42
- await this.page.getByRole("button", { name: "Next" }).click();
43
- await expect(this.page.getByText("You're all good!")).toBeVisible();
44
- await this.page.goto(`chrome-extension://${this.extensionId}/popup.html`);
36
+ this.currentAccountId++;
37
+ this.maxAccountId++;
38
+ return this._importAccount(network, privateKey, true);
39
+ }
40
+ async addAccount(network, privateKey) {
41
+ this.maxAccountId++;
42
+ this.currentAccountId = this.maxAccountId;
43
+ await this.page.goto(
44
+ `chrome-extension://${this.extensionId}/options.html?add-user-account=true`
45
+ );
46
+ await this._importAccount(network, privateKey, false);
47
+ }
48
+ /**
49
+ * Switch account
50
+ * @param id The first added account has id 1, the second – 2, and so on
51
+ */
52
+ async switchAccount(id) {
53
+ await this.page.getByRole("button", { name: `A${this.currentAccountId}` }).click();
54
+ await this.page.getByRole("button", { name: `Account ${id}` }).click();
55
+ this.currentAccountId = id;
45
56
  }
46
57
  async unlock() {
47
58
  await this.page.getByPlaceholder("Password").fill(this.defaultPassword);
48
59
  await this.page.getByRole("button", { name: "Unlock" }).click();
49
60
  }
50
- async goToSettings(accountName) {
51
- await this.page.getByRole("button", { name: accountName ?? "A1" }).click();
52
- await this.page.getByRole("button", { name: "Settings" }).click();
53
- }
54
61
  async setRPC(network, rpc) {
55
- await this.goToSettings();
62
+ await this._clickOnAccount();
63
+ await this.page.getByRole("button", { name: "Settings" }).click();
56
64
  await this.page.getByRole("button", { name: network }).click();
57
65
  await this.page.getByRole("button", { name: "RPC Connection" }).click();
58
66
  await this.page.getByRole("button", { name: "Custom" }).click();
@@ -69,6 +77,24 @@ var Backpack = class extends Wallet {
69
77
  async deny() {
70
78
  await this.page.getByText("Deny", { exact: true }).click();
71
79
  }
80
+ async _clickOnAccount() {
81
+ return this.page.getByRole("button", { name: `A${this.currentAccountId}`, exact: true }).click();
82
+ }
83
+ async _importAccount(network, privateKey, isOnboard) {
84
+ await this.page.getByRole("button", { name: "Import wallet" }).click();
85
+ await this.page.getByRole("button", { name: network }).click();
86
+ await this.page.getByRole("button", { name: "Import private key" }).click();
87
+ await this.page.getByPlaceholder("Enter private key").fill(privateKey);
88
+ await this.page.getByRole("button", { name: "Import" }).click();
89
+ if (isOnboard) {
90
+ await this.page.getByPlaceholder("Password", { exact: true }).fill(this.defaultPassword);
91
+ await this.page.getByPlaceholder("Confirm Password").fill(this.defaultPassword);
92
+ await this.page.getByRole("checkbox").click();
93
+ await this.page.getByRole("button", { name: "Next" }).click();
94
+ }
95
+ await expect(this.page.getByText("You're all good!")).toBeVisible();
96
+ await this.page.goto(`chrome-extension://${this.extensionId}/popup.html`);
97
+ }
72
98
  };
73
99
 
74
100
  // src/polkadotJS/polkadotJS.ts
@@ -128,13 +154,87 @@ var PolkadotJS = class extends Wallet {
128
154
  }
129
155
  };
130
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
+
131
229
  // src/withWallets.ts
132
230
  var w3walletsDir = ".w3wallets";
133
231
  function withWallets(test, ...config) {
134
232
  const withBackpack = config.includes("backpack");
135
233
  const withPolkadotJS = config.includes("polkadotJS");
234
+ const withMetamask = config.includes("metamask");
136
235
  const backpackPath = path.join(process.cwd(), w3walletsDir, "backpack");
137
236
  const polkadotJSPath = path.join(process.cwd(), w3walletsDir, "polkadotJS");
237
+ const metamaskPath = path.join(process.cwd(), w3walletsDir, "metamask");
138
238
  return test.extend({
139
239
  /**
140
240
  * Sets up a persistent browser context with the requested extensions loaded.
@@ -156,6 +256,10 @@ function withWallets(test, ...config) {
156
256
  ensureWalletExtensionExists(polkadotJSPath, "polkadotJS");
157
257
  extensionPaths.push(polkadotJSPath);
158
258
  }
259
+ if (withMetamask) {
260
+ ensureWalletExtensionExists(polkadotJSPath, "metamask");
261
+ extensionPaths.push(metamaskPath);
262
+ }
159
263
  const context = await chromium.launchPersistentContext(userDataDir, {
160
264
  headless: testInfo.project.use.headless ?? true,
161
265
  channel: "chromium",
@@ -195,6 +299,19 @@ function withWallets(test, ...config) {
195
299
  "Polkadot{.js} is not initialized"
196
300
  );
197
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);
198
315
  }
199
316
  });
200
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.2.2",
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 .",