@avalix/chroma 0.0.8 → 0.0.9

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/dist/index.d.ts CHANGED
@@ -21,6 +21,7 @@ interface BaseWalletInstance {
21
21
  approveTx: (options?: {
22
22
  password?: string;
23
23
  }) => Promise<void>;
24
+ rejectTx: () => Promise<void>;
24
25
  }
25
26
  interface PolkadotJsWalletInstance extends BaseWalletInstance {
26
27
  type: 'polkadot-js';
package/dist/index.js CHANGED
@@ -9,14 +9,22 @@ const POLKADOT_JS_CONFIG = {
9
9
  extensionName: "polkadot-extension-0.61.7"
10
10
  };
11
11
  async function findExtensionPopup$1(context, extensionId) {
12
- const pages = context.pages();
13
- for (const p of pages) if (p.url().includes(`chrome-extension://${extensionId}/`)) return p;
12
+ const maxAttempts = 10;
13
+ const retryDelay = 500;
14
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
15
+ const pages = context.pages();
16
+ for (const p of pages) if (p.url().includes(`chrome-extension://${extensionId}/`)) {
17
+ await p.waitForLoadState("domcontentloaded");
18
+ return p;
19
+ }
20
+ if (attempt < maxAttempts - 1) await new Promise((resolve) => setTimeout(resolve, retryDelay));
21
+ }
14
22
  throw new Error(`Extension popup not found for ID: ${extensionId}`);
15
23
  }
16
24
  async function getPolkadotJSExtensionPath() {
17
25
  const extensionsDir = path.resolve(process.cwd(), ".chroma");
18
26
  const extensionDir = path.join(extensionsDir, POLKADOT_JS_CONFIG.extensionName);
19
- 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\nOr if you're using this as a dependency:\n npm run chroma:download\n`);
27
+ 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`);
20
28
  console.log(`✅ Found Polkadot-JS extension at: ${extensionDir}`);
21
29
  return extensionDir;
22
30
  }
@@ -46,7 +54,6 @@ async function importPolkadotJSAccount(page, { seed, name = "Test Account", pass
46
54
  async function authorizePolkadotJS(page) {
47
55
  const context = page.__extensionContext;
48
56
  const extensionId = page.__extensionId;
49
- await new Promise((resolve) => setTimeout(resolve, 1e3));
50
57
  const extensionPopup = await findExtensionPopup$1(context, extensionId);
51
58
  await extensionPopup.getByText("Select all").click();
52
59
  await extensionPopup.getByRole("button", { name: /Connect \d+ account\(s\)/ }).click();
@@ -56,12 +63,17 @@ async function approvePolkadotJSTx(page, options = {}) {
56
63
  const { password = "h3llop0lkadot!" } = options;
57
64
  const context = page.__extensionContext;
58
65
  const extensionId = page.__extensionId;
59
- await new Promise((resolve) => setTimeout(resolve, 1e3));
60
66
  const extensionPopup = await findExtensionPopup$1(context, extensionId);
61
67
  await extensionPopup.getByRole("textbox").fill(password);
62
68
  await extensionPopup.getByRole("button", { name: "Sign the transaction" }).click();
63
69
  console.log("✅ Polkadot-JS transaction signed successfully");
64
70
  }
71
+ async function rejectPolkadotJSTx(page) {
72
+ const context = page.__extensionContext;
73
+ const extensionId = page.__extensionId;
74
+ await (await findExtensionPopup$1(context, extensionId)).getByRole("link", { name: "Cancel" }).click();
75
+ console.log("✅ Polkadot-JS transaction rejected successfully");
76
+ }
65
77
 
66
78
  //#endregion
67
79
  //#region src/wallets/talisman.ts
@@ -70,45 +82,55 @@ const TALISMAN_CONFIG = {
70
82
  extensionName: "talisman-extension-3.0.5"
71
83
  };
72
84
  async function findExtensionPopup(context, extensionId) {
73
- await new Promise((resolve) => setTimeout(resolve, 1e3));
74
- const pages = context.pages();
75
- for (const p of pages) if (p.url().includes(`chrome-extension://${extensionId}/`)) {
76
- p.setViewportSize({
77
- width: 400,
78
- height: 600
79
- });
80
- p.waitForLoadState("domcontentloaded");
81
- return p;
85
+ const maxAttempts = 10;
86
+ const retryDelay = 500;
87
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
88
+ const pages = context.pages();
89
+ for (const p of pages) if (p.url().includes(`chrome-extension://${extensionId}/`)) {
90
+ await p.setViewportSize({
91
+ width: 400,
92
+ height: 600
93
+ });
94
+ await p.waitForLoadState("domcontentloaded");
95
+ return p;
96
+ }
97
+ if (attempt < maxAttempts - 1) await new Promise((resolve) => setTimeout(resolve, retryDelay));
82
98
  }
