@bsv/sdk 2.0.11 → 2.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/dist/cjs/package.json +1 -1
- package/dist/cjs/src/auth/clients/__tests__/AuthFetch.additional.test.js +827 -0
- package/dist/cjs/src/auth/clients/__tests__/AuthFetch.additional.test.js.map +1 -0
- package/dist/cjs/src/auth/transports/__tests__/SimplifiedFetchTransport.additional.test.js +654 -0
- package/dist/cjs/src/auth/transports/__tests__/SimplifiedFetchTransport.additional.test.js.map +1 -0
- package/dist/cjs/src/overlay-tools/HostReputationTracker.js +21 -13
- package/dist/cjs/src/overlay-tools/HostReputationTracker.js.map +1 -1
- package/dist/cjs/src/primitives/PrivateKey.js +3 -3
- package/dist/cjs/src/primitives/PrivateKey.js.map +1 -1
- package/dist/cjs/src/script/Spend.js +17 -9
- package/dist/cjs/src/script/Spend.js.map +1 -1
- package/dist/cjs/src/storage/StorageDownloader.js +6 -6
- package/dist/cjs/src/storage/StorageDownloader.js.map +1 -1
- package/dist/cjs/src/storage/StorageUtils.js +1 -1
- package/dist/cjs/src/storage/StorageUtils.js.map +1 -1
- package/dist/cjs/src/transaction/MerklePath.js +168 -27
- package/dist/cjs/src/transaction/MerklePath.js.map +1 -1
- package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
- package/dist/esm/src/auth/clients/__tests__/AuthFetch.additional.test.js +825 -0
- package/dist/esm/src/auth/clients/__tests__/AuthFetch.additional.test.js.map +1 -0
- package/dist/esm/src/auth/transports/__tests__/SimplifiedFetchTransport.additional.test.js +619 -0
- package/dist/esm/src/auth/transports/__tests__/SimplifiedFetchTransport.additional.test.js.map +1 -0
- package/dist/esm/src/overlay-tools/HostReputationTracker.js +21 -13
- package/dist/esm/src/overlay-tools/HostReputationTracker.js.map +1 -1
- package/dist/esm/src/primitives/PrivateKey.js +3 -3
- package/dist/esm/src/primitives/PrivateKey.js.map +1 -1
- package/dist/esm/src/script/Spend.js +17 -9
- package/dist/esm/src/script/Spend.js.map +1 -1
- package/dist/esm/src/storage/StorageDownloader.js +6 -6
- package/dist/esm/src/storage/StorageDownloader.js.map +1 -1
- package/dist/esm/src/storage/StorageUtils.js +1 -1
- package/dist/esm/src/storage/StorageUtils.js.map +1 -1
- package/dist/esm/src/transaction/MerklePath.js +168 -27
- package/dist/esm/src/transaction/MerklePath.js.map +1 -1
- package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
- package/dist/types/src/auth/clients/__tests__/AuthFetch.additional.test.d.ts +21 -0
- package/dist/types/src/auth/clients/__tests__/AuthFetch.additional.test.d.ts.map +1 -0
- package/dist/types/src/auth/transports/__tests__/SimplifiedFetchTransport.additional.test.d.ts +2 -0
- package/dist/types/src/auth/transports/__tests__/SimplifiedFetchTransport.additional.test.d.ts.map +1 -0
- package/dist/types/src/overlay-tools/HostReputationTracker.d.ts.map +1 -1
- package/dist/types/src/script/Spend.d.ts.map +1 -1
- package/dist/types/src/transaction/MerklePath.d.ts +27 -0
- package/dist/types/src/transaction/MerklePath.d.ts.map +1 -1
- package/dist/types/tsconfig.types.tsbuildinfo +1 -1
- package/dist/umd/bundle.js +3 -3
- package/dist/umd/bundle.js.map +1 -1
- package/docs/reference/storage.md +1 -1
- package/docs/reference/transaction.md +40 -0
- package/package.json +1 -1
- package/src/auth/clients/__tests__/AuthFetch.additional.test.ts +1131 -0
- package/src/auth/transports/__tests__/SimplifiedFetchTransport.additional.test.ts +770 -0
- package/src/auth/utils/__tests/validateCertificates.test.ts +12 -9
- package/src/compat/__tests/Mnemonic.additional.test.ts +64 -0
- package/src/identity/__tests/IdentityClient.additional.test.ts +767 -0
- package/src/kvstore/__tests/LocalKVStore.additional.test.ts +611 -0
- package/src/kvstore/__tests/LocalKVStore.test.ts +4 -6
- package/src/kvstore/__tests/kvStoreInterpreter.test.ts +327 -0
- package/src/overlay-tools/HostReputationTracker.ts +17 -14
- package/src/overlay-tools/__tests/HostReputationTracker.additional.test.ts +561 -0
- package/src/overlay-tools/__tests/LookupResolver.additional.test.ts +612 -0
- package/src/overlay-tools/__tests/withDoubleSpendRetry.test.ts +278 -0
- package/src/primitives/PrivateKey.ts +3 -3
- package/src/primitives/__tests/BigNumber.additional.test.ts +79 -0
- package/src/primitives/__tests/Curve.additional.test.ts +208 -0
- package/src/primitives/__tests/ECDSA.additional.test.ts +122 -0
- package/src/primitives/__tests/Hash.additional.test.ts +59 -0
- package/src/primitives/__tests/JacobianPoint.test.ts +308 -0
- package/src/primitives/__tests/Point.additional.test.ts +503 -0
- package/src/primitives/__tests/PublicKey.additional.test.ts +383 -0
- package/src/primitives/__tests/Random.additional.test.ts +262 -0
- package/src/primitives/__tests/Signature.test.ts +333 -0
- package/src/primitives/__tests/TransactionSignature.additional.test.ts +241 -0
- package/src/registry/__tests/RegistryClient.additional.test.ts +750 -0
- package/src/remittance/__tests/BasicBRC29.additional.test.ts +657 -0
- package/src/remittance/__tests/RemittanceManager.additional.test.ts +1272 -0
- package/src/script/Spend.ts +19 -11
- package/src/script/__tests/LockingUnlockingScript.test.ts +79 -0
- package/src/script/__tests/Script.additional.test.ts +100 -0
- package/src/script/__tests/ScriptEvaluationError.test.ts +98 -0
- package/src/script/__tests/Spend.additional.test.ts +837 -0
- package/src/script/templates/__tests/RPuzzle.test.ts +134 -0
- package/src/storage/StorageDownloader.ts +6 -6
- package/src/storage/StorageUtils.ts +1 -1
- package/src/transaction/MerklePath.ts +196 -36
- package/src/transaction/__tests/BeefParty.additional.test.ts +22 -0
- package/src/transaction/__tests/Broadcaster.test.ts +159 -0
- package/src/transaction/__tests/MerklePath.bench.test.ts +105 -0
- package/src/transaction/__tests/MerklePath.test.ts +232 -21
- package/src/transaction/__tests/Transaction.additional.test.ts +225 -0
- package/src/transaction/broadcasters/__tests/ARC.additional.test.ts +585 -0
- package/src/transaction/broadcasters/__tests/Teranode.test.ts +349 -0
- package/src/transaction/chaintrackers/__tests/BlockHeadersService.test.ts +253 -0
- package/src/transaction/chaintrackers/__tests/DefaultChainTracker.test.ts +44 -0
- package/src/transaction/chaintrackers/__tests/WhatsOnChain.additional.test.ts +193 -0
- package/src/transaction/fee-models/__tests/SatoshisPerKilobyte.test.ts +262 -0
- package/src/transaction/http/__tests/BinaryFetchClient.test.ts +212 -0
- package/src/transaction/http/__tests/DefaultHttpClient.additional.test.ts +192 -0
- package/src/transaction/http/__tests/DefaultHttpClient.test.ts +71 -0
- package/src/wallet/__tests/ProtoWallet.additional.test.ts +134 -0
- package/src/wallet/__tests/WERR.test.ts +212 -0
- package/src/wallet/__tests/WalletClient.additional.test.ts +699 -0
- package/src/wallet/__tests/WalletClient.substrate.test.ts +759 -0
- package/src/wallet/__tests/WalletError.test.ts +290 -0
- package/src/wallet/__tests/validationHelpers.test.ts +1218 -0
- package/src/wallet/substrates/__tests/HTTPWalletJSON.test.ts +496 -0
- package/src/wallet/substrates/__tests/HTTPWalletWire.test.ts +273 -0
|
@@ -0,0 +1,750 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RegistryClient additional tests.
|
|
3
|
+
*
|
|
4
|
+
* Focuses on branches not covered by the primary test file:
|
|
5
|
+
* - updateDefinition (all paths)
|
|
6
|
+
* - removeDefinition itemIdentifier for unknown definitionType
|
|
7
|
+
* - listOwnRegistryEntries: non-spendable skip, parse errors, empty BEEF
|
|
8
|
+
* - resolve: protocol and certificate parsing, JSON parse error in certificate fields
|
|
9
|
+
* - deserializeWalletProtocol: all validation error paths
|
|
10
|
+
* - getIdentityKey: caching behaviour
|
|
11
|
+
* - getNetwork: caching behaviour
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { RegistryClient, deserializeWalletProtocol } from '../RegistryClient'
|
|
15
|
+
import { WalletInterface } from '../../wallet/index.js'
|
|
16
|
+
import { TopicBroadcaster, LookupResolver } from '../../overlay-tools/index.js'
|
|
17
|
+
import { PushDrop } from '../../script/index.js'
|
|
18
|
+
import {
|
|
19
|
+
DefinitionType,
|
|
20
|
+
DefinitionData,
|
|
21
|
+
ProtocolDefinitionData,
|
|
22
|
+
CertificateDefinitionData,
|
|
23
|
+
RegistryRecord,
|
|
24
|
+
CertificateFieldDescriptor
|
|
25
|
+
} from '../types/index.js'
|
|
26
|
+
|
|
27
|
+
// -------------------- Module-level mocks -------------------- //
|
|
28
|
+
|
|
29
|
+
const mockBroadcast = jest.fn().mockResolvedValue('broadcastSuccess')
|
|
30
|
+
|
|
31
|
+
jest.mock('../../overlay-tools/index.js', () => ({
|
|
32
|
+
TopicBroadcaster: jest.fn().mockImplementation(() => ({
|
|
33
|
+
broadcast: mockBroadcast
|
|
34
|
+
})),
|
|
35
|
+
LookupResolver: jest.fn().mockImplementation(() => ({
|
|
36
|
+
query: jest.fn()
|
|
37
|
+
}))
|
|
38
|
+
}))
|
|
39
|
+
|
|
40
|
+
jest.mock('../../script/index.js', () => {
|
|
41
|
+
const actual = jest.requireActual('../../script/index.js')
|
|
42
|
+
return {
|
|
43
|
+
...actual,
|
|
44
|
+
PushDrop: Object.assign(
|
|
45
|
+
jest.fn().mockImplementation(() => ({
|
|
46
|
+
lock: jest.fn().mockResolvedValue({ toHex: () => 'mockLockHex' }),
|
|
47
|
+
unlock: jest.fn().mockReturnValue({
|
|
48
|
+
sign: jest.fn().mockResolvedValue({ toHex: () => 'mockUnlockHex' })
|
|
49
|
+
})
|
|
50
|
+
})),
|
|
51
|
+
{ decode: jest.fn() }
|
|
52
|
+
),
|
|
53
|
+
LockingScript: {
|
|
54
|
+
fromHex: jest.fn().mockImplementation((hex: string) => ({ hex }))
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
jest.mock('../../transaction/index.js', () => ({
|
|
60
|
+
Transaction: {
|
|
61
|
+
fromAtomicBEEF: jest.fn().mockImplementation(() => ({
|
|
62
|
+
outputs: [
|
|
63
|
+
{ lockingScript: 'mockLS0' },
|
|
64
|
+
{ lockingScript: 'mockLS1' }
|
|
65
|
+
]
|
|
66
|
+
})),
|
|
67
|
+
fromBEEF: jest.fn().mockImplementation(() => ({
|
|
68
|
+
outputs: [
|
|
69
|
+
{ lockingScript: { toHex: () => 'mockLSHex0' } },
|
|
70
|
+
{ lockingScript: { toHex: () => 'mockLSHex1' } },
|
|
71
|
+
{ lockingScript: { toHex: () => 'mockLSHex2' } }
|
|
72
|
+
]
|
|
73
|
+
}))
|
|
74
|
+
}
|
|
75
|
+
}))
|
|
76
|
+
|
|
77
|
+
jest.mock('../../primitives/index.js', () => ({
|
|
78
|
+
Utils: {
|
|
79
|
+
toArray: jest.fn().mockImplementation((str: string) =>
|
|
80
|
+
Array.from(str).map((c) => c.charCodeAt(0))
|
|
81
|
+
),
|
|
82
|
+
toUTF8: jest.fn().mockImplementation((arr: number[] | string) => {
|
|
83
|
+
if (Array.isArray(arr)) return arr.map((n) => String.fromCharCode(n)).join('')
|
|
84
|
+
return arr
|
|
85
|
+
})
|
|
86
|
+
}
|
|
87
|
+
}))
|
|
88
|
+
|
|
89
|
+
// -------------------- Test helpers -------------------- //
|
|
90
|
+
|
|
91
|
+
const TEST_ORIGINATOR = 'test.additional.origin'
|
|
92
|
+
const MOCK_PUB_KEY = 'mockPublicKey'
|
|
93
|
+
|
|
94
|
+
function buildWalletMock (): jest.Mocked<Partial<WalletInterface>> {
|
|
95
|
+
return {
|
|
96
|
+
getPublicKey: jest.fn().mockResolvedValue({ publicKey: MOCK_PUB_KEY }),
|
|
97
|
+
createAction: jest.fn().mockResolvedValue({
|
|
98
|
+
tx: [1, 2, 3],
|
|
99
|
+
signableTransaction: { tx: [1, 2, 3], reference: 'ref123' }
|
|
100
|
+
}),
|
|
101
|
+
signAction: jest.fn().mockResolvedValue({ tx: [7, 8, 9] }),
|
|
102
|
+
listOutputs: jest.fn().mockResolvedValue({ outputs: [], BEEF: [] }),
|
|
103
|
+
getNetwork: jest.fn().mockResolvedValue({ network: 'testnet' })
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function buildClient (wallet: Partial<WalletInterface>): RegistryClient {
|
|
108
|
+
const client = new RegistryClient(wallet as WalletInterface, {}, TEST_ORIGINATOR)
|
|
109
|
+
;(client as any).resolver = {
|
|
110
|
+
query: jest.fn().mockResolvedValue({ type: 'output-list', outputs: [] })
|
|
111
|
+
}
|
|
112
|
+
return client
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const baseRegistryRecord: RegistryRecord = {
|
|
116
|
+
definitionType: 'basket',
|
|
117
|
+
basketID: 'testBasket',
|
|
118
|
+
name: 'Test Basket',
|
|
119
|
+
iconURL: 'https://icon.com',
|
|
120
|
+
description: 'A basket',
|
|
121
|
+
documentationURL: 'https://docs.com',
|
|
122
|
+
txid: 'txid123',
|
|
123
|
+
outputIndex: 0,
|
|
124
|
+
satoshis: 1,
|
|
125
|
+
lockingScript: 'lockhex',
|
|
126
|
+
registryOperator: MOCK_PUB_KEY,
|
|
127
|
+
beef: [1, 2, 3]
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// -------------------- deserializeWalletProtocol -------------------- //
|
|
131
|
+
|
|
132
|
+
describe('deserializeWalletProtocol', () => {
|
|
133
|
+
it('parses a valid protocol string', () => {
|
|
134
|
+
const result = deserializeWalletProtocol(JSON.stringify([1, 'my-protocol']))
|
|
135
|
+
expect(result).toEqual([1, 'my-protocol'])
|
|
136
|
+
})
|
|
137
|
+
|
|
138
|
+
it('throws for non-array input', () => {
|
|
139
|
+
expect(() => deserializeWalletProtocol('"not-array"')).toThrow(
|
|
140
|
+
'Invalid wallet protocol format.'
|
|
141
|
+
)
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
it('throws for array with wrong length', () => {
|
|
145
|
+
expect(() => deserializeWalletProtocol(JSON.stringify([1]))).toThrow(
|
|
146
|
+
'Invalid wallet protocol format.'
|
|
147
|
+
)
|
|
148
|
+
})
|
|
149
|
+
|
|
150
|
+
it('throws for invalid security level', () => {
|
|
151
|
+
expect(() => deserializeWalletProtocol(JSON.stringify([3, 'proto']))).toThrow(
|
|
152
|
+
'Invalid security level.'
|
|
153
|
+
)
|
|
154
|
+
})
|
|
155
|
+
|
|
156
|
+
it('accepts security level 0', () => {
|
|
157
|
+
const result = deserializeWalletProtocol(JSON.stringify([0, 'proto']))
|
|
158
|
+
expect(result[0]).toBe(0)
|
|
159
|
+
})
|
|
160
|
+
|
|
161
|
+
it('accepts security level 2', () => {
|
|
162
|
+
const result = deserializeWalletProtocol(JSON.stringify([2, 'proto']))
|
|
163
|
+
expect(result[0]).toBe(2)
|
|
164
|
+
})
|
|
165
|
+
|
|
166
|
+
it('throws for non-string protocol string', () => {
|
|
167
|
+
expect(() => deserializeWalletProtocol(JSON.stringify([1, 42]))).toThrow(
|
|
168
|
+
'Invalid protocolID'
|
|
169
|
+
)
|
|
170
|
+
})
|
|
171
|
+
|
|
172
|
+
it('throws for completely invalid JSON', () => {
|
|
173
|
+
expect(() => deserializeWalletProtocol('not-json')).toThrow()
|
|
174
|
+
})
|
|
175
|
+
})
|
|
176
|
+
|
|
177
|
+
// -------------------- getIdentityKey caching -------------------- //
|
|
178
|
+
|
|
179
|
+
describe('RegistryClient.getIdentityKey – caching', () => {
|
|
180
|
+
it('calls getPublicKey only once on repeated calls', async () => {
|
|
181
|
+
const wallet = buildWalletMock()
|
|
182
|
+
const client = buildClient(wallet)
|
|
183
|
+
|
|
184
|
+
// Trigger two operations that each call getIdentityKey internally
|
|
185
|
+
await client.registerDefinition({
|
|
186
|
+
definitionType: 'basket',
|
|
187
|
+
basketID: 'b1',
|
|
188
|
+
name: 'Basket 1',
|
|
189
|
+
iconURL: 'https://icon.com',
|
|
190
|
+
description: 'desc',
|
|
191
|
+
documentationURL: 'https://docs.com'
|
|
192
|
+
})
|
|
193
|
+
await client.registerDefinition({
|
|
194
|
+
definitionType: 'basket',
|
|
195
|
+
basketID: 'b2',
|
|
196
|
+
name: 'Basket 2',
|
|
197
|
+
iconURL: 'https://icon.com',
|
|
198
|
+
description: 'desc',
|
|
199
|
+
documentationURL: 'https://docs.com'
|
|
200
|
+
})
|
|
201
|
+
|
|
202
|
+
// getPublicKey should only have been called once (identity key was cached)
|
|
203
|
+
expect(wallet.getPublicKey).toHaveBeenCalledTimes(1)
|
|
204
|
+
})
|
|
205
|
+
})
|
|
206
|
+
|
|
207
|
+
// -------------------- getNetwork caching -------------------- //
|
|
208
|
+
|
|
209
|
+
describe('RegistryClient.getNetwork – caching', () => {
|
|
210
|
+
it('calls wallet.getNetwork only once even across multiple operations', async () => {
|
|
211
|
+
const wallet = buildWalletMock()
|
|
212
|
+
const client = buildClient(wallet)
|
|
213
|
+
|
|
214
|
+
await client.registerDefinition({
|
|
215
|
+
definitionType: 'basket',
|
|
216
|
+
basketID: 'b1',
|
|
217
|
+
name: 'Basket 1',
|
|
218
|
+
iconURL: 'https://icon.com',
|
|
219
|
+
description: 'desc',
|
|
220
|
+
documentationURL: 'https://docs.com'
|
|
221
|
+
})
|
|
222
|
+
await client.registerDefinition({
|
|
223
|
+
definitionType: 'basket',
|
|
224
|
+
basketID: 'b2',
|
|
225
|
+
name: 'Basket 2',
|
|
226
|
+
iconURL: 'https://icon.com',
|
|
227
|
+
description: 'desc',
|
|
228
|
+
documentationURL: 'https://docs.com'
|
|
229
|
+
})
|
|
230
|
+
|
|
231
|
+
expect(wallet.getNetwork).toHaveBeenCalledTimes(1)
|
|
232
|
+
})
|
|
233
|
+
})
|
|
234
|
+
|
|
235
|
+
// -------------------- updateDefinition -------------------- //
|
|
236
|
+
|
|
237
|
+
describe('RegistryClient.updateDefinition', () => {
|
|
238
|
+
let wallet: jest.Mocked<Partial<WalletInterface>>
|
|
239
|
+
let client: RegistryClient
|
|
240
|
+
|
|
241
|
+
beforeEach(() => {
|
|
242
|
+
wallet = buildWalletMock()
|
|
243
|
+
client = buildClient(wallet)
|
|
244
|
+
jest.clearAllMocks()
|
|
245
|
+
mockBroadcast.mockClear()
|
|
246
|
+
mockBroadcast.mockResolvedValue('broadcastSuccess')
|
|
247
|
+
})
|
|
248
|
+
|
|
249
|
+
it('throws if txid is missing from the record', async () => {
|
|
250
|
+
const record = { ...baseRegistryRecord, txid: undefined }
|
|
251
|
+
const updated: DefinitionData = { ...baseRegistryRecord }
|
|
252
|
+
await expect(client.updateDefinition(record as any, updated)).rejects.toThrow(
|
|
253
|
+
'Invalid registry record. Missing txid, outputIndex, or lockingScript.'
|
|
254
|
+
)
|
|
255
|
+
})
|
|
256
|
+
|
|
257
|
+
it('throws if outputIndex is missing from the record', async () => {
|
|
258
|
+
const record = { ...baseRegistryRecord, outputIndex: undefined }
|
|
259
|
+
const updated: DefinitionData = { ...baseRegistryRecord }
|
|
260
|
+
await expect(client.updateDefinition(record as any, updated)).rejects.toThrow(
|
|
261
|
+
'Invalid registry record. Missing txid, outputIndex, or lockingScript.'
|
|
262
|
+
)
|
|
263
|
+
})
|
|
264
|
+
|
|
265
|
+
it('throws if lockingScript is missing from the record', async () => {
|
|
266
|
+
const record = { ...baseRegistryRecord, lockingScript: undefined }
|
|
267
|
+
const updated: DefinitionData = { ...baseRegistryRecord }
|
|
268
|
+
await expect(client.updateDefinition(record as any, updated)).rejects.toThrow(
|
|
269
|
+
'Invalid registry record. Missing txid, outputIndex, or lockingScript.'
|
|
270
|
+
)
|
|
271
|
+
})
|
|
272
|
+
|
|
273
|
+
it('throws if definitionType does not match updatedData', async () => {
|
|
274
|
+
const record = { ...baseRegistryRecord }
|
|
275
|
+
const updated: DefinitionData = {
|
|
276
|
+
definitionType: 'protocol',
|
|
277
|
+
protocolID: [1, 'p'],
|
|
278
|
+
name: 'P',
|
|
279
|
+
iconURL: 'u',
|
|
280
|
+
description: 'd',
|
|
281
|
+
documentationURL: 'doc'
|
|
282
|
+
}
|
|
283
|
+
await expect(client.updateDefinition(record, updated)).rejects.toThrow(
|
|
284
|
+
'Cannot change definition type from basket to protocol'
|
|
285
|
+
)
|
|
286
|
+
})
|
|
287
|
+
|
|
288
|
+
it('throws if the registry record does not belong to the current wallet', async () => {
|
|
289
|
+
const record = { ...baseRegistryRecord, registryOperator: 'differentKey' }
|
|
290
|
+
const updated: DefinitionData = { ...baseRegistryRecord }
|
|
291
|
+
await expect(client.updateDefinition(record, updated)).rejects.toThrow(
|
|
292
|
+
'This registry token does not belong to the current wallet.'
|
|
293
|
+
)
|
|
294
|
+
})
|
|
295
|
+
|
|
296
|
+
it('throws if createAction returns no signableTransaction', async () => {
|
|
297
|
+
;(wallet.createAction as jest.Mock).mockResolvedValueOnce({
|
|
298
|
+
tx: [1, 2, 3],
|
|
299
|
+
signableTransaction: undefined
|
|
300
|
+
})
|
|
301
|
+
const record = { ...baseRegistryRecord }
|
|
302
|
+
const updated: DefinitionData = { ...baseRegistryRecord }
|
|
303
|
+
await expect(client.updateDefinition(record, updated)).rejects.toThrow(
|
|
304
|
+
'Failed to create signable transaction.'
|
|
305
|
+
)
|
|
306
|
+
})
|
|
307
|
+
|
|
308
|
+
it('throws if signAction returns no tx', async () => {
|
|
309
|
+
;(wallet.signAction as jest.Mock).mockResolvedValueOnce({ tx: undefined })
|
|
310
|
+
const record = { ...baseRegistryRecord }
|
|
311
|
+
const updated: DefinitionData = { ...baseRegistryRecord }
|
|
312
|
+
await expect(client.updateDefinition(record, updated)).rejects.toThrow(
|
|
313
|
+
'Failed to finalize the transaction signature.'
|
|
314
|
+
)
|
|
315
|
+
})
|
|
316
|
+
|
|
317
|
+
it('successfully updates a basket definition and broadcasts', async () => {
|
|
318
|
+
const record = { ...baseRegistryRecord }
|
|
319
|
+
const updated: DefinitionData = {
|
|
320
|
+
definitionType: 'basket',
|
|
321
|
+
basketID: 'updatedBasket',
|
|
322
|
+
name: 'Updated Basket',
|
|
323
|
+
iconURL: 'https://newicon.com',
|
|
324
|
+
description: 'Updated description',
|
|
325
|
+
documentationURL: 'https://newdocs.com'
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
const result = await client.updateDefinition(record, updated)
|
|
329
|
+
|
|
330
|
+
expect(result).toBe('broadcastSuccess')
|
|
331
|
+
expect(wallet.createAction).toHaveBeenCalledWith(
|
|
332
|
+
expect.objectContaining({
|
|
333
|
+
description: 'Update basket item: testBasket',
|
|
334
|
+
inputs: [expect.objectContaining({ outpoint: 'txid123.0' })],
|
|
335
|
+
outputs: [expect.objectContaining({ basket: 'basketmap' })]
|
|
336
|
+
}),
|
|
337
|
+
TEST_ORIGINATOR
|
|
338
|
+
)
|
|
339
|
+
expect(wallet.signAction).toHaveBeenCalledWith(
|
|
340
|
+
expect.objectContaining({ reference: 'ref123' }),
|
|
341
|
+
TEST_ORIGINATOR
|
|
342
|
+
)
|
|
343
|
+
expect(TopicBroadcaster).toHaveBeenCalledWith(
|
|
344
|
+
['tm_basketmap'],
|
|
345
|
+
expect.objectContaining({ networkPreset: 'testnet' })
|
|
346
|
+
)
|
|
347
|
+
})
|
|
348
|
+
|
|
349
|
+
it('successfully updates a protocol definition and uses protocol item identifier', async () => {
|
|
350
|
+
const protocolRecord: RegistryRecord = {
|
|
351
|
+
definitionType: 'protocol',
|
|
352
|
+
protocolID: [1, 'oldProto'],
|
|
353
|
+
name: 'Old Protocol',
|
|
354
|
+
iconURL: 'https://icon.com',
|
|
355
|
+
description: 'desc',
|
|
356
|
+
documentationURL: 'https://docs.com',
|
|
357
|
+
txid: 'protTxid',
|
|
358
|
+
outputIndex: 0,
|
|
359
|
+
satoshis: 1,
|
|
360
|
+
lockingScript: 'lockhex',
|
|
361
|
+
registryOperator: MOCK_PUB_KEY,
|
|
362
|
+
beef: [1, 2, 3]
|
|
363
|
+
}
|
|
364
|
+
const updated: ProtocolDefinitionData = {
|
|
365
|
+
definitionType: 'protocol',
|
|
366
|
+
protocolID: [1, 'newProto'],
|
|
367
|
+
name: 'New Protocol',
|
|
368
|
+
iconURL: 'https://icon.com',
|
|
369
|
+
description: 'Updated desc',
|
|
370
|
+
documentationURL: 'https://newdocs.com'
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
const result = await client.updateDefinition(protocolRecord, updated)
|
|
374
|
+
|
|
375
|
+
expect(result).toBe('broadcastSuccess')
|
|
376
|
+
expect(wallet.createAction).toHaveBeenCalledWith(
|
|
377
|
+
expect.objectContaining({
|
|
378
|
+
description: 'Update protocol item: Old Protocol'
|
|
379
|
+
}),
|
|
380
|
+
TEST_ORIGINATOR
|
|
381
|
+
)
|
|
382
|
+
expect(TopicBroadcaster).toHaveBeenCalledWith(['tm_protomap'], expect.anything())
|
|
383
|
+
})
|
|
384
|
+
|
|
385
|
+
it('uses certificate type when name is undefined in the item identifier', async () => {
|
|
386
|
+
const certRecord: RegistryRecord = {
|
|
387
|
+
definitionType: 'certificate',
|
|
388
|
+
type: 'certType123',
|
|
389
|
+
name: undefined as any,
|
|
390
|
+
iconURL: 'https://icon.com',
|
|
391
|
+
description: 'desc',
|
|
392
|
+
documentationURL: 'https://docs.com',
|
|
393
|
+
fields: {},
|
|
394
|
+
txid: 'certTxid',
|
|
395
|
+
outputIndex: 0,
|
|
396
|
+
satoshis: 1,
|
|
397
|
+
lockingScript: 'lockhex',
|
|
398
|
+
registryOperator: MOCK_PUB_KEY,
|
|
399
|
+
beef: [1, 2, 3]
|
|
400
|
+
}
|
|
401
|
+
const updated: CertificateDefinitionData = {
|
|
402
|
+
definitionType: 'certificate',
|
|
403
|
+
type: 'certType123',
|
|
404
|
+
name: 'New Cert Name',
|
|
405
|
+
iconURL: 'https://icon.com',
|
|
406
|
+
description: 'Updated',
|
|
407
|
+
documentationURL: 'https://docs.com',
|
|
408
|
+
fields: {}
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
const result = await client.updateDefinition(certRecord, updated)
|
|
412
|
+
|
|
413
|
+
expect(result).toBe('broadcastSuccess')
|
|
414
|
+
expect(wallet.createAction).toHaveBeenCalledWith(
|
|
415
|
+
expect.objectContaining({
|
|
416
|
+
description: 'Update certificate item: certType123'
|
|
417
|
+
}),
|
|
418
|
+
TEST_ORIGINATOR
|
|
419
|
+
)
|
|
420
|
+
})
|
|
421
|
+
|
|
422
|
+
it('uses certificate name when defined for the item identifier', async () => {
|
|
423
|
+
const certRecord: RegistryRecord = {
|
|
424
|
+
definitionType: 'certificate',
|
|
425
|
+
type: 'certType456',
|
|
426
|
+
name: 'Named Cert',
|
|
427
|
+
iconURL: 'https://icon.com',
|
|
428
|
+
description: 'desc',
|
|
429
|
+
documentationURL: 'https://docs.com',
|
|
430
|
+
fields: {},
|
|
431
|
+
txid: 'certTxid2',
|
|
432
|
+
outputIndex: 0,
|
|
433
|
+
satoshis: 1,
|
|
434
|
+
lockingScript: 'lockhex',
|
|
435
|
+
registryOperator: MOCK_PUB_KEY,
|
|
436
|
+
beef: [1, 2, 3]
|
|
437
|
+
}
|
|
438
|
+
const updated: CertificateDefinitionData = {
|
|
439
|
+
definitionType: 'certificate',
|
|
440
|
+
type: 'certType456',
|
|
441
|
+
name: 'Updated Cert',
|
|
442
|
+
iconURL: 'https://icon.com',
|
|
443
|
+
description: 'desc',
|
|
444
|
+
documentationURL: 'https://docs.com',
|
|
445
|
+
fields: {}
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
await client.updateDefinition(certRecord, updated)
|
|
449
|
+
|
|
450
|
+
expect(wallet.createAction).toHaveBeenCalledWith(
|
|
451
|
+
expect.objectContaining({
|
|
452
|
+
description: 'Update certificate item: Named Cert'
|
|
453
|
+
}),
|
|
454
|
+
TEST_ORIGINATOR
|
|
455
|
+
)
|
|
456
|
+
})
|
|
457
|
+
|
|
458
|
+
it('uses acceptDelayedBroadcast: true when configured', async () => {
|
|
459
|
+
const delayedClient = new RegistryClient(
|
|
460
|
+
wallet as WalletInterface,
|
|
461
|
+
{ acceptDelayedBroadcast: true },
|
|
462
|
+
TEST_ORIGINATOR
|
|
463
|
+
)
|
|
464
|
+
;(delayedClient as any).resolver = {
|
|
465
|
+
query: jest.fn().mockResolvedValue({ type: 'output-list', outputs: [] })
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
const record = { ...baseRegistryRecord }
|
|
469
|
+
const updated: DefinitionData = { ...baseRegistryRecord }
|
|
470
|
+
await delayedClient.updateDefinition(record, updated)
|
|
471
|
+
|
|
472
|
+
expect(wallet.createAction).toHaveBeenCalledWith(
|
|
473
|
+
expect.objectContaining({
|
|
474
|
+
options: expect.objectContaining({ acceptDelayedBroadcast: true })
|
|
475
|
+
}),
|
|
476
|
+
TEST_ORIGINATOR
|
|
477
|
+
)
|
|
478
|
+
expect(wallet.signAction).toHaveBeenCalledWith(
|
|
479
|
+
expect.objectContaining({
|
|
480
|
+
options: expect.objectContaining({ acceptDelayedBroadcast: true })
|
|
481
|
+
}),
|
|
482
|
+
TEST_ORIGINATOR
|
|
483
|
+
)
|
|
484
|
+
})
|
|
485
|
+
|
|
486
|
+
it('propagates broadcast errors', async () => {
|
|
487
|
+
mockBroadcast.mockRejectedValueOnce(new Error('Update broadcast failed!'))
|
|
488
|
+
const record = { ...baseRegistryRecord }
|
|
489
|
+
const updated: DefinitionData = { ...baseRegistryRecord }
|
|
490
|
+
await expect(client.updateDefinition(record, updated)).rejects.toThrow('Update broadcast failed!')
|
|
491
|
+
})
|
|
492
|
+
})
|
|
493
|
+
|
|
494
|
+
// -------------------- removeDefinition: unknown identifier -------------------- //
|
|
495
|
+
|
|
496
|
+
describe('RegistryClient.removeDefinition – itemIdentifier edge cases', () => {
|
|
497
|
+
let wallet: jest.Mocked<Partial<WalletInterface>>
|
|
498
|
+
let client: RegistryClient
|
|
499
|
+
|
|
500
|
+
beforeEach(() => {
|
|
501
|
+
wallet = buildWalletMock()
|
|
502
|
+
client = buildClient(wallet)
|
|
503
|
+
jest.clearAllMocks()
|
|
504
|
+
mockBroadcast.mockClear()
|
|
505
|
+
mockBroadcast.mockResolvedValue('broadcastSuccess')
|
|
506
|
+
})
|
|
507
|
+
|
|
508
|
+
it('uses basketID as itemIdentifier for basket records', async () => {
|
|
509
|
+
const record = { ...baseRegistryRecord }
|
|
510
|
+
await client.removeDefinition(record)
|
|
511
|
+
expect(wallet.createAction).toHaveBeenCalledWith(
|
|
512
|
+
expect.objectContaining({
|
|
513
|
+
description: 'Remove basket item: testBasket'
|
|
514
|
+
}),
|
|
515
|
+
TEST_ORIGINATOR
|
|
516
|
+
)
|
|
517
|
+
})
|
|
518
|
+
})
|
|
519
|
+
|
|
520
|
+
// -------------------- listOwnRegistryEntries edge cases -------------------- //
|
|
521
|
+
|
|
522
|
+
describe('RegistryClient.listOwnRegistryEntries – edge cases', () => {
|
|
523
|
+
let wallet: jest.Mocked<Partial<WalletInterface>>
|
|
524
|
+
let client: RegistryClient
|
|
525
|
+
|
|
526
|
+
beforeEach(() => {
|
|
527
|
+
wallet = buildWalletMock()
|
|
528
|
+
client = buildClient(wallet)
|
|
529
|
+
jest.clearAllMocks()
|
|
530
|
+
})
|
|
531
|
+
|
|
532
|
+
it('returns empty array when no outputs are returned', async () => {
|
|
533
|
+
;(wallet.listOutputs as jest.Mock).mockResolvedValue({ outputs: [], BEEF: [] })
|
|
534
|
+
const results = await client.listOwnRegistryEntries('basket')
|
|
535
|
+
expect(results).toEqual([])
|
|
536
|
+
})
|
|
537
|
+
|
|
538
|
+
it('skips non-spendable outputs', async () => {
|
|
539
|
+
;(wallet.listOutputs as jest.Mock).mockResolvedValue({
|
|
540
|
+
outputs: [
|
|
541
|
+
{ outpoint: 'tx1.0', satoshis: 1, spendable: false },
|
|
542
|
+
{ outpoint: 'tx2.0', satoshis: 1, spendable: false }
|
|
543
|
+
],
|
|
544
|
+
BEEF: [1, 2, 3]
|
|
545
|
+
})
|
|
546
|
+
const results = await client.listOwnRegistryEntries('basket')
|
|
547
|
+
expect(results).toEqual([])
|
|
548
|
+
expect(PushDrop.decode).not.toHaveBeenCalled()
|
|
549
|
+
})
|
|
550
|
+
|
|
551
|
+
it('skips spendable outputs that fail to parse (catches error silently)', async () => {
|
|
552
|
+
;(wallet.listOutputs as jest.Mock).mockResolvedValue({
|
|
553
|
+
outputs: [{ outpoint: 'badtx.0', satoshis: 1, spendable: true }],
|
|
554
|
+
BEEF: [1, 2, 3]
|
|
555
|
+
})
|
|
556
|
+
// Make decode throw to simulate parse failure
|
|
557
|
+
;(PushDrop.decode as jest.Mock).mockImplementationOnce(() => {
|
|
558
|
+
throw new Error('Invalid script')
|
|
559
|
+
})
|
|
560
|
+
const results = await client.listOwnRegistryEntries('basket')
|
|
561
|
+
expect(results).toEqual([])
|
|
562
|
+
})
|
|
563
|
+
|
|
564
|
+
it('returns records for all valid spendable outputs', async () => {
|
|
565
|
+
;(wallet.listOutputs as jest.Mock).mockResolvedValue({
|
|
566
|
+
outputs: [
|
|
567
|
+
{ outpoint: 'tx1.0', satoshis: 1, spendable: true },
|
|
568
|
+
{ outpoint: 'tx2.0', satoshis: 2, spendable: true }
|
|
569
|
+
],
|
|
570
|
+
BEEF: [0, 1, 2, 3]
|
|
571
|
+
})
|
|
572
|
+
// Basket has 7 fields
|
|
573
|
+
;(PushDrop.decode as jest.Mock).mockReturnValue({
|
|
574
|
+
fields: [
|
|
575
|
+
[98], // basketID: 'b'
|
|
576
|
+
[97], // name: 'a'
|
|
577
|
+
[115], // iconURL: 's'
|
|
578
|
+
[107], // description: 'k'
|
|
579
|
+
[101], // documentationURL: 'e'
|
|
580
|
+
[116], // operator: 't'
|
|
581
|
+
[111] // signature field
|
|
582
|
+
]
|
|
583
|
+
})
|
|
584
|
+
|
|
585
|
+
const results = await client.listOwnRegistryEntries('basket')
|
|
586
|
+
expect(results).toHaveLength(2)
|
|
587
|
+
expect(results[0].txid).toBe('tx1')
|
|
588
|
+
expect(results[1].txid).toBe('tx2')
|
|
589
|
+
})
|
|
590
|
+
|
|
591
|
+
it('uses protomap basket for protocol definition type', async () => {
|
|
592
|
+
;(wallet.listOutputs as jest.Mock).mockResolvedValue({ outputs: [], BEEF: [] })
|
|
593
|
+
await client.listOwnRegistryEntries('protocol')
|
|
594
|
+
expect(wallet.listOutputs).toHaveBeenCalledWith({
|
|
595
|
+
basket: 'protomap',
|
|
596
|
+
include: 'entire transactions'
|
|
597
|
+
})
|
|
598
|
+
})
|
|
599
|
+
|
|
600
|
+
it('uses certmap basket for certificate definition type', async () => {
|
|
601
|
+
;(wallet.listOutputs as jest.Mock).mockResolvedValue({ outputs: [], BEEF: [] })
|
|
602
|
+
await client.listOwnRegistryEntries('certificate')
|
|
603
|
+
expect(wallet.listOutputs).toHaveBeenCalledWith({
|
|
604
|
+
basket: 'certmap',
|
|
605
|
+
include: 'entire transactions'
|
|
606
|
+
})
|
|
607
|
+
})
|
|
608
|
+
})
|
|
609
|
+
|
|
610
|
+
// -------------------- resolve: protocol and certificate parsing -------------------- //
|
|
611
|
+
|
|
612
|
+
describe('RegistryClient.resolve – protocol and certificate parsing', () => {
|
|
613
|
+
let wallet: jest.Mocked<Partial<WalletInterface>>
|
|
614
|
+
let client: RegistryClient
|
|
615
|
+
|
|
616
|
+
beforeEach(() => {
|
|
617
|
+
wallet = buildWalletMock()
|
|
618
|
+
client = buildClient(wallet)
|
|
619
|
+
jest.clearAllMocks()
|
|
620
|
+
})
|
|
621
|
+
|
|
622
|
+
it('parses a protocol output from the resolver', async () => {
|
|
623
|
+
;(client as any).resolver.query = jest.fn().mockResolvedValue({
|
|
624
|
+
type: 'output-list',
|
|
625
|
+
outputs: [{ beef: [1, 2, 3], outputIndex: 0 }]
|
|
626
|
+
})
|
|
627
|
+
|
|
628
|
+
// protocol has 7 fields: protocolID, name, iconURL, description, docURL, operator, sig
|
|
629
|
+
;(PushDrop.decode as jest.Mock).mockReturnValueOnce({
|
|
630
|
+
fields: [
|
|
631
|
+
Array.from('[1,"proto"]').map((c) => c.charCodeAt(0)), // protocolID JSON
|
|
632
|
+
[110, 97, 109, 101], // 'name'
|
|
633
|
+
[105, 99, 111, 110], // 'icon'
|
|
634
|
+
[100, 101, 115, 99], // 'desc'
|
|
635
|
+
[100, 111, 99], // 'doc'
|
|
636
|
+
[111, 112], // 'op' - operator
|
|
637
|
+
[115, 105, 103] // signature
|
|
638
|
+
]
|
|
639
|
+
})
|
|
640
|
+
|
|
641
|
+
const result = await client.resolve('protocol', { name: 'proto' })
|
|
642
|
+
expect(result).toHaveLength(1)
|
|
643
|
+
expect(result[0].definitionType).toBe('protocol')
|
|
644
|
+
})
|
|
645
|
+
|
|
646
|
+
it('parses a certificate output from the resolver', async () => {
|
|
647
|
+
;(client as any).resolver.query = jest.fn().mockResolvedValue({
|
|
648
|
+
type: 'output-list',
|
|
649
|
+
outputs: [{ beef: [1, 2, 3], outputIndex: 0 }]
|
|
650
|
+
})
|
|
651
|
+
|
|
652
|
+
// certificate has 8 fields: type, name, iconURL, desc, docURL, fieldsJSON, operator, sig
|
|
653
|
+
const fieldsJSON = JSON.stringify({ field1: { friendlyName: 'Field One', description: 'd', type: 'text', fieldIcon: 'i' } })
|
|
654
|
+
;(PushDrop.decode as jest.Mock).mockReturnValueOnce({
|
|
655
|
+
fields: [
|
|
656
|
+
[116, 121, 112, 101], // 'type'
|
|
657
|
+
[110, 97, 109, 101], // 'name'
|
|
658
|
+
[105, 99, 111, 110], // 'icon'
|
|
659
|
+
[100, 101, 115, 99], // 'desc'
|
|
660
|
+
[100, 111, 99], // 'doc'
|
|
661
|
+
Array.from(fieldsJSON).map((c) => c.charCodeAt(0)), // fieldsJSON
|
|
662
|
+
[111, 112], // 'op' - operator
|
|
663
|
+
[115, 105, 103] // signature
|
|
664
|
+
]
|
|
665
|
+
})
|
|
666
|
+
|
|
667
|
+
const result = await client.resolve('certificate', { type: 'type' })
|
|
668
|
+
expect(result).toHaveLength(1)
|
|
669
|
+
expect(result[0].definitionType).toBe('certificate')
|
|
670
|
+
})
|
|
671
|
+
|
|
672
|
+
it('uses empty fields object when certificate fieldsJSON is invalid JSON', async () => {
|
|
673
|
+
;(client as any).resolver.query = jest.fn().mockResolvedValue({
|
|
674
|
+
type: 'output-list',
|
|
675
|
+
outputs: [{ beef: [1, 2, 3], outputIndex: 0 }]
|
|
676
|
+
})
|
|
677
|
+
|
|
678
|
+
// Invalid JSON for fieldsJSON
|
|
679
|
+
;(PushDrop.decode as jest.Mock).mockReturnValueOnce({
|
|
680
|
+
fields: [
|
|
681
|
+
[116, 121, 112, 101], // 'type'
|
|
682
|
+
[110, 97, 109, 101], // 'name'
|
|
683
|
+
[105, 99, 111, 110], // 'icon'
|
|
684
|
+
[100, 101, 115, 99], // 'desc'
|
|
685
|
+
[100, 111, 99], // 'doc'
|
|
686
|
+
[123, 105, 110, 118], // '{inv' - invalid JSON
|
|
687
|
+
[111, 112], // operator
|
|
688
|
+
[115, 105, 103] // signature
|
|
689
|
+
]
|
|
690
|
+
})
|
|
691
|
+
|
|
692
|
+
const result = await client.resolve('certificate', { type: 'type' })
|
|
693
|
+
expect(result).toHaveLength(1)
|
|
694
|
+
expect((result[0] as CertificateDefinitionData).fields).toEqual({})
|
|
695
|
+
})
|
|
696
|
+
|
|
697
|
+
it('skips outputs with wrong field count for basket (not 7)', async () => {
|
|
698
|
+
;(client as any).resolver.query = jest.fn().mockResolvedValue({
|
|
699
|
+
type: 'output-list',
|
|
700
|
+
outputs: [{ beef: [1, 2, 3], outputIndex: 0 }]
|
|
701
|
+
})
|
|
702
|
+
|
|
703
|
+
// Return only 5 fields — should fail the basket field count check and be skipped
|
|
704
|
+
;(PushDrop.decode as jest.Mock).mockReturnValueOnce({
|
|
705
|
+
fields: [[1], [2], [3], [4], [5]]
|
|
706
|
+
})
|
|
707
|
+
|
|
708
|
+
const result = await client.resolve('basket', {})
|
|
709
|
+
expect(result).toEqual([])
|
|
710
|
+
})
|
|
711
|
+
|
|
712
|
+
it('skips outputs with wrong field count for certificate (not 8)', async () => {
|
|
713
|
+
;(client as any).resolver.query = jest.fn().mockResolvedValue({
|
|
714
|
+
type: 'output-list',
|
|
715
|
+
outputs: [{ beef: [1, 2, 3], outputIndex: 0 }]
|
|
716
|
+
})
|
|
717
|
+
|
|
718
|
+
// Return only 5 fields — should fail the certificate field count check
|
|
719
|
+
;(PushDrop.decode as jest.Mock).mockReturnValueOnce({
|
|
720
|
+
fields: [[1], [2], [3], [4], [5]]
|
|
721
|
+
})
|
|
722
|
+
|
|
723
|
+
const result = await client.resolve('certificate', {})
|
|
724
|
+
expect(result).toEqual([])
|
|
725
|
+
})
|
|
726
|
+
})
|
|
727
|
+
|
|
728
|
+
// -------------------- registerDefinition: network preset used -------------------- //
|
|
729
|
+
|
|
730
|
+
describe('RegistryClient.registerDefinition – network preset', () => {
|
|
731
|
+
it('passes testnet to TopicBroadcaster when wallet returns testnet', async () => {
|
|
732
|
+
const wallet = buildWalletMock()
|
|
733
|
+
;(wallet.getNetwork as jest.Mock).mockResolvedValue({ network: 'testnet' })
|
|
734
|
+
const client = buildClient(wallet)
|
|
735
|
+
|
|
736
|
+
await client.registerDefinition({
|
|
737
|
+
definitionType: 'basket',
|
|
738
|
+
basketID: 'b1',
|
|
739
|
+
name: 'Basket',
|
|
740
|
+
iconURL: 'u',
|
|
741
|
+
description: 'd',
|
|
742
|
+
documentationURL: 'doc'
|
|
743
|
+
})
|
|
744
|
+
|
|
745
|
+
expect(TopicBroadcaster).toHaveBeenCalledWith(
|
|
746
|
+
expect.anything(),
|
|
747
|
+
expect.objectContaining({ networkPreset: 'testnet' })
|
|
748
|
+
)
|
|
749
|
+
})
|
|
750
|
+
})
|