@avalix/chroma 0.0.11 → 0.0.13
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 +27 -228
- package/dist/index.d.mts +28 -21
- package/dist/index.mjs +123 -101
- package/package.json +5 -3
- package/scripts/download-extensions.ts +3 -3
- package/src/context-playwright/index.test.ts +148 -0
- package/src/context-playwright/index.ts +17 -10
- package/src/context-playwright/types.ts +8 -26
- package/src/context-playwright/wallet-factory.test.ts +106 -0
- package/src/context-playwright/wallet-factory.ts +72 -96
- package/src/index.test.ts +57 -0
- package/src/utils/download-extension.ts +1 -1
- package/src/wallets/polkadot-js.test.ts +97 -0
- package/src/wallets/polkadot-js.ts +15 -1
- package/src/wallets/talisman.test.ts +97 -0
- package/src/wallets/talisman.ts +121 -53
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import type { BrowserContext, Page } from '@playwright/test'
|
|
2
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
3
|
+
import {
|
|
4
|
+
createPolkadotJsWallet,
|
|
5
|
+
createTalismanWallet,
|
|
6
|
+
walletFactories,
|
|
7
|
+
} from './wallet-factory.js'
|
|
8
|
+
|
|
9
|
+
// Mock wallet implementations
|
|
10
|
+
vi.mock('../wallets/polkadot-js.js', () => ({
|
|
11
|
+
importPolkadotJSAccount: vi.fn(),
|
|
12
|
+
authorizePolkadotJS: vi.fn(),
|
|
13
|
+
approvePolkadotJSTx: vi.fn(),
|
|
14
|
+
rejectPolkadotJSTx: vi.fn(),
|
|
15
|
+
}))
|
|
16
|
+
|
|
17
|
+
vi.mock('../wallets/talisman.js', () => ({
|
|
18
|
+
importPolkadotMnemonic: vi.fn(),
|
|
19
|
+
importEthPrivateKey: vi.fn(),
|
|
20
|
+
authorizeTalisman: vi.fn(),
|
|
21
|
+
approveTalismanTx: vi.fn(),
|
|
22
|
+
rejectTalismanTx: vi.fn(),
|
|
23
|
+
}))
|
|
24
|
+
|
|
25
|
+
// Create mock browser context
|
|
26
|
+
function createMockContext(): BrowserContext {
|
|
27
|
+
const mockPage = {
|
|
28
|
+
url: () => 'https://example.com',
|
|
29
|
+
__extensionContext: null,
|
|
30
|
+
__extensionId: '',
|
|
31
|
+
} as unknown as Page
|
|
32
|
+
|
|
33
|
+
return {
|
|
34
|
+
pages: vi.fn().mockReturnValue([mockPage]),
|
|
35
|
+
newPage: vi.fn().mockResolvedValue(mockPage),
|
|
36
|
+
} as unknown as BrowserContext
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
describe('wallet-factory', () => {
|
|
40
|
+
beforeEach(() => {
|
|
41
|
+
vi.clearAllMocks()
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
describe('walletFactories', () => {
|
|
45
|
+
it('should have polkadot-js factory', () => {
|
|
46
|
+
expect(walletFactories['polkadot-js']).toBeDefined()
|
|
47
|
+
expect(typeof walletFactories['polkadot-js']).toBe('function')
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
it('should have talisman factory', () => {
|
|
51
|
+
expect(walletFactories.talisman).toBeDefined()
|
|
52
|
+
expect(typeof walletFactories.talisman).toBe('function')
|
|
53
|
+
})
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
describe('createPolkadotJsWallet', () => {
|
|
57
|
+
const extensionId = 'test-extension-id'
|
|
58
|
+
let mockContext: BrowserContext
|
|
59
|
+
|
|
60
|
+
beforeEach(() => {
|
|
61
|
+
mockContext = createMockContext()
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
it('should create wallet with correct type and extensionId', () => {
|
|
65
|
+
const wallet = createPolkadotJsWallet(extensionId, mockContext)
|
|
66
|
+
|
|
67
|
+
expect(wallet.type).toBe('polkadot-js')
|
|
68
|
+
expect(wallet.extensionId).toBe(extensionId)
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
it('should have all required methods', () => {
|
|
72
|
+
const wallet = createPolkadotJsWallet(extensionId, mockContext)
|
|
73
|
+
|
|
74
|
+
expect(typeof wallet.importMnemonic).toBe('function')
|
|
75
|
+
expect(typeof wallet.authorize).toBe('function')
|
|
76
|
+
expect(typeof wallet.approveTx).toBe('function')
|
|
77
|
+
expect(typeof wallet.rejectTx).toBe('function')
|
|
78
|
+
})
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
describe('createTalismanWallet', () => {
|
|
82
|
+
const extensionId = 'test-extension-id'
|
|
83
|
+
let mockContext: BrowserContext
|
|
84
|
+
|
|
85
|
+
beforeEach(() => {
|
|
86
|
+
mockContext = createMockContext()
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
it('should create wallet with correct type and extensionId', () => {
|
|
90
|
+
const wallet = createTalismanWallet(extensionId, mockContext)
|
|
91
|
+
|
|
92
|
+
expect(wallet.type).toBe('talisman')
|
|
93
|
+
expect(wallet.extensionId).toBe(extensionId)
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
it('should have all required methods', () => {
|
|
97
|
+
const wallet = createTalismanWallet(extensionId, mockContext)
|
|
98
|
+
|
|
99
|
+
expect(typeof wallet.importPolkadotMnemonic).toBe('function')
|
|
100
|
+
expect(typeof wallet.importEthPrivateKey).toBe('function')
|
|
101
|
+
expect(typeof wallet.authorize).toBe('function')
|
|
102
|
+
expect(typeof wallet.approveTx).toBe('function')
|
|
103
|
+
expect(typeof wallet.rejectTx).toBe('function')
|
|
104
|
+
})
|
|
105
|
+
})
|
|
106
|
+
})
|
|
@@ -1,11 +1,5 @@
|
|
|
1
1
|
import type { BrowserContext, Page } from '@playwright/test'
|
|
2
|
-
import type {
|
|
3
|
-
BaseWalletInstance,
|
|
4
|
-
PolkadotJsWalletInstance,
|
|
5
|
-
TalismanWalletInstance,
|
|
6
|
-
WalletAccount,
|
|
7
|
-
WalletInstance,
|
|
8
|
-
} from './types.js'
|
|
2
|
+
import type { WalletAccount } from './types.js'
|
|
9
3
|
import {
|
|
10
4
|
approvePolkadotJSTx,
|
|
11
5
|
authorizePolkadotJS,
|
|
@@ -16,125 +10,107 @@ import {
|
|
|
16
10
|
approveTalismanTx,
|
|
17
11
|
authorizeTalisman,
|
|
18
12
|
importEthPrivateKey,
|
|
13
|
+
importPolkadotMnemonic,
|
|
19
14
|
rejectTalismanTx,
|
|
20
15
|
} from '../wallets/talisman.js'
|
|
21
16
|
|
|
22
17
|
// Helper to create extended page with wallet context
|
|
18
|
+
/* c8 ignore start */
|
|
23
19
|
function createExtendedPage(page: Page, context: BrowserContext, extensionId: string) {
|
|
24
20
|
const extPage = page as Page & { __extensionContext: BrowserContext, __extensionId: string }
|
|
25
21
|
extPage.__extensionContext = context
|
|
26
22
|
extPage.__extensionId = extensionId
|
|
27
23
|
return extPage
|
|
28
24
|
}
|
|
25
|
+
/* c8 ignore stop */
|
|
29
26
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
let importedAccountName: string | undefined
|
|
38
|
-
|
|
39
|
-
// Common methods for all wallets
|
|
40
|
-
const baseInstance: BaseWalletInstance = {
|
|
27
|
+
/*
|
|
28
|
+
* Factory function for Polkadot-JS wallet
|
|
29
|
+
* Coverage excluded: methods interact with Chrome extension APIs via browser context.
|
|
30
|
+
*/
|
|
31
|
+
/* c8 ignore start */
|
|
32
|
+
export function createPolkadotJsWallet(extensionId: string, context: BrowserContext) {
|
|
33
|
+
return {
|
|
41
34
|
extensionId,
|
|
35
|
+
type: 'polkadot-js' as const,
|
|
42
36
|
importMnemonic: async (options: WalletAccount) => {
|
|
43
37
|
const page = context.pages()[0] || await context.newPage()
|
|
44
38
|
const extPage = createExtendedPage(page, context, extensionId)
|
|
39
|
+
await importPolkadotJSAccount(extPage, options)
|
|
40
|
+
},
|
|
41
|
+
authorize: async () => {
|
|
42
|
+
const page = context.pages()[0] || await context.newPage()
|
|
43
|
+
const extPage = createExtendedPage(page, context, extensionId)
|
|
44
|
+
await authorizePolkadotJS(extPage)
|
|
45
|
+
},
|
|
46
|
+
approveTx: async (options: { password?: string } = {}) => {
|
|
47
|
+
const page = context.pages()[0] || await context.newPage()
|
|
48
|
+
const extPage = createExtendedPage(page, context, extensionId)
|
|
49
|
+
await approvePolkadotJSTx(extPage, options)
|
|
50
|
+
},
|
|
51
|
+
rejectTx: async () => {
|
|
52
|
+
const page = context.pages()[0] || await context.newPage()
|
|
53
|
+
const extPage = createExtendedPage(page, context, extensionId)
|
|
54
|
+
await rejectPolkadotJSTx(extPage)
|
|
55
|
+
},
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/* c8 ignore stop */
|
|
45
59
|
|
|
46
|
-
|
|
47
|
-
|
|
60
|
+
/*
|
|
61
|
+
* Factory function for Talisman wallet
|
|
62
|
+
* Coverage excluded: methods interact with Chrome extension APIs via browser context.
|
|
63
|
+
*/
|
|
64
|
+
/* c8 ignore start */
|
|
65
|
+
export function createTalismanWallet(extensionId: string, context: BrowserContext) {
|
|
66
|
+
let importedAccountName: string | undefined
|
|
48
67
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
68
|
+
return {
|
|
69
|
+
extensionId,
|
|
70
|
+
type: 'talisman' as const,
|
|
71
|
+
importPolkadotMnemonic: async (options: WalletAccount) => {
|
|
72
|
+
const page = context.pages()[0] || await context.newPage()
|
|
73
|
+
const extPage = createExtendedPage(page, context, extensionId)
|
|
74
|
+
importedAccountName = options.name || 'Test Account'
|
|
75
|
+
await importPolkadotMnemonic(extPage, options)
|
|
76
|
+
},
|
|
77
|
+
importEthPrivateKey: async (options: { privateKey: string, name?: string, password?: string }) => {
|
|
78
|
+
const page = context.pages()[0] || await context.newPage()
|
|
79
|
+
const extPage = createExtendedPage(page, context, extensionId)
|
|
80
|
+
importedAccountName = options.name || 'Test Account'
|
|
81
|
+
await importEthPrivateKey(extPage, {
|
|
82
|
+
seed: options.privateKey,
|
|
83
|
+
name: options.name,
|
|
84
|
+
password: options.password,
|
|
85
|
+
})
|
|
58
86
|
},
|
|
59
87
|
authorize: async (options: { accountName?: string } = {}) => {
|
|
60
88
|
const page = context.pages()[0] || await context.newPage()
|
|
61
89
|
const extPage = createExtendedPage(page, context, extensionId)
|
|
62
|
-
|
|
63
|
-
// Use provided account name or fall back to the imported one
|
|
64
90
|
const accountName = options.accountName || importedAccountName
|
|
65
|
-
|
|
66
|
-
switch (walletType) {
|
|
67
|
-
case 'polkadot-js':
|
|
68
|
-
await authorizePolkadotJS(extPage)
|
|
69
|
-
break
|
|
70
|
-
case 'talisman':
|
|
71
|
-
await authorizeTalisman(extPage, { accountName })
|
|
72
|
-
break
|
|
73
|
-
default:
|
|
74
|
-
throw new Error(`Unsupported wallet type: ${walletType}`)
|
|
75
|
-
}
|
|
91
|
+
await authorizeTalisman(extPage, { accountName })
|
|
76
92
|
},
|
|
77
|
-
approveTx: async (
|
|
93
|
+
approveTx: async () => {
|
|
78
94
|
const page = context.pages()[0] || await context.newPage()
|
|
79
95
|
const extPage = createExtendedPage(page, context, extensionId)
|
|
80
|
-
|
|
81
|
-
switch (walletType) {
|
|
82
|
-
case 'polkadot-js':
|
|
83
|
-
await approvePolkadotJSTx(extPage, options)
|
|
84
|
-
break
|
|
85
|
-
case 'talisman':
|
|
86
|
-
await approveTalismanTx(extPage)
|
|
87
|
-
break
|
|
88
|
-
default:
|
|
89
|
-
throw new Error(`Unsupported wallet type: ${walletType}`)
|
|
90
|
-
}
|
|
96
|
+
await approveTalismanTx(extPage)
|
|
91
97
|
},
|
|
92
98
|
rejectTx: async () => {
|
|
93
99
|
const page = context.pages()[0] || await context.newPage()
|
|
94
100
|
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
|
-
}
|
|
101
|
+
await rejectTalismanTx(extPage)
|
|
106
102
|
},
|
|
107
103
|
}
|
|
104
|
+
}
|
|
105
|
+
/* c8 ignore stop */
|
|
108
106
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
...baseInstance,
|
|
114
|
-
type: 'polkadot-js',
|
|
115
|
-
} as PolkadotJsWalletInstance
|
|
116
|
-
|
|
117
|
-
case 'talisman':
|
|
118
|
-
return {
|
|
119
|
-
...baseInstance,
|
|
120
|
-
type: 'talisman',
|
|
121
|
-
importEthPrivateKey: async (options: { privateKey: string, name?: string, password?: string }) => {
|
|
122
|
-
const page = context.pages()[0] || await context.newPage()
|
|
123
|
-
const extPage = createExtendedPage(page, context, extensionId)
|
|
124
|
-
|
|
125
|
-
// Store the account name for future authorize calls
|
|
126
|
-
importedAccountName = options.name || 'Test Account'
|
|
127
|
-
|
|
128
|
-
// Use the seed property to pass the private key
|
|
129
|
-
await importEthPrivateKey(extPage, {
|
|
130
|
-
seed: options.privateKey,
|
|
131
|
-
name: options.name,
|
|
132
|
-
password: options.password,
|
|
133
|
-
})
|
|
134
|
-
},
|
|
135
|
-
} as TalismanWalletInstance
|
|
136
|
-
|
|
137
|
-
default:
|
|
138
|
-
throw new Error(`Unsupported wallet type: ${walletType}`)
|
|
139
|
-
}
|
|
107
|
+
// Wallet factories map - auto-inferred types
|
|
108
|
+
export const walletFactories = {
|
|
109
|
+
'polkadot-js': createPolkadotJsWallet,
|
|
110
|
+
'talisman': createTalismanWallet,
|
|
140
111
|
}
|
|
112
|
+
|
|
113
|
+
// Auto-inferred types from factory functions
|
|
114
|
+
export type PolkadotJsWalletInstance = ReturnType<typeof createPolkadotJsWallet>
|
|
115
|
+
export type TalismanWalletInstance = ReturnType<typeof createTalismanWallet>
|
|
116
|
+
export type WalletInstance = PolkadotJsWalletInstance | TalismanWalletInstance
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from 'vitest'
|
|
2
|
+
|
|
3
|
+
// Mock playwright before importing
|
|
4
|
+
vi.mock('@playwright/test', () => ({
|
|
5
|
+
test: {
|
|
6
|
+
extend: vi.fn().mockReturnValue({}),
|
|
7
|
+
},
|
|
8
|
+
chromium: {
|
|
9
|
+
launchPersistentContext: vi.fn(),
|
|
10
|
+
},
|
|
11
|
+
expect: vi.fn(),
|
|
12
|
+
}))
|
|
13
|
+
|
|
14
|
+
vi.mock('./wallets/polkadot-js.js', () => ({
|
|
15
|
+
getPolkadotJSExtensionPath: vi.fn().mockResolvedValue('/mock/path'),
|
|
16
|
+
}))
|
|
17
|
+
|
|
18
|
+
vi.mock('./wallets/talisman.js', () => ({
|
|
19
|
+
getTalismanExtensionPath: vi.fn().mockResolvedValue('/mock/path'),
|
|
20
|
+
}))
|
|
21
|
+
|
|
22
|
+
vi.mock('./context-playwright/wallet-factory.js', () => ({
|
|
23
|
+
walletFactories: {
|
|
24
|
+
'polkadot-js': vi.fn(),
|
|
25
|
+
'talisman': vi.fn(),
|
|
26
|
+
},
|
|
27
|
+
}))
|
|
28
|
+
|
|
29
|
+
describe('index exports', () => {
|
|
30
|
+
it('should export createWalletTest function', async () => {
|
|
31
|
+
const { createWalletTest } = await import('./index.js')
|
|
32
|
+
expect(createWalletTest).toBeDefined()
|
|
33
|
+
expect(typeof createWalletTest).toBe('function')
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
it('should export test function', async () => {
|
|
37
|
+
const { test } = await import('./index.js')
|
|
38
|
+
expect(test).toBeDefined()
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
it('should export expect function', async () => {
|
|
42
|
+
const { expect: playwrightExpect } = await import('./index.js')
|
|
43
|
+
expect(playwrightExpect).toBeDefined()
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
it('should be able to call createWalletTest', async () => {
|
|
47
|
+
const { createWalletTest } = await import('./index.js')
|
|
48
|
+
const result = createWalletTest()
|
|
49
|
+
expect(result).toBeDefined()
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
it('should be able to call createWalletTest with options', async () => {
|
|
53
|
+
const { createWalletTest } = await import('./index.js')
|
|
54
|
+
const result = createWalletTest({ headless: true })
|
|
55
|
+
expect(result).toBeDefined()
|
|
56
|
+
})
|
|
57
|
+
})
|
|
@@ -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)
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import fs from 'node:fs'
|
|
2
|
+
import path from 'node:path'
|
|
3
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
|
4
|
+
import {
|
|
5
|
+
getPolkadotJSExtensionPath,
|
|
6
|
+
POLKADOT_JS_CONFIG,
|
|
7
|
+
} from './polkadot-js.js'
|
|
8
|
+
|
|
9
|
+
// Mock node:fs module
|
|
10
|
+
vi.mock('node:fs', async () => {
|
|
11
|
+
const actual = await vi.importActual<typeof import('node:fs')>('node:fs')
|
|
12
|
+
return {
|
|
13
|
+
...actual,
|
|
14
|
+
default: {
|
|
15
|
+
...actual,
|
|
16
|
+
existsSync: vi.fn(),
|
|
17
|
+
readdirSync: vi.fn(),
|
|
18
|
+
},
|
|
19
|
+
existsSync: vi.fn(),
|
|
20
|
+
readdirSync: vi.fn(),
|
|
21
|
+
}
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
describe('polkadot-js wallet', () => {
|
|
25
|
+
beforeEach(() => {
|
|
26
|
+
vi.clearAllMocks()
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
afterEach(() => {
|
|
30
|
+
vi.restoreAllMocks()
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
describe('polkadot_js_config', () => {
|
|
34
|
+
it('should have correct extension name format', () => {
|
|
35
|
+
expect(POLKADOT_JS_CONFIG.extensionName).toMatch(/^polkadot-extension-\d+\.\d+\.\d+$/)
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
it('should have valid download URL', () => {
|
|
39
|
+
expect(POLKADOT_JS_CONFIG.downloadUrl).toContain('github.com')
|
|
40
|
+
expect(POLKADOT_JS_CONFIG.downloadUrl).toContain('polkadot-js/extension')
|
|
41
|
+
expect(POLKADOT_JS_CONFIG.downloadUrl.endsWith('.zip')).toBe(true)
|
|
42
|
+
})
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
describe('getPolkadotJSExtensionPath', () => {
|
|
46
|
+
it('should return extension path when extension exists', async () => {
|
|
47
|
+
const mockedFs = vi.mocked(fs)
|
|
48
|
+
mockedFs.existsSync.mockReturnValue(true)
|
|
49
|
+
mockedFs.readdirSync.mockReturnValue(['manifest.json'] as any)
|
|
50
|
+
|
|
51
|
+
const result = await getPolkadotJSExtensionPath()
|
|
52
|
+
|
|
53
|
+
expect(result).toContain('.chroma')
|
|
54
|
+
expect(result).toContain(POLKADOT_JS_CONFIG.extensionName)
|
|
55
|
+
expect(mockedFs.existsSync).toHaveBeenCalled()
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
it('should throw error when extension directory does not exist', async () => {
|
|
59
|
+
const mockedFs = vi.mocked(fs)
|
|
60
|
+
mockedFs.existsSync.mockReturnValue(false)
|
|
61
|
+
|
|
62
|
+
await expect(getPolkadotJSExtensionPath()).rejects.toThrow(
|
|
63
|
+
'Polkadot-JS extension not found',
|
|
64
|
+
)
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
it('should throw error when extension directory is empty', async () => {
|
|
68
|
+
const mockedFs = vi.mocked(fs)
|
|
69
|
+
mockedFs.existsSync.mockReturnValue(true)
|
|
70
|
+
mockedFs.readdirSync.mockReturnValue([])
|
|
71
|
+
|
|
72
|
+
await expect(getPolkadotJSExtensionPath()).rejects.toThrow(
|
|
73
|
+
'Polkadot-JS extension not found',
|
|
74
|
+
)
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
it('should include download instructions in error message', async () => {
|
|
78
|
+
const mockedFs = vi.mocked(fs)
|
|
79
|
+
mockedFs.existsSync.mockReturnValue(false)
|
|
80
|
+
|
|
81
|
+
await expect(getPolkadotJSExtensionPath()).rejects.toThrow(
|
|
82
|
+
'npx @avalix/chroma download-extensions',
|
|
83
|
+
)
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
it('should use correct path structure', async () => {
|
|
87
|
+
const mockedFs = vi.mocked(fs)
|
|
88
|
+
mockedFs.existsSync.mockReturnValue(true)
|
|
89
|
+
mockedFs.readdirSync.mockReturnValue(['manifest.json'] as any)
|
|
90
|
+
|
|
91
|
+
const result = await getPolkadotJSExtensionPath()
|
|
92
|
+
|
|
93
|
+
const expectedPath = path.join(process.cwd(), '.chroma', POLKADOT_JS_CONFIG.extensionName)
|
|
94
|
+
expect(result).toBe(expectedPath)
|
|
95
|
+
})
|
|
96
|
+
})
|
|
97
|
+
})
|
|
@@ -12,7 +12,11 @@ export const POLKADOT_JS_CONFIG = {
|
|
|
12
12
|
extensionName: `polkadot-extension-${VERSION}`,
|
|
13
13
|
} as const
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
/*
|
|
16
|
+
* Helper function to find extension popup
|
|
17
|
+
* Coverage excluded: requires real browser context with Chrome extension APIs.
|
|
18
|
+
*/
|
|
19
|
+
/* c8 ignore start */
|
|
16
20
|
async function findExtensionPopup(context: BrowserContext, extensionId: string): Promise<Page> {
|
|
17
21
|
// Wait for extension popup to appear with retry logic
|
|
18
22
|
const maxAttempts = 10
|
|
@@ -35,6 +39,7 @@ async function findExtensionPopup(context: BrowserContext, extensionId: string):
|
|
|
35
39
|
|
|
36
40
|
throw new Error(`Extension popup not found for ID: ${extensionId}`)
|
|
37
41
|
}
|
|
42
|
+
/* c8 ignore stop */
|
|
38
43
|
|
|
39
44
|
// Get Polkadot-JS extension path
|
|
40
45
|
export async function getPolkadotJSExtensionPath(): Promise<string> {
|
|
@@ -53,6 +58,13 @@ export async function getPolkadotJSExtensionPath(): Promise<string> {
|
|
|
53
58
|
return extensionDir
|
|
54
59
|
}
|
|
55
60
|
|
|
61
|
+
/*
|
|
62
|
+
* Wallet interaction functions below are excluded from coverage because:
|
|
63
|
+
* - They require a real Chromium browser with extension support
|
|
64
|
+
* - They interact with Chrome extension popup pages
|
|
65
|
+
*/
|
|
66
|
+
/* c8 ignore start */
|
|
67
|
+
|
|
56
68
|
// Polkadot-JS specific account import implementation
|
|
57
69
|
export async function importPolkadotJSAccount(
|
|
58
70
|
page: Page & { __extensionContext: BrowserContext, __extensionId: string },
|
|
@@ -142,3 +154,5 @@ export async function rejectPolkadotJSTx(
|
|
|
142
154
|
const extensionPopup = await findExtensionPopup(context, extensionId)
|
|
143
155
|
await extensionPopup.getByRole('link', { name: 'Cancel' }).click()
|
|
144
156
|
}
|
|
157
|
+
|
|
158
|
+
/* c8 ignore stop */
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import fs from 'node:fs'
|
|
2
|
+
import path from 'node:path'
|
|
3
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
|
4
|
+
import {
|
|
5
|
+
getTalismanExtensionPath,
|
|
6
|
+
TALISMAN_CONFIG,
|
|
7
|
+
} from './talisman.js'
|
|
8
|
+
|
|
9
|
+
// Mock node:fs module
|
|
10
|
+
vi.mock('node:fs', async () => {
|
|
11
|
+
const actual = await vi.importActual<typeof import('node:fs')>('node:fs')
|
|
12
|
+
return {
|
|
13
|
+
...actual,
|
|
14
|
+
default: {
|
|
15
|
+
...actual,
|
|
16
|
+
existsSync: vi.fn(),
|
|
17
|
+
readdirSync: vi.fn(),
|
|
18
|
+
},
|
|
19
|
+
existsSync: vi.fn(),
|
|
20
|
+
readdirSync: vi.fn(),
|
|
21
|
+
}
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
describe('talisman wallet', () => {
|
|
25
|
+
beforeEach(() => {
|
|
26
|
+
vi.clearAllMocks()
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
afterEach(() => {
|
|
30
|
+
vi.restoreAllMocks()
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
describe('talisman_config', () => {
|
|
34
|
+
it('should have correct extension name format', () => {
|
|
35
|
+
expect(TALISMAN_CONFIG.extensionName).toMatch(/^talisman-extension-\d+\.\d+\.\d+$/)
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
it('should have valid download URL', () => {
|
|
39
|
+
expect(TALISMAN_CONFIG.downloadUrl).toContain('github.com')
|
|
40
|
+
expect(TALISMAN_CONFIG.downloadUrl).toContain('talisman')
|
|
41
|
+
expect(TALISMAN_CONFIG.downloadUrl.endsWith('.zip')).toBe(true)
|
|
42
|
+
})
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
describe('getTalismanExtensionPath', () => {
|
|
46
|
+
it('should return extension path when extension exists', async () => {
|
|
47
|
+
const mockedFs = vi.mocked(fs)
|
|
48
|
+
mockedFs.existsSync.mockReturnValue(true)
|
|
49
|
+
mockedFs.readdirSync.mockReturnValue(['manifest.json'] as any)
|
|
50
|
+
|
|
51
|
+
const result = await getTalismanExtensionPath()
|
|
52
|
+
|
|
53
|
+
expect(result).toContain('.chroma')
|
|
54
|
+
expect(result).toContain(TALISMAN_CONFIG.extensionName)
|
|
55
|
+
expect(mockedFs.existsSync).toHaveBeenCalled()
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
it('should throw error when extension directory does not exist', async () => {
|
|
59
|
+
const mockedFs = vi.mocked(fs)
|
|
60
|
+
mockedFs.existsSync.mockReturnValue(false)
|
|
61
|
+
|
|
62
|
+
await expect(getTalismanExtensionPath()).rejects.toThrow(
|
|
63
|
+
'Talisman extension not found',
|
|
64
|
+
)
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
it('should throw error when extension directory is empty', async () => {
|
|
68
|
+
const mockedFs = vi.mocked(fs)
|
|
69
|
+
mockedFs.existsSync.mockReturnValue(true)
|
|
70
|
+
mockedFs.readdirSync.mockReturnValue([])
|
|
71
|
+
|
|
72
|
+
await expect(getTalismanExtensionPath()).rejects.toThrow(
|
|
73
|
+
'Talisman extension not found',
|
|
74
|
+
)
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
it('should include download instructions in error message', async () => {
|
|
78
|
+
const mockedFs = vi.mocked(fs)
|
|
79
|
+
mockedFs.existsSync.mockReturnValue(false)
|
|
80
|
+
|
|
81
|
+
await expect(getTalismanExtensionPath()).rejects.toThrow(
|
|
82
|
+
'npx @avalix/chroma download-extensions',
|
|
83
|
+
)
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
it('should use correct path structure', async () => {
|
|
87
|
+
const mockedFs = vi.mocked(fs)
|
|
88
|
+
mockedFs.existsSync.mockReturnValue(true)
|
|
89
|
+
mockedFs.readdirSync.mockReturnValue(['manifest.json'] as any)
|
|
90
|
+
|
|
91
|
+
const result = await getTalismanExtensionPath()
|
|
92
|
+
|
|
93
|
+
const expectedPath = path.join(process.cwd(), '.chroma', TALISMAN_CONFIG.extensionName)
|
|
94
|
+
expect(result).toBe(expectedPath)
|
|
95
|
+
})
|
|
96
|
+
})
|
|
97
|
+
})
|