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 +12 -1
- package/dist/index.d.mts +33 -2
- package/dist/index.d.ts +33 -2
- package/dist/index.js +135 -18
- package/dist/index.mjs +133 -16
- package/package.json +5 -3
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(
|
|
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
|
|
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
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
await this.page.
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
await this.
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
await this.page.
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
await this.
|
|
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.
|
|
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.
|
|
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=
|
|
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 .",
|