83
99
  throw new Error(`Extension popup not found for ID: ${extensionId}`);
84
100
  }
85
101
  async function getTalismanExtensionPath() {
86
102
  const extensionsDir = path.resolve(process.cwd(), ".chroma");
87
103
  const extensionDir = path.join(extensionsDir, TALISMAN_CONFIG.extensionName);
88
- 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\nOr if you're using this as a dependency:\n npm run chroma:download\n`);
104
+ 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`);
89
105
  console.log(`✅ Found Talisman extension at: ${extensionDir}`);
90
106
  return extensionDir;
91
107
  }
92
108
  async function importEthPrivateKey(page, { seed, name = "Test Account", password = "h3llop0lkadot!" }) {
93
109
  const context = page.__extensionContext;
94
110
  const extensionId = page.__extensionId;
95
- await new Promise((resolve) => setTimeout(resolve, 2e3));
111
+ const maxAttempts = 20;
112
+ const retryDelay = 500;
96
113
  let extensionPage = null;
97
- const pages = context.pages();
98
- for (const page$1 of pages) {
99
- const url = page$1.url();
100
- console.log(`📄 Found page: ${url}`);
101
- if (url.includes("onboarding.html") || url.includes(`chrome-extension://${extensionId}/`)) {
102
- extensionPage = page$1;
103
- console.log(`✅ Found Talisman onboarding page: ${url}`);
104
- break;
114
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
115
+ const pages = context.pages();
116
+ for (const p of pages) {
117
+ const url = p.url();
118
+ console.log(`📄 Found page: ${url}`);
119
+ if (url.includes("onboarding.html") || url.includes(`chrome-extension://${extensionId}/`)) {
120
+ extensionPage = p;
121
+ console.log(`✅ Found Talisman onboarding page: ${url}`);
122
+ break;
123
+ }
124
+ }
125
+ 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));
105
129
  }
106
130
  }
