@avalix/chroma 0.0.10 → 0.0.12
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 +21 -228
- package/dist/index.d.mts +1736 -45729
- package/dist/index.mjs +107 -101
- package/package.json +9 -4
- package/scripts/download-extensions.ts +3 -3
- package/src/context-playwright/index.ts +6 -9
- package/src/context-playwright/types.ts +8 -26
- package/src/context-playwright/wallet-factory.ts +60 -96
- package/src/utils/download-extension.integration.test.ts +95 -0
- package/src/utils/download-extension.test.ts +173 -0
- package/src/utils/download-extension.ts +1 -1
- package/src/wallets/talisman.ts +106 -52
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import type { DownloadExtensionOptions } from './download-extension.js'
|
|
2
|
+
import fs from 'node:fs'
|
|
3
|
+
import os from 'node:os'
|
|
4
|
+
import path from 'node:path'
|
|
5
|
+
import { afterEach, beforeEach, describe, expect, it } from 'vitest'
|
|
6
|
+
import { downloadAndExtractExtension } from './download-extension.js'
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Integration Tests (real download) - Requires network
|
|
10
|
+
* Tests actual download and extraction with real extension files
|
|
11
|
+
*
|
|
12
|
+
* Important test cases:
|
|
13
|
+
* - Nested zip extraction (Talisman has a zip inside a zip)
|
|
14
|
+
* - Standard zip extraction (Polkadot-JS)
|
|
15
|
+
* - Skip download if already exists
|
|
16
|
+
* - Error handling for invalid URLs
|
|
17
|
+
*/
|
|
18
|
+
describe('downloadAndExtractExtension (integration tests)', () => {
|
|
19
|
+
let tempDir: string
|
|
20
|
+
|
|
21
|
+
beforeEach(async () => {
|
|
22
|
+
tempDir = path.join(os.tmpdir(), `chroma-test-${Date.now()}-${Math.random().toString(36).slice(2)}`)
|
|
23
|
+
await fs.promises.mkdir(tempDir, { recursive: true })
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
afterEach(async () => {
|
|
27
|
+
if (tempDir && fs.existsSync(tempDir)) {
|
|
28
|
+
await fs.promises.rm(tempDir, { recursive: true, force: true })
|
|
29
|
+
}
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
it('should handle nested zip extraction (Talisman)', async () => {
|
|
33
|
+
// Talisman extension has a nested zip structure
|
|
34
|
+
const VERSION = '3.1.13'
|
|
35
|
+
const options: DownloadExtensionOptions = {
|
|
36
|
+
downloadUrl: `https://github.com/avalix-labs/polkadot-wallets/raw/refs/heads/main/talisman/talisman-${VERSION}.zip`,
|
|
37
|
+
extensionName: `talisman-extension-${VERSION}`,
|
|
38
|
+
targetDir: tempDir,
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const result = await downloadAndExtractExtension(options)
|
|
42
|
+
|
|
43
|
+
expect(result).toBe(path.join(tempDir, `talisman-extension-${VERSION}`))
|
|
44
|
+
expect(fs.existsSync(result)).toBe(true)
|
|
45
|
+
|
|
46
|
+
// Talisman should have manifest.json after nested extraction
|
|
47
|
+
const files = await fs.promises.readdir(result)
|
|
48
|
+
expect(files).toContain('manifest.json')
|
|
49
|
+
}, 60000)
|
|
50
|
+
|
|
51
|
+
it('should handle standard zip extraction (Polkadot-JS)', async () => {
|
|
52
|
+
const VERSION = '0.62.6'
|
|
53
|
+
const options: DownloadExtensionOptions = {
|
|
54
|
+
downloadUrl: `https://github.com/polkadot-js/extension/releases/download/v${VERSION}/master-chrome-build.zip`,
|
|
55
|
+
extensionName: `polkadot-extension-${VERSION}`,
|
|
56
|
+
targetDir: tempDir,
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const result = await downloadAndExtractExtension(options)
|
|
60
|
+
|
|
61
|
+
expect(result).toBe(path.join(tempDir, `polkadot-extension-${VERSION}`))
|
|
62
|
+
expect(fs.existsSync(result)).toBe(true)
|
|
63
|
+
|
|
64
|
+
const files = await fs.promises.readdir(result)
|
|
65
|
+
expect(files).toContain('manifest.json')
|
|
66
|
+
}, 60000)
|
|
67
|
+
|
|
68
|
+
it('should skip download if extension already exists', async () => {
|
|
69
|
+
const extensionDir = path.join(tempDir, 'existing-extension')
|
|
70
|
+
await fs.promises.mkdir(extensionDir, { recursive: true })
|
|
71
|
+
await fs.promises.writeFile(path.join(extensionDir, 'manifest.json'), '{"name": "test"}')
|
|
72
|
+
|
|
73
|
+
const options: DownloadExtensionOptions = {
|
|
74
|
+
downloadUrl: 'https://example.com/should-not-be-called.zip',
|
|
75
|
+
extensionName: 'existing-extension',
|
|
76
|
+
targetDir: tempDir,
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const result = await downloadAndExtractExtension(options)
|
|
80
|
+
|
|
81
|
+
expect(result).toBe(extensionDir)
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
it('should throw error for invalid URL', async () => {
|
|
85
|
+
const options: DownloadExtensionOptions = {
|
|
86
|
+
downloadUrl: 'https://github.com/invalid-user-12345/nonexistent-repo/releases/download/v0.0.0/nonexistent.zip',
|
|
87
|
+
extensionName: 'invalid-extension',
|
|
88
|
+
targetDir: tempDir,
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
await expect(downloadAndExtractExtension(options)).rejects.toThrow(
|
|
92
|
+
/Failed to download\/extract invalid-extension/,
|
|
93
|
+
)
|
|
94
|
+
}, 15000)
|
|
95
|
+
})
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import type { DownloadExtensionOptions } from './download-extension.js'
|
|
2
|
+
import fs from 'node:fs'
|
|
3
|
+
import path from 'node:path'
|
|
4
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
|
5
|
+
import { downloadAndExtractExtension } from './download-extension.js'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Unit Tests (with mocks) - Fast, no network required
|
|
9
|
+
* Tests error handling, cleanup logic, and path resolution
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
// Mock adm-zip
|
|
13
|
+
const mockExtractAllTo = vi.fn()
|
|
14
|
+
vi.mock('adm-zip', () => {
|
|
15
|
+
return {
|
|
16
|
+
default: vi.fn().mockImplementation(() => ({
|
|
17
|
+
extractAllTo: mockExtractAllTo,
|
|
18
|
+
})),
|
|
19
|
+
}
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
// Mock fetch
|
|
23
|
+
const mockFetch = vi.fn()
|
|
24
|
+
vi.stubGlobal('fetch', mockFetch)
|
|
25
|
+
|
|
26
|
+
// Mock stream/promises pipeline
|
|
27
|
+
vi.mock('node:stream/promises', () => ({
|
|
28
|
+
pipeline: vi.fn().mockResolvedValue(undefined),
|
|
29
|
+
}))
|
|
30
|
+
|
|
31
|
+
// Mock fs module
|
|
32
|
+
vi.mock('node:fs', async () => {
|
|
33
|
+
const actual = await vi.importActual<typeof import('node:fs')>('node:fs')
|
|
34
|
+
return {
|
|
35
|
+
...actual,
|
|
36
|
+
default: {
|
|
37
|
+
...actual,
|
|
38
|
+
existsSync: vi.fn(),
|
|
39
|
+
readdirSync: vi.fn(),
|
|
40
|
+
promises: {
|
|
41
|
+
mkdir: vi.fn().mockResolvedValue(undefined),
|
|
42
|
+
rm: vi.fn().mockResolvedValue(undefined),
|
|
43
|
+
rename: vi.fn().mockResolvedValue(undefined),
|
|
44
|
+
unlink: vi.fn().mockResolvedValue(undefined),
|
|
45
|
+
readdir: vi.fn().mockResolvedValue([]),
|
|
46
|
+
},
|
|
47
|
+
createWriteStream: vi.fn().mockReturnValue({
|
|
48
|
+
on: vi.fn(),
|
|
49
|
+
write: vi.fn(),
|
|
50
|
+
end: vi.fn(),
|
|
51
|
+
}),
|
|
52
|
+
},
|
|
53
|
+
existsSync: vi.fn(),
|
|
54
|
+
readdirSync: vi.fn(),
|
|
55
|
+
createWriteStream: vi.fn().mockReturnValue({
|
|
56
|
+
on: vi.fn(),
|
|
57
|
+
write: vi.fn(),
|
|
58
|
+
end: vi.fn(),
|
|
59
|
+
}),
|
|
60
|
+
}
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
describe('downloadAndExtractExtension (unit tests)', () => {
|
|
64
|
+
const mockOptions: DownloadExtensionOptions = {
|
|
65
|
+
downloadUrl: 'https://example.com/extension.zip',
|
|
66
|
+
extensionName: 'test-extension',
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
beforeEach(() => {
|
|
70
|
+
vi.clearAllMocks()
|
|
71
|
+
vi.spyOn(console, 'log').mockImplementation(() => {})
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
afterEach(() => {
|
|
75
|
+
vi.restoreAllMocks()
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
describe('when extension already exists', () => {
|
|
79
|
+
it('should skip download and return existing path', async () => {
|
|
80
|
+
const mockedFs = vi.mocked(fs)
|
|
81
|
+
mockedFs.existsSync.mockReturnValue(true)
|
|
82
|
+
mockedFs.readdirSync.mockReturnValue(['manifest.json'] as any)
|
|
83
|
+
|
|
84
|
+
const result = await downloadAndExtractExtension(mockOptions)
|
|
85
|
+
|
|
86
|
+
expect(result).toContain('test-extension')
|
|
87
|
+
expect(mockFetch).not.toHaveBeenCalled()
|
|
88
|
+
expect(console.log).toHaveBeenCalledWith(
|
|
89
|
+
expect.stringContaining('already exists'),
|
|
90
|
+
expect.any(String),
|
|
91
|
+
)
|
|
92
|
+
})
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
describe('when extension does not exist', () => {
|
|
96
|
+
beforeEach(() => {
|
|
97
|
+
const mockedFs = vi.mocked(fs)
|
|
98
|
+
mockedFs.existsSync.mockReturnValue(false)
|
|
99
|
+
mockedFs.readdirSync.mockReturnValue([])
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
it('should throw error when download fails with bad status', async () => {
|
|
103
|
+
mockFetch.mockResolvedValue({
|
|
104
|
+
ok: false,
|
|
105
|
+
status: 404,
|
|
106
|
+
statusText: 'Not Found',
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
await expect(downloadAndExtractExtension(mockOptions)).rejects.toThrow(
|
|
110
|
+
'Failed to download/extract test-extension',
|
|
111
|
+
)
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
it('should throw error when fetch throws network error', async () => {
|
|
115
|
+
mockFetch.mockRejectedValue(new Error('Network error'))
|
|
116
|
+
|
|
117
|
+
await expect(downloadAndExtractExtension(mockOptions)).rejects.toThrow(
|
|
118
|
+
'Failed to download/extract test-extension: Network error',
|
|
119
|
+
)
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
it('should cleanup files on error', async () => {
|
|
123
|
+
const mockedFs = vi.mocked(fs)
|
|
124
|
+
|
|
125
|
+
mockFetch.mockResolvedValue({
|
|
126
|
+
ok: false,
|
|
127
|
+
status: 500,
|
|
128
|
+
statusText: 'Internal Server Error',
|
|
129
|
+
})
|
|
130
|
+
|
|
131
|
+
mockedFs.existsSync.mockImplementation((p: fs.PathLike) => {
|
|
132
|
+
const pathStr = p.toString()
|
|
133
|
+
if (pathStr.endsWith('test-extension') && !pathStr.includes('.zip')) {
|
|
134
|
+
return false
|
|
135
|
+
}
|
|
136
|
+
return true
|
|
137
|
+
})
|
|
138
|
+
|
|
139
|
+
await expect(downloadAndExtractExtension(mockOptions)).rejects.toThrow()
|
|
140
|
+
|
|
141
|
+
expect(mockedFs.promises.unlink).toHaveBeenCalled()
|
|
142
|
+
expect(mockedFs.promises.rm).toHaveBeenCalled()
|
|
143
|
+
})
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
describe('targetDir option', () => {
|
|
147
|
+
it('should use custom targetDir when provided', async () => {
|
|
148
|
+
const mockedFs = vi.mocked(fs)
|
|
149
|
+
mockedFs.existsSync.mockReturnValue(true)
|
|
150
|
+
mockedFs.readdirSync.mockReturnValue(['manifest.json'] as any)
|
|
151
|
+
|
|
152
|
+
const customOptions: DownloadExtensionOptions = {
|
|
153
|
+
...mockOptions,
|
|
154
|
+
targetDir: '/custom/path',
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const result = await downloadAndExtractExtension(customOptions)
|
|
158
|
+
|
|
159
|
+
expect(result).toBe(path.join('/custom/path', 'test-extension'))
|
|
160
|
+
})
|
|
161
|
+
|
|
162
|
+
it('should use default .chroma directory when targetDir not provided', async () => {
|
|
163
|
+
const mockedFs = vi.mocked(fs)
|
|
164
|
+
mockedFs.existsSync.mockReturnValue(true)
|
|
165
|
+
mockedFs.readdirSync.mockReturnValue(['manifest.json'] as any)
|
|
166
|
+
|
|
167
|
+
const result = await downloadAndExtractExtension(mockOptions)
|
|
168
|
+
|
|
169
|
+
expect(result).toContain('.chroma')
|
|
170
|
+
expect(result).toContain('test-extension')
|
|
171
|
+
})
|
|
172
|
+
})
|
|
173
|
+
})
|
|
@@ -34,7 +34,7 @@ export async function downloadAndExtractExtension(options: DownloadExtensionOpti
|
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
try {
|
|
37
|
-
console.log(
|
|
37
|
+
console.log(`\n📥 Downloading ${extensionName}...`)
|
|
38
38
|
|
|
39
39
|
// Download the ZIP file
|
|
40
40
|
const response = await fetch(downloadUrl)
|
package/src/wallets/talisman.ts
CHANGED
|
@@ -54,65 +54,114 @@ export async function getTalismanExtensionPath(): Promise<string> {
|
|
|
54
54
|
return extensionDir
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
//
|
|
58
|
-
|
|
57
|
+
// Helper function to find Talisman onboarding page
|
|
58
|
+
async function findOnboardingPage(
|
|
59
|
+
context: BrowserContext,
|
|
60
|
+
extensionId: string,
|
|
61
|
+
): Promise<Page> {
|
|
62
|
+
// Open new dashboard page
|
|
63
|
+
const popupUrl = `chrome-extension://${extensionId}/dashboard.html`
|
|
64
|
+
const newPage = await context.newPage()
|
|
65
|
+
await newPage.goto(popupUrl)
|
|
66
|
+
await newPage.waitForLoadState('domcontentloaded')
|
|
67
|
+
|
|
68
|
+
// Close any other extension tabs that may have been opened automatically
|
|
69
|
+
for (const p of context.pages()) {
|
|
70
|
+
if (p !== newPage && p.url().includes(`chrome-extension://${extensionId}/`)) {
|
|
71
|
+
await p.close()
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return newPage
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Helper function to complete Talisman onboarding flow
|
|
79
|
+
async function completeOnboarding(
|
|
80
|
+
extensionPage: Page,
|
|
81
|
+
password: string,
|
|
82
|
+
): Promise<void> {
|
|
83
|
+
// Bring the onboarding page to front
|
|
84
|
+
await extensionPage.bringToFront()
|
|
85
|
+
|
|
86
|
+
// Wait for the page to load and become interactive
|
|
87
|
+
await extensionPage.waitForLoadState('domcontentloaded')
|
|
88
|
+
|
|
89
|
+
if (await extensionPage.getByRole('button', { name: 'Settings' }).isVisible()) {
|
|
90
|
+
await extensionPage.getByRole('button', { name: 'Settings' }).click({ force: true })
|
|
91
|
+
return
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Click the get started button
|
|
95
|
+
await extensionPage.getByTestId('onboarding-get-started-button').click()
|
|
96
|
+
|
|
97
|
+
// Fill the password
|
|
98
|
+
await extensionPage.getByRole('textbox', { name: 'Enter password' }).fill(password)
|
|
99
|
+
await extensionPage.getByRole('textbox', { name: 'Confirm password' }).fill(password)
|
|
100
|
+
await extensionPage.getByTestId('onboarding-password-confirm-button').click()
|
|
101
|
+
|
|
102
|
+
// Click the no thanks button
|
|
103
|
+
await extensionPage.getByRole('button', { name: 'No thanks' }).click()
|
|
104
|
+
await extensionPage.getByTestId('onboarding-enter-talisman-button').click()
|
|
105
|
+
|
|
106
|
+
// Navigate directly to settings/general page
|
|
107
|
+
const extensionId = extensionPage.url().match(/chrome-extension:\/\/([^/]+)/)?.[1]
|
|
108
|
+
await extensionPage.goto(`chrome-extension://${extensionId}/dashboard.html#/settings/general`)
|
|
109
|
+
await extensionPage.waitForLoadState('domcontentloaded')
|
|
110
|
+
await extensionPage.getByRole('link', { name: 'Security & Privacy' }).click()
|
|
111
|
+
|
|
112
|
+
// Toggle the risk scan setting
|
|
113
|
+
await extensionPage.getByTestId('component-toggle-button').first().click()
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Talisman specific Polkadot mnemonic import implementation
|
|
117
|
+
export async function importPolkadotMnemonic(
|
|
59
118
|
page: Page & { __extensionContext: BrowserContext, __extensionId: string },
|
|
60
119
|
{ seed, name = 'Test Account', password = 'h3llop0lkadot!' }: WalletAccount,
|
|
61
120
|
): Promise<void> {
|
|
62
121
|
const context = page.__extensionContext
|
|
63
122
|
const extensionId = page.__extensionId
|
|
64
123
|
|
|
65
|
-
|
|
66
|
-
const maxAttempts = 20
|
|
67
|
-
const retryDelay = 500
|
|
68
|
-
let extensionPage: Page | null = null
|
|
69
|
-
|
|
70
|
-
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
71
|
-
const pages = context.pages()
|
|
124
|
+
const extensionPage = await findOnboardingPage(context, extensionId)
|
|
72
125
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
if (url.includes('onboarding.html') || url.includes(`chrome-extension://${extensionId}/`)) {
|
|
76
|
-
extensionPage = p
|
|
77
|
-
break
|
|
78
|
-
}
|
|
79
|
-
}
|
|
126
|
+
try {
|
|
127
|
+
await completeOnboarding(extensionPage, password!)
|
|
80
128
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
}
|
|
129
|
+
// Import Polkadot account via Recovery Phrase
|
|
130
|
+
await extensionPage.getByRole('link', { name: 'Manage Accounts' }).click()
|
|
131
|
+
await extensionPage.getByRole('button', { name: 'Get Started' }).click()
|
|
132
|
+
await extensionPage.getByRole('button', { name: 'Add Account' }).click()
|
|
133
|
+
await extensionPage.getByRole('button', { name: 'Import Import an existing' }).click()
|
|
134
|
+
await extensionPage.getByRole('button', { name: 'Import via Recovery Phrase' }).click()
|
|
135
|
+
await extensionPage.getByRole('button', { name: 'Polkadot Relay Chain, Asset' }).click()
|
|
136
|
+
await extensionPage.getByRole('textbox', { name: 'Choose a name' }).fill(name!)
|
|
137
|
+
await extensionPage.getByRole('textbox', { name: 'Enter your 12 or 24 word' }).fill(seed!)
|
|
138
|
+
await extensionPage.getByTestId('account-add-mnemonic-import-button').click()
|
|
84
139
|
|
|
85
|
-
|
|
86
|
-
if (attempt < maxAttempts - 1) {
|
|
87
|
-
await new Promise(resolve => setTimeout(resolve, retryDelay))
|
|
88
|
-
}
|
|
140
|
+
await extensionPage.close()
|
|
89
141
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
throw
|
|
142
|
+
catch (error) {
|
|
143
|
+
console.error('❌ Error during Talisman Polkadot account import:', error)
|
|
144
|
+
throw error
|
|
93
145
|
}
|
|
146
|
+
}
|
|
94
147
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
// Click the get started button
|
|
103
|
-
await extensionPage.getByTestId('onboarding-get-started-button').click()
|
|
148
|
+
// Talisman specific Ethereum private key import implementation
|
|
149
|
+
export async function importEthPrivateKey(
|
|
150
|
+
page: Page & { __extensionContext: BrowserContext, __extensionId: string },
|
|
151
|
+
{ seed, name = 'Test Account', password = 'h3llop0lkadot!' }: WalletAccount,
|
|
152
|
+
): Promise<void> {
|
|
153
|
+
const context = page.__extensionContext
|
|
154
|
+
const extensionId = page.__extensionId
|
|
104
155
|
|
|
105
|
-
|
|
106
|
-
await extensionPage.getByRole('textbox', { name: 'Enter password' }).fill(password!)
|
|
107
|
-
await extensionPage.getByRole('textbox', { name: 'Confirm password' }).fill(password!)
|
|
108
|
-
await extensionPage.getByTestId('onboarding-password-confirm-button').click()
|
|
156
|
+
const extensionPage = await findOnboardingPage(context, extensionId)
|
|
109
157
|
|
|
110
|
-
|
|
111
|
-
await extensionPage
|
|
112
|
-
await extensionPage.getByTestId('onboarding-enter-talisman-button').click()
|
|
158
|
+
try {
|
|
159
|
+
await completeOnboarding(extensionPage, password!)
|
|
113
160
|
|
|
114
|
-
// Import Ethereum account
|
|
115
|
-
await extensionPage.getByRole('
|
|
161
|
+
// Import Ethereum account via Private Key
|
|
162
|
+
await extensionPage.getByRole('link', { name: 'Manage Accounts' }).click()
|
|
163
|
+
await extensionPage.getByRole('button', { name: 'Get Started' }).click()
|
|
164
|
+
await extensionPage.getByRole('button', { name: 'Add Account' }).click()
|
|
116
165
|
await extensionPage.getByRole('button', { name: 'Import Import an existing' }).click()
|
|
117
166
|
await extensionPage.getByRole('button', { name: 'Import via Private Key' }).click()
|
|
118
167
|
await extensionPage.getByRole('button', { name: 'Select account platform' }).click()
|
|
@@ -124,7 +173,7 @@ export async function importEthPrivateKey(
|
|
|
124
173
|
await extensionPage.close()
|
|
125
174
|
}
|
|
126
175
|
catch (error) {
|
|
127
|
-
console.error('❌ Error during Talisman account import:', error)
|
|
176
|
+
console.error('❌ Error during Talisman Ethereum account import:', error)
|
|
128
177
|
throw error
|
|
129
178
|
}
|
|
130
179
|
}
|
|
@@ -134,14 +183,18 @@ export async function authorizeTalisman(
|
|
|
134
183
|
page: Page & { __extensionContext: BrowserContext, __extensionId: string },
|
|
135
184
|
options: { accountName?: string } = {},
|
|
136
185
|
): Promise<void> {
|
|
137
|
-
const { accountName = 'Test Account' } = options
|
|
138
186
|
const context = page.__extensionContext
|
|
139
187
|
const extensionId = page.__extensionId
|
|
188
|
+
const { accountName = 'Test Account' } = options
|
|
140
189
|
|
|
141
190
|
const extensionPopup = await findExtensionPopup(context, extensionId)
|
|
191
|
+
await extensionPopup.waitForLoadState('domcontentloaded')
|
|
142
192
|
|
|
143
193
|
// Authorize Talisman account
|
|
144
|
-
|
|
194
|
+
const accountButton = extensionPopup.getByRole('button', { name: accountName })
|
|
195
|
+
await accountButton.waitFor({ state: 'visible' })
|
|
196
|
+
await accountButton.scrollIntoViewIfNeeded()
|
|
197
|
+
await accountButton.click({ force: true })
|
|
145
198
|
await extensionPopup.getByTestId('connection-connect-button').click()
|
|
146
199
|
|
|
147
200
|
try {
|
|
@@ -161,12 +214,9 @@ export async function approveTalismanTx(
|
|
|
161
214
|
|
|
162
215
|
const extensionPopup = await findExtensionPopup(context, extensionId)
|
|
163
216
|
|
|
164
|
-
|
|
217
|
+
if (await extensionPopup.getByRole('button', { name: 'Yes' }).isVisible()) {
|
|
165
218
|
await extensionPopup.getByRole('button', { name: 'Yes' }).click()
|
|
166
219
|
}
|
|
167
|
-
catch {
|
|
168
|
-
console.log('No another popup found, skipping')
|
|
169
|
-
}
|
|
170
220
|
|
|
171
221
|
await extensionPopup.getByRole('button', { name: 'Approve' }).click()
|
|
172
222
|
}
|
|
@@ -179,5 +229,9 @@ export async function rejectTalismanTx(
|
|
|
179
229
|
const extensionId = page.__extensionId
|
|
180
230
|
|
|
181
231
|
const extensionPopup = await findExtensionPopup(context, extensionId)
|
|
182
|
-
|
|
232
|
+
|
|
233
|
+
const rejectButton = extensionPopup.getByTestId('connection-reject-button')
|
|
234
|
+
.or(extensionPopup.getByRole('button', { name: 'Cancel' }))
|
|
235
|
+
|
|
236
|
+
await rejectButton.click()
|
|
183
237
|
}
|