@avalix/chroma 0.0.9 → 0.0.10
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 +20 -2
- package/dist/index.d.mts +53987 -0
- package/dist/{index.js → index.mjs} +23 -33
- package/package.json +15 -14
- package/scripts/download-extensions.ts +26 -1
- package/src/context-playwright/index.ts +0 -1
- package/src/utils/download-extension.ts +33 -6
- package/src/wallets/polkadot-js.ts +21 -12
- package/src/wallets/talisman.ts +12 -9
- package/dist/index.d.ts +0 -65
|
@@ -4,9 +4,10 @@ import path from "node:path";
|
|
|
4
4
|
import process from "node:process";
|
|
5
5
|
|
|
6
6
|
//#region src/wallets/polkadot-js.ts
|
|
7
|
+
const VERSION$1 = "0.62.6";
|
|
7
8
|
const POLKADOT_JS_CONFIG = {
|
|
8
|
-
downloadUrl:
|
|
9
|
-
extensionName:
|
|
9
|
+
downloadUrl: `https://github.com/polkadot-js/extension/releases/download/v${VERSION$1}/master-chrome-build.zip`,
|
|
10
|
+
extensionName: `polkadot-extension-${VERSION$1}`
|
|
10
11
|
};
|
|
11
12
|
async function findExtensionPopup$1(context, extensionId) {
|
|
12
13
|
const maxAttempts = 10;
|
|
@@ -25,7 +26,6 @@ async function getPolkadotJSExtensionPath() {
|
|
|
25
26
|
const extensionsDir = path.resolve(process.cwd(), ".chroma");
|
|
26
27
|
const extensionDir = path.join(extensionsDir, POLKADOT_JS_CONFIG.extensionName);
|
|
27
28
|
if (!fs.existsSync(extensionDir) || fs.readdirSync(extensionDir).length === 0) throw new Error(`Polkadot-JS extension not found at: ${extensionDir}\n\nPlease download the extension first by running:\n npx @avalix/chroma download-extensions\n`);
|
|
28
|
-
console.log(`✅ Found Polkadot-JS extension at: ${extensionDir}`);
|
|
29
29
|
return extensionDir;
|
|
30
30
|
}
|
|
31
31
|
async function importPolkadotJSAccount(page, { seed, name = "Test Account", password = "h3llop0lkadot!" }) {
|
|
@@ -39,6 +39,7 @@ async function importPolkadotJSAccount(page, { seed, name = "Test Account", pass
|
|
|
39
39
|
await understoodButton.click();
|
|
40
40
|
await extensionPage.waitForTimeout(100);
|
|
41
41
|
}
|
|
42
|
+
if (await extensionPage.getByRole("button", { name: "I Understand" }).isVisible()) await extensionPage.getByRole("button", { name: "I Understand" }).click();
|
|
42
43
|
await extensionPage.goto(`${extensionPopupUrl}#/account/import-seed`);
|
|
43
44
|
await extensionPage.locator("textarea").fill(seed);
|
|
44
45
|
await extensionPage.locator("button:has-text(\"Next\")").click();
|
|
@@ -46,7 +47,6 @@ async function importPolkadotJSAccount(page, { seed, name = "Test Account", pass
|
|
|
46
47
|
await extensionPage.locator("input[type=\"password\"]").fill(password);
|
|
47
48
|
await extensionPage.locator("div").filter({ hasText: /^Repeat password for verification$/ }).getByRole("textbox").fill(password);
|
|
48
49
|
await extensionPage.getByRole("button", { name: "Add the account with the supplied seed" }).click();
|
|
49
|
-
console.log(`✅ Created Polkadot-JS wallet account: ${name}`);
|
|
50
50
|
} finally {
|
|
51
51
|
await extensionPage.close();
|
|
52
52
|
}
|
|
@@ -55,9 +55,9 @@ async function authorizePolkadotJS(page) {
|
|
|
55
55
|
const context = page.__extensionContext;
|
|
56
56
|
const extensionId = page.__extensionId;
|
|
57
57
|
const extensionPopup = await findExtensionPopup$1(context, extensionId);
|
|
58
|
-
await extensionPopup.
|
|
58
|
+
if (await extensionPopup.getByRole("button", { name: "I Understand" }).isVisible()) await extensionPopup.getByRole("button", { name: "I Understand" }).click();
|
|
59
|
+
if (!await extensionPopup.getByText("Select all").locator("..").locator("input[type=\"checkbox\"]").isChecked().catch(() => false)) await extensionPopup.getByText("Select all").click();
|
|
59
60
|
await extensionPopup.getByRole("button", { name: /Connect \d+ account\(s\)/ }).click();
|
|
60
|
-
console.log("✅ Polkadot-JS wallet connected successfully");
|
|
61
61
|
}
|
|
62
62
|
async function approvePolkadotJSTx(page, options = {}) {
|
|
63
63
|
const { password = "h3llop0lkadot!" } = options;
|
|
@@ -66,20 +66,19 @@ async function approvePolkadotJSTx(page, options = {}) {
|
|
|
66
66
|
const extensionPopup = await findExtensionPopup$1(context, extensionId);
|
|
67
67
|
await extensionPopup.getByRole("textbox").fill(password);
|
|
68
68
|
await extensionPopup.getByRole("button", { name: "Sign the transaction" }).click();
|
|
69
|
-
console.log("✅ Polkadot-JS transaction signed successfully");
|
|
70
69
|
}
|
|
71
70
|
async function rejectPolkadotJSTx(page) {
|
|
72
71
|
const context = page.__extensionContext;
|
|
73
72
|
const extensionId = page.__extensionId;
|
|
74
73
|
await (await findExtensionPopup$1(context, extensionId)).getByRole("link", { name: "Cancel" }).click();
|
|
75
|
-
console.log("✅ Polkadot-JS transaction rejected successfully");
|
|
76
74
|
}
|
|
77
75
|
|
|
78
76
|
//#endregion
|
|
79
77
|
//#region src/wallets/talisman.ts
|
|
78
|
+
const VERSION = "3.1.13";
|
|
80
79
|
const TALISMAN_CONFIG = {
|
|
81
|
-
downloadUrl:
|
|
82
|
-
extensionName:
|
|
80
|
+
downloadUrl: `https://github.com/avalix-labs/polkadot-wallets/raw/refs/heads/main/talisman/talisman-${VERSION}.zip`,
|
|
81
|
+
extensionName: `talisman-extension-${VERSION}`
|
|
83
82
|
};
|
|
84
83
|
async function findExtensionPopup(context, extensionId) {
|
|
85
84
|
const maxAttempts = 10;
|
|
@@ -102,7 +101,6 @@ async function getTalismanExtensionPath() {
|
|
|
102
101
|
const extensionsDir = path.resolve(process.cwd(), ".chroma");
|
|
103
102
|
const extensionDir = path.join(extensionsDir, TALISMAN_CONFIG.extensionName);
|
|
104
103
|
if (!fs.existsSync(extensionDir) || fs.readdirSync(extensionDir).length === 0) throw new Error(`Talisman extension not found at: ${extensionDir}\n\nPlease download the extension first by running:\n npx @avalix/chroma download-extensions\n`);
|
|
105
|
-
console.log(`✅ Found Talisman extension at: ${extensionDir}`);
|
|
106
104
|
return extensionDir;
|
|
107
105
|
}
|
|
108
106
|
async function importEthPrivateKey(page, { seed, name = "Test Account", password = "h3llop0lkadot!" }) {
|
|
@@ -115,18 +113,13 @@ async function importEthPrivateKey(page, { seed, name = "Test Account", password
|
|
|
115
113
|
const pages = context.pages();
|
|
116
114
|
for (const p of pages) {
|
|
117
115
|
const url = p.url();
|
|
118
|
-
console.log(`📄 Found page: ${url}`);
|
|
119
116
|
if (url.includes("onboarding.html") || url.includes(`chrome-extension://${extensionId}/`)) {
|
|
120
117
|
extensionPage = p;
|
|
121
|
-
console.log(`✅ Found Talisman onboarding page: ${url}`);
|
|
122
118
|
break;
|
|
123
119
|
}
|
|
124
120
|
}
|
|
125
121
|
if (extensionPage) break;
|
|
126
|
-
if (attempt < maxAttempts - 1)
|
|
127
|
-
console.log(`⏳ Attempt ${attempt + 1}/${maxAttempts}: Waiting for onboarding page...`);
|
|
128
|
-
await new Promise((resolve) => setTimeout(resolve, retryDelay));
|
|
129
|
-
}
|
|
122
|
+
if (attempt < maxAttempts - 1) await new Promise((resolve) => setTimeout(resolve, retryDelay));
|
|
130
123
|
}
|
|
131
124
|
if (!extensionPage) throw new Error(`Talisman onboarding page not found after ${maxAttempts} attempts`);
|
|
132
125
|
try {
|
|
@@ -147,7 +140,6 @@ async function importEthPrivateKey(page, { seed, name = "Test Account", password
|
|
|
147
140
|
await extensionPage.getByRole("textbox", { name: "Enter your private key" }).fill(seed);
|
|
148
141
|
await extensionPage.getByRole("button", { name: "Save" }).click();
|
|
149
142
|
await extensionPage.close();
|
|
150
|
-
console.log("✅ Talisman account import completed");
|
|
151
143
|
} catch (error) {
|
|
152
144
|
console.error("❌ Error during Talisman account import:", error);
|
|
153
145
|
throw error;
|
|
@@ -162,14 +154,18 @@ async function authorizeTalisman(page, options = {}) {
|
|
|
162
154
|
await extensionPopup.getByTestId("connection-connect-button").click();
|
|
163
155
|
try {
|
|
164
156
|
await (await findExtensionPopup(context, extensionId)).getByRole("button", { name: "Approve" }).click();
|
|
165
|
-
} catch {
|
|
166
|
-
console.log("No another popup found, skipping");
|
|
167
|
-
}
|
|
157
|
+
} catch {}
|
|
168
158
|
}
|
|
169
159
|
async function approveTalismanTx(page) {
|
|
170
160
|
const context = page.__extensionContext;
|
|
171
161
|
const extensionId = page.__extensionId;
|
|
172
|
-
|
|
162
|
+
const extensionPopup = await findExtensionPopup(context, extensionId);
|
|
163
|
+
try {
|
|
164
|
+
await extensionPopup.getByRole("button", { name: "Yes" }).click();
|
|
165
|
+
} catch {
|
|
166
|
+
console.log("No another popup found, skipping");
|
|
167
|
+
}
|
|
168
|
+
await extensionPopup.getByRole("button", { name: "Approve" }).click();
|
|
173
169
|
}
|
|
174
170
|
async function rejectTalismanTx(page) {
|
|
175
171
|
const context = page.__extensionContext;
|
|
@@ -194,8 +190,7 @@ function createWalletInstance(walletType, extensionId, context) {
|
|
|
194
190
|
const baseInstance = {
|
|
195
191
|
extensionId,
|
|
196
192
|
importMnemonic: async (options) => {
|
|
197
|
-
const
|
|
198
|
-
const extPage = createExtendedPage(page, context, extensionId);
|
|
193
|
+
const extPage = createExtendedPage(context.pages()[0] || await context.newPage(), context, extensionId);
|
|
199
194
|
importedAccountName = options.name || "Test Account";
|
|
200
195
|
switch (walletType) {
|
|
201
196
|
case "polkadot-js":
|
|
@@ -206,8 +201,7 @@ function createWalletInstance(walletType, extensionId, context) {
|
|
|
206
201
|
}
|
|
207
202
|
},
|
|
208
203
|
authorize: async (options = {}) => {
|
|
209
|
-
const
|
|
210
|
-
const extPage = createExtendedPage(page, context, extensionId);
|
|
204
|
+
const extPage = createExtendedPage(context.pages()[0] || await context.newPage(), context, extensionId);
|
|
211
205
|
const accountName = options.accountName || importedAccountName;
|
|
212
206
|
switch (walletType) {
|
|
213
207
|
case "polkadot-js":
|
|
@@ -220,8 +214,7 @@ function createWalletInstance(walletType, extensionId, context) {
|
|
|
220
214
|
}
|
|
221
215
|
},
|
|
222
216
|
approveTx: async (options = {}) => {
|
|
223
|
-
const
|
|
224
|
-
const extPage = createExtendedPage(page, context, extensionId);
|
|
217
|
+
const extPage = createExtendedPage(context.pages()[0] || await context.newPage(), context, extensionId);
|
|
225
218
|
switch (walletType) {
|
|
226
219
|
case "polkadot-js":
|
|
227
220
|
await approvePolkadotJSTx(extPage, options);
|
|
@@ -233,8 +226,7 @@ function createWalletInstance(walletType, extensionId, context) {
|
|
|
233
226
|
}
|
|
234
227
|
},
|
|
235
228
|
rejectTx: async () => {
|
|
236
|
-
const
|
|
237
|
-
const extPage = createExtendedPage(page, context, extensionId);
|
|
229
|
+
const extPage = createExtendedPage(context.pages()[0] || await context.newPage(), context, extensionId);
|
|
238
230
|
switch (walletType) {
|
|
239
231
|
case "polkadot-js":
|
|
240
232
|
await rejectPolkadotJSTx(extPage);
|
|
@@ -255,8 +247,7 @@ function createWalletInstance(walletType, extensionId, context) {
|
|
|
255
247
|
...baseInstance,
|
|
256
248
|
type: "talisman",
|
|
257
249
|
importEthPrivateKey: async (options) => {
|
|
258
|
-
const
|
|
259
|
-
const extPage = createExtendedPage(page, context, extensionId);
|
|
250
|
+
const extPage = createExtendedPage(context.pages()[0] || await context.newPage(), context, extensionId);
|
|
260
251
|
importedAccountName = options.name || "Test Account";
|
|
261
252
|
await importEthPrivateKey(extPage, {
|
|
262
253
|
seed: options.privateKey,
|
|
@@ -304,7 +295,6 @@ function createWalletTest(options = {}) {
|
|
|
304
295
|
const extensionId = allServiceWorkers[i].url().split("/")[2];
|
|
305
296
|
const walletType = walletConfigs[i].type;
|
|
306
297
|
extensionIds.set(walletType, extensionId);
|
|
307
|
-
console.log(`✅ Loaded ${walletType} extension with ID: ${extensionId}`);
|
|
308
298
|
}
|
|
309
299
|
await use(extensionIds);
|
|
310
300
|
}, { scope: "worker" }],
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@avalix/chroma",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.10",
|
|
5
5
|
"description": "End-to-end testing library for Polkadot wallet interactions",
|
|
6
6
|
"author": "Avalix Labs",
|
|
7
7
|
"license": "MIT",
|
|
@@ -24,12 +24,12 @@
|
|
|
24
24
|
"blockchain"
|
|
25
25
|
],
|
|
26
26
|
"exports": {
|
|
27
|
-
".": "./dist/index.
|
|
27
|
+
".": "./dist/index.mjs",
|
|
28
28
|
"./package.json": "./package.json"
|
|
29
29
|
},
|
|
30
|
-
"main": "./dist/index.
|
|
31
|
-
"module": "./dist/index.
|
|
32
|
-
"types": "./dist/index.d.
|
|
30
|
+
"main": "./dist/index.mjs",
|
|
31
|
+
"module": "./dist/index.mjs",
|
|
32
|
+
"types": "./dist/index.d.mts",
|
|
33
33
|
"bin": {
|
|
34
34
|
"chroma": "./scripts/cli.js"
|
|
35
35
|
},
|
|
@@ -43,22 +43,23 @@
|
|
|
43
43
|
"dev": "tsdown --watch",
|
|
44
44
|
"lint": "eslint --fix .",
|
|
45
45
|
"prepublishOnly": "npm run build",
|
|
46
|
-
"download-extensions": "rm -rf .chroma && tsx scripts/download-extensions.ts"
|
|
46
|
+
"download-extensions": "rm -rf .chroma && tsx scripts/download-extensions.ts",
|
|
47
|
+
"test": "playwright test --ui"
|
|
47
48
|
},
|
|
48
49
|
"peerDependencies": {
|
|
49
|
-
"@playwright/test": "^1.
|
|
50
|
+
"@playwright/test": "^1.57.0"
|
|
50
51
|
},
|
|
51
52
|
"dependencies": {
|
|
52
|
-
"
|
|
53
|
+
"adm-zip": "^0.5.16"
|
|
53
54
|
},
|
|
54
55
|
"devDependencies": {
|
|
55
|
-
"@antfu/eslint-config": "^5.
|
|
56
|
-
"@playwright/test": "^1.
|
|
57
|
-
"@types/node": "^24.
|
|
58
|
-
"@types/unzipper": "^0.10.
|
|
59
|
-
"eslint": "^9.
|
|
56
|
+
"@antfu/eslint-config": "^6.5.1",
|
|
57
|
+
"@playwright/test": "^1.57.0",
|
|
58
|
+
"@types/node": "^24.10.2",
|
|
59
|
+
"@types/unzipper": "^0.10.11",
|
|
60
|
+
"eslint": "^9.39.1",
|
|
60
61
|
"tsdown": "latest",
|
|
61
|
-
"tsx": "^4.
|
|
62
|
+
"tsx": "^4.21.0"
|
|
62
63
|
},
|
|
63
64
|
"publishConfig": {
|
|
64
65
|
"access": "public"
|
|
@@ -1,13 +1,38 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import fs from 'node:fs'
|
|
3
|
+
import path from 'node:path'
|
|
2
4
|
import process from 'node:process'
|
|
5
|
+
import { fileURLToPath } from 'node:url'
|
|
3
6
|
import { downloadAndExtractExtension } from '../src/utils/download-extension.js'
|
|
4
7
|
import { POLKADOT_JS_CONFIG } from '../src/wallets/polkadot-js.js'
|
|
5
8
|
import { TALISMAN_CONFIG } from '../src/wallets/talisman.js'
|
|
6
9
|
|
|
10
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
|
11
|
+
|
|
12
|
+
async function getVersion(): Promise<string> {
|
|
13
|
+
const packageJsonPath = path.resolve(__dirname, '../package.json')
|
|
14
|
+
const packageJson = JSON.parse(await fs.promises.readFile(packageJsonPath, 'utf-8'))
|
|
15
|
+
return packageJson.version
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
async function clearChromaDir(): Promise<void> {
|
|
19
|
+
const chromaDir = path.resolve(process.cwd(), '.chroma')
|
|
20
|
+
|
|
21
|
+
if (fs.existsSync(chromaDir)) {
|
|
22
|
+
console.log('🗑️ Clearing existing .chroma directory...')
|
|
23
|
+
await fs.promises.rm(chromaDir, { recursive: true, force: true })
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
7
27
|
async function main() {
|
|
8
|
-
|
|
28
|
+
const version = await getVersion()
|
|
29
|
+
console.log(`🎨 Chroma v${version}\n`)
|
|
30
|
+
console.log('🚀 Downloading wallet extensions...\n')
|
|
9
31
|
|
|
10
32
|
try {
|
|
33
|
+
// Clear existing .chroma directory
|
|
34
|
+
await clearChromaDir()
|
|
35
|
+
|
|
11
36
|
// Download Polkadot-JS extension
|
|
12
37
|
await downloadAndExtractExtension({
|
|
13
38
|
downloadUrl: POLKADOT_JS_CONFIG.downloadUrl,
|
|
@@ -97,7 +97,6 @@ export function createWalletTest<const T extends readonly WalletConfig[]>(
|
|
|
97
97
|
const extensionId = allServiceWorkers[i].url().split('/')[2]
|
|
98
98
|
const walletType = walletConfigs[i].type
|
|
99
99
|
extensionIds.set(walletType, extensionId)
|
|
100
|
-
console.log(`✅ Loaded ${walletType} extension with ID: ${extensionId}`)
|
|
101
100
|
}
|
|
102
101
|
|
|
103
102
|
await use(extensionIds)
|
|
@@ -2,7 +2,7 @@ import fs, { createWriteStream } from 'node:fs'
|
|
|
2
2
|
import path from 'node:path'
|
|
3
3
|
import process from 'node:process'
|
|
4
4
|
import { pipeline } from 'node:stream/promises'
|
|
5
|
-
import
|
|
5
|
+
import AdmZip from 'adm-zip'
|
|
6
6
|
|
|
7
7
|
export interface DownloadExtensionOptions {
|
|
8
8
|
downloadUrl: string
|
|
@@ -10,6 +10,11 @@ export interface DownloadExtensionOptions {
|
|
|
10
10
|
targetDir?: string
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
+
function unzipFile(zipPath: string, destDir: string): void {
|
|
14
|
+
const zip = new AdmZip(zipPath)
|
|
15
|
+
zip.extractAllTo(destDir, true)
|
|
16
|
+
}
|
|
17
|
+
|
|
13
18
|
export async function downloadAndExtractExtension(options: DownloadExtensionOptions): Promise<string> {
|
|
14
19
|
const { downloadUrl, extensionName, targetDir } = options
|
|
15
20
|
|
|
@@ -17,6 +22,7 @@ export async function downloadAndExtractExtension(options: DownloadExtensionOpti
|
|
|
17
22
|
const extensionsDir = targetDir || path.resolve(process.cwd(), '.chroma')
|
|
18
23
|
const extensionDir = path.join(extensionsDir, extensionName)
|
|
19
24
|
const zipPath = path.join(extensionsDir, `${extensionName}.zip`)
|
|
25
|
+
const tempExtractDir = path.join(extensionsDir, `${extensionName}-temp`)
|
|
20
26
|
|
|
21
27
|
// Create extensions directory if it doesn't exist
|
|
22
28
|
await fs.promises.mkdir(extensionsDir, { recursive: true })
|
|
@@ -42,11 +48,29 @@ export async function downloadAndExtractExtension(options: DownloadExtensionOpti
|
|
|
42
48
|
|
|
43
49
|
console.log('📦 Extracting extension...')
|
|
44
50
|
|
|
45
|
-
//
|
|
46
|
-
await
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
)
|
|
51
|
+
// Extract to temp directory first
|
|
52
|
+
await fs.promises.mkdir(tempExtractDir, { recursive: true })
|
|
53
|
+
unzipFile(zipPath, tempExtractDir)
|
|
54
|
+
|
|
55
|
+
// Check if it's a nested zip (contains another .zip file)
|
|
56
|
+
const files = await fs.promises.readdir(tempExtractDir)
|
|
57
|
+
const nestedZip = files.find(f => f.endsWith('.zip'))
|
|
58
|
+
|
|
59
|
+
if (nestedZip) {
|
|
60
|
+
console.log(`📦 Found nested zip: ${nestedZip}, extracting...`)
|
|
61
|
+
const nestedZipPath = path.join(tempExtractDir, nestedZip)
|
|
62
|
+
|
|
63
|
+
// Extract the nested zip to final location
|
|
64
|
+
await fs.promises.mkdir(extensionDir, { recursive: true })
|
|
65
|
+
unzipFile(nestedZipPath, extensionDir)
|
|
66
|
+
|
|
67
|
+
// Clean up temp directory
|
|
68
|
+
await fs.promises.rm(tempExtractDir, { recursive: true, force: true })
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
// No nested zip, just rename temp to final
|
|
72
|
+
await fs.promises.rename(tempExtractDir, extensionDir)
|
|
73
|
+
}
|
|
50
74
|
|
|
51
75
|
// Clean up ZIP file
|
|
52
76
|
await fs.promises.unlink(zipPath)
|
|
@@ -62,6 +86,9 @@ export async function downloadAndExtractExtension(options: DownloadExtensionOpti
|
|
|
62
86
|
if (fs.existsSync(extensionDir)) {
|
|
63
87
|
await fs.promises.rm(extensionDir, { recursive: true, force: true }).catch(() => {})
|
|
64
88
|
}
|
|
89
|
+
if (fs.existsSync(tempExtractDir)) {
|
|
90
|
+
await fs.promises.rm(tempExtractDir, { recursive: true, force: true }).catch(() => {})
|
|
91
|
+
}
|
|
65
92
|
|
|
66
93
|
throw new Error(`Failed to download/extract ${extensionName}: ${error instanceof Error ? error.message : String(error)}`)
|
|
67
94
|
}
|
|
@@ -5,9 +5,11 @@ import path from 'node:path'
|
|
|
5
5
|
import process from 'node:process'
|
|
6
6
|
|
|
7
7
|
// Polkadot-JS specific configuration
|
|
8
|
+
// https://github.com/polkadot-js/extension/releases
|
|
9
|
+
const VERSION = '0.62.6'
|
|
8
10
|
export const POLKADOT_JS_CONFIG = {
|
|
9
|
-
downloadUrl:
|
|
10
|
-
extensionName:
|
|
11
|
+
downloadUrl: `https://github.com/polkadot-js/extension/releases/download/v${VERSION}/master-chrome-build.zip`,
|
|
12
|
+
extensionName: `polkadot-extension-${VERSION}`,
|
|
11
13
|
} as const
|
|
12
14
|
|
|
13
15
|
// Helper function to find extension popup
|
|
@@ -48,7 +50,6 @@ export async function getPolkadotJSExtensionPath(): Promise<string> {
|
|
|
48
50
|
)
|
|
49
51
|
}
|
|
50
52
|
|
|
51
|
-
console.log(`✅ Found Polkadot-JS extension at: ${extensionDir}`)
|
|
52
53
|
return extensionDir
|
|
53
54
|
}
|
|
54
55
|
|
|
@@ -73,6 +74,10 @@ export async function importPolkadotJSAccount(
|
|
|
73
74
|
await extensionPage.waitForTimeout(100)
|
|
74
75
|
}
|
|
75
76
|
|
|
77
|
+
if (await extensionPage.getByRole('button', { name: 'I Understand' }).isVisible()) {
|
|
78
|
+
await extensionPage.getByRole('button', { name: 'I Understand' }).click()
|
|
79
|
+
}
|
|
80
|
+
|
|
76
81
|
// Navigate to import seed page
|
|
77
82
|
await extensionPage.goto(`${extensionPopupUrl}#/account/import-seed`)
|
|
78
83
|
|
|
@@ -83,8 +88,6 @@ export async function importPolkadotJSAccount(
|
|
|
83
88
|
await extensionPage.locator('input[type="password"]').fill(password)
|
|
84
89
|
await extensionPage.locator('div').filter({ hasText: /^Repeat password for verification$/ }).getByRole('textbox').fill(password)
|
|
85
90
|
await extensionPage.getByRole('button', { name: 'Add the account with the supplied seed' }).click()
|
|
86
|
-
|
|
87
|
-
console.log(`✅ Created Polkadot-JS wallet account: ${name}`)
|
|
88
91
|
}
|
|
89
92
|
finally {
|
|
90
93
|
await extensionPage.close()
|
|
@@ -99,10 +102,20 @@ export async function authorizePolkadotJS(
|
|
|
99
102
|
const extensionId = page.__extensionId
|
|
100
103
|
|
|
101
104
|
const extensionPopup = await findExtensionPopup(context, extensionId)
|
|
102
|
-
await extensionPopup.getByText('Select all').click()
|
|
103
|
-
await extensionPopup.getByRole('button', { name: /Connect \d+ account\(s\)/ }).click()
|
|
104
105
|
|
|
105
|
-
|
|
106
|
+
if (await extensionPopup.getByRole('button', { name: 'I Understand' }).isVisible()) {
|
|
107
|
+
await extensionPopup.getByRole('button', { name: 'I Understand' }).click()
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Check if "Select all" checkbox is already checked
|
|
111
|
+
const selectAllCheckbox = extensionPopup.getByText('Select all').locator('..').locator('input[type="checkbox"]')
|
|
112
|
+
const isChecked = await selectAllCheckbox.isChecked().catch(() => false)
|
|
113
|
+
|
|
114
|
+
if (!isChecked) {
|
|
115
|
+
await extensionPopup.getByText('Select all').click()
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
await extensionPopup.getByRole('button', { name: /Connect \d+ account\(s\)/ }).click()
|
|
106
119
|
}
|
|
107
120
|
|
|
108
121
|
// Polkadot-JS specific transaction approval implementation
|
|
@@ -117,8 +130,6 @@ export async function approvePolkadotJSTx(
|
|
|
117
130
|
const extensionPopup = await findExtensionPopup(context, extensionId)
|
|
118
131
|
await extensionPopup.getByRole('textbox').fill(password)
|
|
119
132
|
await extensionPopup.getByRole('button', { name: 'Sign the transaction' }).click()
|
|
120
|
-
|
|
121
|
-
console.log('✅ Polkadot-JS transaction signed successfully')
|
|
122
133
|
}
|
|
123
134
|
|
|
124
135
|
// Polkadot-JS specific transaction rejection implementation
|
|
@@ -130,6 +141,4 @@ export async function rejectPolkadotJSTx(
|
|
|
130
141
|
|
|
131
142
|
const extensionPopup = await findExtensionPopup(context, extensionId)
|
|
132
143
|
await extensionPopup.getByRole('link', { name: 'Cancel' }).click()
|
|
133
|
-
|
|
134
|
-
console.log('✅ Polkadot-JS transaction rejected successfully')
|
|
135
144
|
}
|
package/src/wallets/talisman.ts
CHANGED
|
@@ -5,9 +5,11 @@ import path from 'node:path'
|
|
|
5
5
|
import process from 'node:process'
|
|
6
6
|
|
|
7
7
|
// Talisman specific configuration
|
|
8
|
+
// https://github.com/avalix-labs/polkadot-wallets/tree/main/talisman
|
|
9
|
+
const VERSION = '3.1.13'
|
|
8
10
|
export const TALISMAN_CONFIG = {
|
|
9
|
-
downloadUrl:
|
|
10
|
-
extensionName:
|
|
11
|
+
downloadUrl: `https://github.com/avalix-labs/polkadot-wallets/raw/refs/heads/main/talisman/talisman-${VERSION}.zip`,
|
|
12
|
+
extensionName: `talisman-extension-${VERSION}`,
|
|
11
13
|
} as const
|
|
12
14
|
|
|
13
15
|
// Helper function to find extension popup
|
|
@@ -49,7 +51,6 @@ export async function getTalismanExtensionPath(): Promise<string> {
|
|
|
49
51
|
)
|
|
50
52
|
}
|
|
51
53
|
|
|
52
|
-
console.log(`✅ Found Talisman extension at: ${extensionDir}`)
|
|
53
54
|
return extensionDir
|
|
54
55
|
}
|
|
55
56
|
|
|
@@ -71,10 +72,8 @@ export async function importEthPrivateKey(
|
|
|
71
72
|
|
|
72
73
|
for (const p of pages) {
|
|
73
74
|
const url = p.url()
|
|
74
|
-
console.log(`📄 Found page: ${url}`)
|
|
75
75
|
if (url.includes('onboarding.html') || url.includes(`chrome-extension://${extensionId}/`)) {
|
|
76
76
|
extensionPage = p
|
|
77
|
-
console.log(`✅ Found Talisman onboarding page: ${url}`)
|
|
78
77
|
break
|
|
79
78
|
}
|
|
80
79
|
}
|
|
@@ -85,7 +84,6 @@ export async function importEthPrivateKey(
|
|
|
85
84
|
|
|
86
85
|
// If not found, wait before retrying
|
|
87
86
|
if (attempt < maxAttempts - 1) {
|
|
88
|
-
console.log(`⏳ Attempt ${attempt + 1}/${maxAttempts}: Waiting for onboarding page...`)
|
|
89
87
|
await new Promise(resolve => setTimeout(resolve, retryDelay))
|
|
90
88
|
}
|
|
91
89
|
}
|
|
@@ -124,8 +122,6 @@ export async function importEthPrivateKey(
|
|
|
124
122
|
await extensionPage.getByRole('button', { name: 'Save' }).click()
|
|
125
123
|
|
|
126
124
|
await extensionPage.close()
|
|
127
|
-
|
|
128
|
-
console.log('✅ Talisman account import completed')
|
|
129
125
|
}
|
|
130
126
|
catch (error) {
|
|
131
127
|
console.error('❌ Error during Talisman account import:', error)
|
|
@@ -153,7 +149,6 @@ export async function authorizeTalisman(
|
|
|
153
149
|
await anotherPopup.getByRole('button', { name: 'Approve' }).click()
|
|
154
150
|
}
|
|
155
151
|
catch {
|
|
156
|
-
console.log('No another popup found, skipping')
|
|
157
152
|
}
|
|
158
153
|
}
|
|
159
154
|
|
|
@@ -165,6 +160,14 @@ export async function approveTalismanTx(
|
|
|
165
160
|
const extensionId = page.__extensionId
|
|
166
161
|
|
|
167
162
|
const extensionPopup = await findExtensionPopup(context, extensionId)
|
|
163
|
+
|
|
164
|
+
try {
|
|
165
|
+
await extensionPopup.getByRole('button', { name: 'Yes' }).click()
|
|
166
|
+
}
|
|
167
|
+
catch {
|
|
168
|
+
console.log('No another popup found, skipping')
|
|
169
|
+
}
|
|
170
|
+
|
|
168
171
|
await extensionPopup.getByRole('button', { name: 'Approve' }).click()
|
|
169
172
|
}
|
|
170
173
|
|
package/dist/index.d.ts
DELETED
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
import { BrowserContext, Page, expect } from "@playwright/test";
|
|
2
|
-
import * as playwright_test0 from "playwright/test";
|
|
3
|
-
|
|
4
|
-
//#region src/context-playwright/types.d.ts
|
|
5
|
-
type WalletType = 'polkadot-js' | 'talisman';
|
|
6
|
-
interface WalletAccount {
|
|
7
|
-
seed: string;
|
|
8
|
-
name?: string;
|
|
9
|
-
password?: string;
|
|
10
|
-
}
|
|
11
|
-
interface WalletConfig {
|
|
12
|
-
type: WalletType;
|
|
13
|
-
downloadUrl?: string;
|
|
14
|
-
}
|
|
15
|
-
interface BaseWalletInstance {
|
|
16
|
-
extensionId: string;
|
|
17
|
-
importMnemonic: (options: WalletAccount) => Promise<void>;
|
|
18
|
-
authorize: (options?: {
|
|
19
|
-
accountName?: string;
|
|
20
|
-
}) => Promise<void>;
|
|
21
|
-
approveTx: (options?: {
|
|
22
|
-
password?: string;
|
|
23
|
-
}) => Promise<void>;
|
|
24
|
-
rejectTx: () => Promise<void>;
|
|
25
|
-
}
|
|
26
|
-
interface PolkadotJsWalletInstance extends BaseWalletInstance {
|
|
27
|
-
type: 'polkadot-js';
|
|
28
|
-
}
|
|
29
|
-
interface TalismanWalletInstance extends BaseWalletInstance {
|
|
30
|
-
type: 'talisman';
|
|
31
|
-
importEthPrivateKey: (options: {
|
|
32
|
-
privateKey: string;
|
|
33
|
-
name?: string;
|
|
34
|
-
password?: string;
|
|
35
|
-
}) => Promise<void>;
|
|
36
|
-
}
|
|
37
|
-
interface WalletTypeMap {
|
|
38
|
-
'polkadot-js': PolkadotJsWalletInstance;
|
|
39
|
-
'talisman': TalismanWalletInstance;
|
|
40
|
-
}
|
|
41
|
-
type Wallets = WalletTypeMap;
|
|
42
|
-
type ConfiguredWallets<T extends readonly WalletConfig[]> = { [K in T[number]['type']]: WalletTypeMap[K] };
|
|
43
|
-
type ExtendedPage = Page & {
|
|
44
|
-
__extensionContext: BrowserContext;
|
|
45
|
-
__walletExtensionIds: Map<string, string>;
|
|
46
|
-
};
|
|
47
|
-
interface ChromaTestOptions<T extends readonly WalletConfig[] = WalletConfig[]> {
|
|
48
|
-
wallets?: T;
|
|
49
|
-
headless?: boolean;
|
|
50
|
-
slowMo?: number;
|
|
51
|
-
}
|
|
52
|
-
interface WalletFixtures<W = Wallets> {
|
|
53
|
-
page: ExtendedPage;
|
|
54
|
-
wallets: W;
|
|
55
|
-
}
|
|
56
|
-
interface WalletWorkerFixtures {
|
|
57
|
-
walletContext: BrowserContext;
|
|
58
|
-
walletExtensionIds: Map<string, string>;
|
|
59
|
-
}
|
|
60
|
-
//#endregion
|
|
61
|
-
//#region src/context-playwright/index.d.ts
|
|
62
|
-
declare function createWalletTest<const T extends readonly WalletConfig[]>(options?: ChromaTestOptions<T>): playwright_test0.TestType<playwright_test0.PlaywrightTestArgs & playwright_test0.PlaywrightTestOptions & WalletFixtures<T extends readonly WalletConfig[] ? ConfiguredWallets<T> : WalletTypeMap>, playwright_test0.PlaywrightWorkerArgs & playwright_test0.PlaywrightWorkerOptions & WalletWorkerFixtures>;
|
|
63
|
-
declare const test: ReturnType<typeof createWalletTest>;
|
|
64
|
-
//#endregion
|
|
65
|
-
export { createWalletTest, expect, test };
|