107
- if (!extensionPage) throw new Error(`Talisman onboarding page not found`);
131
+ if (!extensionPage) throw new Error(`Talisman onboarding page not found after ${maxAttempts} attempts`);
108
132
  try {
109
133
  await extensionPage.bringToFront();
110
- console.log("🔄 Reloading onboarding page for fresh state...");
111
- await extensionPage.reload();
112
134
  await extensionPage.waitForLoadState("domcontentloaded");
113
135
  await extensionPage.getByTestId("onboarding-get-started-button").click();
114
136
  await extensionPage.getByRole("textbox", { name: "Enter password" }).fill(password);
@@ -135,7 +157,6 @@ async function authorizeTalisman(page, options = {}) {
135
157
  const { accountName = "Test Account" } = options;
136
158
  const context = page.__extensionContext;
137
159
  const extensionId = page.__extensionId;
138
- await new Promise((resolve) => setTimeout(resolve, 1e3));
139
160
  const extensionPopup = await findExtensionPopup(context, extensionId);
140
161
  await extensionPopup.getByRole("button", { name: accountName }).click();
141
162
  await extensionPopup.getByTestId("connection-connect-button").click();
@@ -148,9 +169,13 @@ async function authorizeTalisman(page, options = {}) {
148
169
  async function approveTalismanTx(page) {
149
170
  const context = page.__extensionContext;
150
171
  const extensionId = page.__extensionId;
151
- await new Promise((resolve) => setTimeout(resolve, 1e3));
152
172
  await (await findExtensionPopup(context, extensionId)).getByRole("button", { name: "Approve" }).click();
153
173
  }
174
+ async function rejectTalismanTx(page) {
175
+ const context = page.__extensionContext;
176
+ const extensionId = page.__extensionId;
177
+ await (await findExtensionPopup(context, extensionId)).getByTestId("connection-reject-button").click();
178
+ }
154
179
 
155
180
  //#endregion
156
181
  //#region src/context-playwright/types.ts
@@ -206,6 +231,19 @@ function createWalletInstance(walletType, extensionId, context) {
206
231
  break;
207
232
  default: throw new Error(`Unsupported wallet type: ${walletType}`);
208
233
  }
234
+ },
235
+ rejectTx: async () => {
236
+ const page = context.pages()[0] || await context.newPage();
237
+ const extPage = createExtendedPage(page, context, extensionId);
238
+ switch (walletType) {
239
+ case "polkadot-js":
240
+ await rejectPolkadotJSTx(extPage);
241
+ break;
242
+ case "talisman":
243
+ await rejectTalismanTx(extPage);
244
+ break;
245
+ default: throw new Error(`Unsupported wallet type: ${walletType}`);
246
+ }
209
247
  }
210
248
  };
211
249
  switch (walletType) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@avalix/chroma",
3
3
  "type": "module",
4
- "version": "0.0.8",
4
+ "version": "0.0.9",
5
5
  "description": "End-to-end testing library for Polkadot wallet interactions",
6
6
  "author": "Avalix Labs",
7
7
  "license": "MIT",
@@ -25,6 +25,7 @@ export interface BaseWalletInstance {
25
25
  importMnemonic: (options: WalletAccount) => Promise<void>
26
26
  authorize: (options?: { accountName?: string }) => Promise<void>
27
27
  approveTx: (options?: { password?: string }) => Promise<void>
28
+ rejectTx: () => Promise<void>
28
29
  }
29
30
 
30
31
  // Polkadot-JS specific wallet instance
@@ -10,11 +10,13 @@ import {
10
10
  approvePolkadotJSTx,
11
11
  authorizePolkadotJS,
12
12
  importPolkadotJSAccount,
13
+ rejectPolkadotJSTx,
13
14
  } from '../wallets/polkadot-js.js'
14
15
  import {
15
16
  approveTalismanTx,
16
17
  authorizeTalisman,
17
18
  importEthPrivateKey,
19
+ rejectTalismanTx,
18
20
  } from '../wallets/talisman.js'
19
21
 
20
22
  // Helper to create extended page with wallet context
@@ -87,6 +89,21 @@ export function createWalletInstance(
87
89
  throw new Error(`Unsupported wallet type: ${walletType}`)
88
90
  }
89
91
  },
92
+ rejectTx: async () => {
93
+ const page = context.pages()[0] || await context.newPage()
94
+ const extPage = createExtendedPage(page, context, extensionId)
95
+
96
+ switch (walletType) {
97
+ case 'polkadot-js':
98
+ await rejectPolkadotJSTx(extPage)
99
+ break
100
+ case 'talisman':
101
+ await rejectTalismanTx(extPage)
102
+ break
103
+ default:
104
+ throw new Error(`Unsupported wallet type: ${walletType}`)
105
+ }
106
+ },
90
107
  }
91
108
 
92
109
  // Return wallet-specific instance with type discriminator
@@ -12,12 +12,25 @@ export const POLKADOT_JS_CONFIG = {
12
12
 
13
13
  // Helper function to find extension popup
14
14
  async function findExtensionPopup(context: BrowserContext, extensionId: string): Promise<Page> {
15
- const pages = context.pages()
16
- for (const p of pages) {
17
- if (p.url().includes(`chrome-extension://${extensionId}/`)) {
18
- return p
15
+ // Wait for extension popup to appear with retry logic
16
+ const maxAttempts = 10
17
+ const retryDelay = 500
18
+
19
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
20
+ const pages = context.pages()
21
+ for (const p of pages) {
22
+ if (p.url().includes(`chrome-extension://${extensionId}/`)) {
23
+ await p.waitForLoadState('domcontentloaded')
24
+ return p
25
+ }
26
+ }
27
+
28
+ // If not found, wait a bit before retrying
29
+ if (attempt < maxAttempts - 1) {
30
+ await new Promise(resolve => setTimeout(resolve, retryDelay))
19
31
  }
20
32
  }
33
+
21
34
  throw new Error(`Extension popup not found for ID: ${extensionId}`)
22
35
  }
23
36
 
@@ -31,9 +44,7 @@ export async function getPolkadotJSExtensionPath(): Promise<string> {
31
44
  throw new Error(
32
45
  `Polkadot-JS extension not found at: ${extensionDir}\n\n`
33
46
  + `Please download the extension first by running:\n`
34
- + ` npx @avalix/chroma download-extensions\n\n`
35
- + `Or if you're using this as a dependency:\n`
36
- + ` npm run chroma:download\n`,
47
+ + ` npx @avalix/chroma download-extensions\n`,
37
48
  )
38
49
  }
39
50
 
@@ -86,7 +97,6 @@ export async function authorizePolkadotJS(
86
97
  ): Promise<void> {
87
98
  const context = page.__extensionContext
88
99
  const extensionId = page.__extensionId
89
- await new Promise(resolve => setTimeout(resolve, 1000))
90
100
 
91
101
  const extensionPopup = await findExtensionPopup(context, extensionId)
92
102
  await extensionPopup.getByText('Select all').click()
@@ -104,11 +114,22 @@ export async function approvePolkadotJSTx(
104
114
  const context = page.__extensionContext
105
115
  const extensionId = page.__extensionId
106
116
 
107
- await new Promise(resolve => setTimeout(resolve, 1000))
108
117
  const extensionPopup = await findExtensionPopup(context, extensionId)
109
-
110
118
  await extensionPopup.getByRole('textbox').fill(password)
111
119
  await extensionPopup.getByRole('button', { name: 'Sign the transaction' }).click()
112
120
 
113
121
  console.log('✅ Polkadot-JS transaction signed successfully')
114
122
  }
123
+
124
+ // Polkadot-JS specific transaction rejection implementation
125
+ export async function rejectPolkadotJSTx(
126
+ page: Page & { __extensionContext: BrowserContext, __extensionId: string },
127
+ ): Promise<void> {
128
+ const context = page.__extensionContext
129
+ const extensionId = page.__extensionId
130
+
131
+ const extensionPopup = await findExtensionPopup(context, extensionId)
132
+ await extensionPopup.getByRole('link', { name: 'Cancel' }).click()
133
+
134
+ console.log('✅ Polkadot-JS transaction rejected successfully')
135
+ }
@@ -12,15 +12,23 @@ export const TALISMAN_CONFIG = {
12
12
 
13
13
  // Helper function to find extension popup
14
14
  async function findExtensionPopup(context: BrowserContext, extensionId: string): Promise<Page> {
15
- // delay for 1 second
16
- await new Promise(resolve => setTimeout(resolve, 1000))
17
-
18
- const pages = context.pages()
19
- for (const p of pages) {
20
- if (p.url().includes(`chrome-extension://${extensionId}/`)) {
21
- p.setViewportSize({ width: 400, height: 600 })
22
- p.waitForLoadState('domcontentloaded')
23
- return p
15
+ // Wait for extension popup to appear with retry logic
16
+ const maxAttempts = 10
17
+ const retryDelay = 500
18
+
19
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
20
+ const pages = context.pages()
21
+ for (const p of pages) {
22
+ if (p.url().includes(`chrome-extension://${extensionId}/`)) {
23
+ await p.setViewportSize({ width: 400, height: 600 })
24
+ await p.waitForLoadState('domcontentloaded')
25
+ return p
26
+ }
27
+ }
28
+
29
+ // If not found, wait a bit before retrying
30
+ if (attempt < maxAttempts - 1) {
31
+ await new Promise(resolve => setTimeout(resolve, retryDelay))
24
32
  }
25
33
  }
26
34
 
@@ -37,9 +45,7 @@ export async function getTalismanExtensionPath(): Promise<string> {
37
45
  throw new Error(
38
46
  `Talisman extension not found at: ${extensionDir}\n\n`
39
47
  + `Please download the extension first by running:\n`
40
- + ` npx @avalix/chroma download-extensions\n\n`
41
- + `Or if you're using this as a dependency:\n`
42
- + ` npm run chroma:download\n`,
48
+ + ` npx @avalix/chroma download-extensions\n`,
43
49
  )
44
50
  }
45
51
 
@@ -55,38 +61,45 @@ export async function importEthPrivateKey(
55
61
  const context = page.__extensionContext
56
62
  const extensionId = page.__extensionId
57
63
 
58
- // Wait for Talisman to open its onboarding tab
59
- await new Promise(resolve => setTimeout(resolve, 2000))
60
-
61
- // Find the onboarding tab
64
+ // Wait for Talisman to open its onboarding tab with retry logic
65
+ const maxAttempts = 20
66
+ const retryDelay = 500
62
67
  let extensionPage: Page | null = null
63
- const pages = context.pages()
64
-
65
- for (const page of pages) {
66
- const url = page.url()
67
- console.log(`📄 Found page: ${url}`)
68
- if (url.includes('onboarding.html') || url.includes(`chrome-extension://${extensionId}/`)) {
69
- extensionPage = page
70
- console.log(`✅ Found Talisman onboarding page: ${url}`)
68
+
69
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
70
+ const pages = context.pages()
71
+
72
+ for (const p of pages) {
73
+ const url = p.url()
74
+ console.log(`📄 Found page: ${url}`)
75
+ if (url.includes('onboarding.html') || url.includes(`chrome-extension://${extensionId}/`)) {
76
+ extensionPage = p
77
+ console.log(`✅ Found Talisman onboarding page: ${url}`)
78
+ break
79
+ }
80
+ }
81
+
82
+ if (extensionPage) {
71
83
  break
72
84
  }
85
+
86
+ // If not found, wait before retrying
87
+ if (attempt < maxAttempts - 1) {
88
+ console.log(`⏳ Attempt ${attempt + 1}/${maxAttempts}: Waiting for onboarding page...`)
89
+ await new Promise(resolve => setTimeout(resolve, retryDelay))
90
+ }
73
91
  }
74
92
 
75
93
  if (!extensionPage) {
76
- throw new Error(`Talisman onboarding page not found`)
94
+ throw new Error(`Talisman onboarding page not found after ${maxAttempts} attempts`)
77
95
  }
78
96
 
79
97
  try {
80
98
  // Bring the onboarding page to front
81
99
  await extensionPage.bringToFront()
82
100
 
83
- // Reload the onboarding page to ensure fresh state
84
- console.log('🔄 Reloading onboarding page for fresh state...')
85
- await extensionPage.reload()
86
-
87
101
  // Wait for the page to load and become interactive
88
102
  await extensionPage.waitForLoadState('domcontentloaded')
89
- // await extensionPage.waitForTimeout(20000) // Give Talisman more time to initialize
90
103
 
91
104
  // Click the get started button
92
105
  await extensionPage.getByTestId('onboarding-get-started-button').click()
@@ -128,7 +141,6 @@ export async function authorizeTalisman(
128
141
  const { accountName = 'Test Account' } = options
129
142
  const context = page.__extensionContext
130
143
  const extensionId = page.__extensionId
131
- await new Promise(resolve => setTimeout(resolve, 1000))
132
144
 
133
145
  const extensionPopup = await findExtensionPopup(context, extensionId)
134
146
 
@@ -152,8 +164,17 @@ export async function approveTalismanTx(
152
164
  const context = page.__extensionContext
153
165
  const extensionId = page.__extensionId
154
166
 
155
- await new Promise(resolve => setTimeout(resolve, 1000))
156
167
  const extensionPopup = await findExtensionPopup(context, extensionId)
157
-
158
168
  await extensionPopup.getByRole('button', { name: 'Approve' }).click()
159
169
  }
170
+
171
+ // Talisman specific transaction rejection implementation
172
+ export async function rejectTalismanTx(
173
+ page: Page & { __extensionContext: BrowserContext, __extensionId: string },
174
+ ): Promise<void> {
175
+ const context = page.__extensionContext
176
+ const extensionId = page.__extensionId
177
+
178
+ const extensionPopup = await findExtensionPopup(context, extensionId)
179
+ await extensionPopup.getByTestId('connection-reject-button').click()
180
+ }