feat(BCH): Added BCH REST API for proxying to IPFS wallet service

This commit is contained in:
Chris Troutner
2021-11-26 15:28:41 -08:00
parent 52ca71ec16
commit 14150f81e9
10 changed files with 812 additions and 9 deletions
+68 -1
View File
@@ -4,24 +4,33 @@
const assert = require('chai').assert
const sinon = require('sinon')
const cloneDeep = require('lodash.clonedeep')
const IPFSCoordAdapter = require('../../../src/adapters/ipfs/ipfs-coord')
const IPFSMock = require('../mocks/ipfs-mock')
const IPFSCoordMock = require('../mocks/ipfs-coord-mock')
const EventEmitter = require('events')
const mockDataLib = require('../mocks/adapters/ipfs-coord-mocks')
describe('#IPFS', () => {
let uut
let sandbox
let mockData
beforeEach(() => {
const ipfs = IPFSMock.create()
uut = new IPFSCoordAdapter({ ipfs, eventEmitter: new EventEmitter() })
sandbox = sinon.createSandbox()
mockData = cloneDeep(mockDataLib)
})
afterEach(() => sandbox.restore())
afterEach(() => {
sandbox.restore()
clearInterval(uut.pollServiceInterval)
})
describe('#constructor', () => {
it('should throw an error if ipfs instance is not included', () => {
@@ -36,6 +45,20 @@ describe('#IPFS', () => {
)
}
})
it('should throw an error if EventEmitter instance is not included', () => {
try {
const ipfs = IPFSMock.create()
uut = new IPFSCoordAdapter({ ipfs })
assert.fail('Unexpected code path')
} catch (err) {
assert.include(
err.message,
'An instance of an EventEmitter must be passed when instantiating the ipfs-coord adapter.'
)
}
})
})
describe('#start', () => {
@@ -101,4 +124,48 @@ describe('#IPFS', () => {
}
})
})
describe('#pollForServices', () => {
it('should find and select the wallet service', () => {
uut.ipfsCoord = {
thisNode: {
peerList: mockData.peers,
peerData: mockData.peerData
}
}
uut.pollForServices()
// It should fine the service in the mocked data.
assert.equal(
uut.state.selectedServiceProvider,
'QmWkjYRRTaxVEuGK8ip2X3trVyJShFs6U9g1h9x6fK5mZ2'
)
})
it('should catch and report errors', () => {
uut.pollForServices()
assert.isOk(true, 'Not throwing an error is a success.')
})
})
describe('#peerInputHandler', () => {
it('should emit an event trigger', () => {
const data = 'some data'
uut.peerInputHandler(data)
assert.isOk(true, 'Not throwing an error is a success')
})
it('should catch and report errors', () => {
// Force an error
sandbox.stub(uut.eventEmitter, 'emit').throws(new Error('test error'))
uut.peerInputHandler()
assert.isOk(true, 'Not throwing an error is a success.')
})
})
})
@@ -0,0 +1,143 @@
/*
Unit tests for the REST API handler for the /bch endpoints.
*/
// Public npm libraries
const assert = require('chai').assert
const sinon = require('sinon')
// Local support libraries
const adapters = require('../../../mocks/adapters')
const UseCasesMock = require('../../../mocks/use-cases')
const BchController = require('../../../../../src/controllers/rest-api/bch/controller')
let uut
let sandbox
let ctx
const mockContext = require('../../../../unit/mocks/ctx-mock').context
describe('#BCH-REST-Controller', () => {
// const testUser = {}
beforeEach(() => {
const useCases = new UseCasesMock()
uut = new BchController({ adapters, useCases })
sandbox = sinon.createSandbox()
// Mock the context object.
ctx = mockContext()
})
afterEach(() => sandbox.restore())
describe('#constructor', () => {
it('should throw an error if adapters are not passed in', () => {
try {
uut = new BchController()
assert.fail('Unexpected code path')
} catch (err) {
assert.include(
err.message,
'Instance of Adapters library required when instantiating /bch REST Controller.'
)
}
})
it('should throw an error if useCases are not passed in', () => {
try {
uut = new BchController({ adapters })
assert.fail('Unexpected code path')
} catch (err) {
assert.include(
err.message,
'Instance of Use Cases library required when instantiating /bch REST Controller.'
)
}
})
})
describe('#handleError', () => {
it('should still throw error if there is no message', () => {
try {
const err = {
status: 404
}
uut.handleError(ctx, err)
} catch (err) {
assert.include(err.message, 'Not Found')
}
})
})
describe('#getStatus', () => {
it('should return 422 status on arbitrary biz logic error', async () => {
try {
// Force an error
sandbox
.stub(uut.useCases.bch, 'getStatus')
.rejects(new Error('test error'))
await uut.getStatus(ctx)
assert.fail('Unexpected result')
} catch (err) {
console.log('err: ', err)
assert.equal(err.status, 422)
assert.include(err.message, 'test error')
}
})
it('should return 200 status on success', async () => {
sandbox.stub(uut.useCases.bch, 'getStatus').resolves('bch')
await uut.getStatus(ctx)
// Assert the expected HTTP response
assert.equal(ctx.status, 200)
// Assert that expected properties exist in the returned data.
assert.equal(ctx.response.body.status, 'bch')
})
})
describe('#balance', () => {
it('should return 422 status on arbitrary biz logic error', async () => {
try {
// Force an error
sandbox
.stub(uut.useCases.bch, 'getBalances')
.rejects(new Error('test error'))
ctx.request.body = {
addresses: 'blah'
}
await uut.balance(ctx)
assert.fail('Unexpected result')
} catch (err) {
console.log('err: ', err)
assert.equal(err.status, 422)
assert.include(err.message, 'test error')
}
})
it('should return 200 status on success', async () => {
sandbox.stub(uut.useCases.bch, 'getBalances').resolves({ status: 200 })
ctx.request.body = {
addresses: 'blah'
}
await uut.getStatus(ctx)
// Assert the expected HTTP response
assert.equal(ctx.status, 200)
})
})
})
@@ -0,0 +1,78 @@
/*
Unit tests for the REST API handler for the /users endpoints.
*/
// Public npm libraries
const assert = require('chai').assert
const sinon = require('sinon')
// Local support libraries
const adapters = require('../../../mocks/adapters')
const UseCasesMock = require('../../../mocks/use-cases')
// const app = require('../../../mocks/app-mock')
const BchRouter = require('../../../../../src/controllers/rest-api/bch')
let uut
let sandbox
// let ctx
// const mockContext = require('../../../../unit/mocks/ctx-mock').context
describe('#Users-REST-Router', () => {
// const testUser = {}
beforeEach(() => {
const useCases = new UseCasesMock()
uut = new BchRouter({ adapters, useCases })
sandbox = sinon.createSandbox()
// Mock the context object.
// ctx = mockContext()
})
afterEach(() => sandbox.restore())
describe('#constructor', () => {
it('should throw an error if adapters are not passed in', () => {
try {
uut = new BchRouter()
assert.fail('Unexpected code path')
} catch (err) {
assert.include(
err.message,
'Instance of Adapters library required when instantiating BCH REST Controller.'
)
}
})
it('should throw an error if useCases are not passed in', () => {
try {
uut = new BchRouter({ adapters })
assert.fail('Unexpected code path')
} catch (err) {
assert.include(
err.message,
'Instance of Use Cases library required when instantiating BCH REST Controller.'
)
}
})
})
describe('#attach', () => {
it('should throw an error if app is not passed in.', () => {
try {
uut.attach()
assert.fail('Unexpected code path')
} catch (err) {
assert.include(
err.message,
'Must pass app object when attaching REST API controllers.'
)
}
})
})
})
@@ -0,0 +1,119 @@
/*
Mock data for the ipfs-coord.unit.js unit tests.
*/
const peers = [
'QmWkjYRRTaxVEuGK8ip2X3trVyJShFs6U9g1h9x6fK5mZ2',
'QmQqjVVD3CS6zaJmoSdt6GwX1c1tD5T9FZas4qxLbru8xN'
]
const peerData = [
{
from: 'QmWkjYRRTaxVEuGK8ip2X3trVyJShFs6U9g1h9x6fK5mZ2',
channel: 'psf-ipfs-coordination-001',
data: {
apiName: 'ipfs-coord-announce',
apiVersion: '1.3.2',
apiInfo:
'You should put an IPFS hash or web URL here to your documentation.',
ipfsId: 'QmWkjYRRTaxVEuGK8ip2X3trVyJShFs6U9g1h9x6fK5mZ2',
type: 'node.js',
ipfsMultiaddrs: [
'/ip4/127.0.0.1/tcp/5701/p2p/QmWkjYRRTaxVEuGK8ip2X3trVyJShFs6U9g1h9x6fK5mZ2',
'/ip4/127.0.0.1/tcp/5702/ws/p2p/QmWkjYRRTaxVEuGK8ip2X3trVyJShFs6U9g1h9x6fK5mZ2',
'/ip4/192.168.0.2/tcp/5701/p2p/QmWkjYRRTaxVEuGK8ip2X3trVyJShFs6U9g1h9x6fK5mZ2',
'/ip4/192.168.0.2/tcp/5702/ws/p2p/QmWkjYRRTaxVEuGK8ip2X3trVyJShFs6U9g1h9x6fK5mZ2'
],
orbitdb:
'/orbitdb/zdpuAntCMCcmZuFy2hq5F7kpcti3yHa34LLZHzyVqorkoSpAJ/QmWkjYRRTaxVEuGK8ip2X3trVyJShFs6U9g1h9x6fK5mZ221082417',
circuitRelays: [],
isCircuitRelay: false,
cryptoAddresses: [
{
blockchain: 'BCH',
type: 'cashAddr',
address: 'bitcoincash:qru6kq3p4tv6z2lmy0n560lyhh3z2feay5gjzggc37'
},
{
blockchain: 'BCH',
type: 'slpAddr',
address: 'simpleledger:qru6kq3p4tv6z2lmy0n560lyhh3z2feay5yffnac0q'
}
],
encryptPubKey:
'021db6e97650659653ba61dd493dc348a7429cdcbafd4fb73b08b1223bf5bd98df',
jsonLd: {
'@context': 'https://schema.org/',
'@type': 'WebAPI',
name: 'trout-bch-wallet-service-dev',
version: '1.11.1',
protocol: 'bch-wallet',
description:
'IPFS service providing BCH blockchain access needed by a wallet.',
documentation: 'https://ipfs-bch-wallet-service.fullstack.cash/',
provider: {
'@type': 'Organization',
name: 'Permissionless Software Foundation',
url: 'https://PSFoundation.cash'
},
identifier: 'QmWkjYRRTaxVEuGK8ip2X3trVyJShFs6U9g1h9x6fK5mZ2'
},
updatedAt: '2021-08-24T23:13:19.306Z'
}
},
{
from: 'QmQqjVVD3CS6zaJmoSdt6GwX1c1tD5T9FZas4qxLbru8xN',
channel: 'psf-ipfs-coordination-001',
data: {
apiName: 'ipfs-coord-announce',
apiVersion: '1.3.2',
apiInfo: 'https://ipfs-service-provider.fullstack.cash/',
ipfsId: 'QmQqjVVD3CS6zaJmoSdt6GwX1c1tD5T9FZas4qxLbru8xN',
type: 'node.js',
ipfsMultiaddrs: [
'/ip4/127.0.0.1/tcp/5668/p2p/QmQqjVVD3CS6zaJmoSdt6GwX1c1tD5T9FZas4qxLbru8xN',
'/ip4/127.0.0.1/tcp/5669/ws/p2p/QmQqjVVD3CS6zaJmoSdt6GwX1c1tD5T9FZas4qxLbru8xN',
'/ip4/172.17.0.4/tcp/5668/p2p/QmQqjVVD3CS6zaJmoSdt6GwX1c1tD5T9FZas4qxLbru8xN',
'/ip4/172.17.0.4/tcp/5669/ws/p2p/QmQqjVVD3CS6zaJmoSdt6GwX1c1tD5T9FZas4qxLbru8xN'
],
orbitdb:
'/orbitdb/zdpuB2H7Eqv63qWnEisR9SkW71h1GHTu32xdvza4gjBtD9AD8/QmQqjVVD3CS6zaJmoSdt6GwX1c1tD5T9FZas4qxLbru8xN21072122',
circuitRelays: [],
isCircuitRelay: false,
cryptoAddresses: [
{
blockchain: 'BCH',
type: 'cashAddr',
address: 'bitcoincash:qq4pk63gngzxnnhne39n0sl7kn2ekhnxngm5fyrgyd'
},
{
blockchain: 'BCH',
type: 'slpAddr',
address: 'simpleledger:qq4pk63gngzxnnhne39n0sl7kn2ekhnxngh0zlkg6n'
}
],
encryptPubKey:
'037676cdeac8376a75c19f62b40aa06feebc788a6704e1a1d13dcf478d090d7205',
jsonLd: {
'@context': 'https://schema.org/',
'@type': 'WebAPI',
name: 'ipfs-bch-wallet-service-dsl',
description:
'IPFS service providing BCH blockchain access needed by a wallet.',
documentation: 'https://ipfs-bch-wallet-service.fullstack.cash/',
provider: {
'@type': 'Organization',
name: 'Permissionless Software Foundation',
url: 'https://PSFoundation.cash'
},
identifier: 'QmQqjVVD3CS6zaJmoSdt6GwX1c1tD5T9FZas4qxLbru8xN'
},
updatedAt: '2021-08-24T23:13:20.411Z'
}
}
]
module.exports = {
peers,
peerData
}
+21
View File
@@ -31,12 +31,33 @@ class UserUseCaseMock {
}
}
class BchUseCaseMock {
rpcHandler() {
return {}
}
async getStatus() {
return {}
}
async getBalances() {
return {}
}
async waitForRPCResponse() {
return {}
}
}
class UseCasesMock {
constuctor(localConfig = {}) {
// this.user = new UserUseCaseMock(localConfig)
// this.user = new UserUseCaseMock()
// this.bch = new BchUseCaseMock()
}
user = new UserUseCaseMock()
bch = new BchUseCaseMock()
}
module.exports = UseCasesMock
+214
View File
@@ -0,0 +1,214 @@
/*
Mock data for the rest-api.unit.js unit tests.
*/
const rpcData = {
payload: {
id: '123',
result: {
value: {
success: true,
balances: [
{
balance: {},
address: 'addressString'
}
]
}
}
}
}
const mockRelayData = [
{
multiaddr:
'/ip4/139.162.76.54/tcp/5269/ws/p2p/QmaKzQTAtoJWYMiG5ATx41uWsMajr1kSxRdtg919s8fK77',
connected: true,
updatedAt: '2021-10-11T15:59:31.701Z',
ipfsId: 'QmaKzQTAtoJWYMiG5ATx41uWsMajr1kSxRdtg919s8fK77',
isBootstrap: false,
metrics: {
aboutLatency: [596, 769, 1029]
},
latencyScore: 682
},
{
multiaddr:
'/ip4/143.198.60.119/tcp/4003/ws/p2p/QmcewynF2DMxuvK7zk1E5es1cvBwZrfnYEaiN995KVYaKp',
connected: true,
updatedAt: '2021-10-11T15:59:31.701Z',
ipfsId: 'QmcewynF2DMxuvK7zk1E5es1cvBwZrfnYEaiN995KVYaKp',
isBootstrap: false,
metrics: {
aboutLatency: [1080, 530, 1137]
},
latencyScore: 805
},
{
multiaddr:
'/ip4/143.198.60.119/tcp/4003/ws/p2p/QmcewynF2DMxuvK7zk1E5es1cvBwZrfnYEaiN995KVYaKq',
connected: true,
updatedAt: '2021-10-11T15:59:31.701Z',
ipfsId: 'QmcewynF2DMxuvK7zk1E5es1cvBwZrfnYEaiN995KVYaKq',
isBootstrap: false,
metrics: {
aboutLatency: [1080, 530, 1137]
},
latencyScore: 805
}
]
const mockPeerData = [
{
from: 'QmaKzQTAtoJWYMiG5ATx41uWsMajr1kSxRdtg919s8fK77',
channel: 'psf-ipfs-coordination-001',
data: {
apiName: 'ipfs-coord-announce',
apiVersion: '1.3.2',
apiInfo:
'You should put an IPFS hash or web URL here to your documentation.',
broadcastedAt: '2021-10-11T15:59:59.598Z',
ipfsId: 'QmaKzQTAtoJWYMiG5ATx41uWsMajr1kSxRdtg919s8fK77',
type: 'node.js',
ipfsMultiaddrs: [
'/ip4/127.0.0.1/tcp/5268/p2p/QmaKzQTAtoJWYMiG5ATx41uWsMajr1kSxRdtg919s8fK77',
'/ip4/127.0.0.1/tcp/5269/ws/p2p/QmaKzQTAtoJWYMiG5ATx41uWsMajr1kSxRdtg919s8fK77',
'/ip4/139.162.76.54/tcp/5268/p2p/QmaKzQTAtoJWYMiG5ATx41uWsMajr1kSxRdtg919s8fK77',
'/ip4/139.162.76.54/tcp/5269/ws/p2p/QmaKzQTAtoJWYMiG5ATx41uWsMajr1kSxRdtg919s8fK77'
],
orbitdb:
'/orbitdb/zdpuApooyo2rWMuDkuTrEcxQghJKzmyQSpfUEvBhx45UNgLJX/QmaKzQTAtoJWYMiG5ATx41uWsMajr1kSxRdtg919s8fK7721101115',
circuitRelays: [],
isCircuitRelay: true,
cryptoAddresses: [
{
blockchain: 'BCH',
type: 'cashAddr',
address: 'bitcoincash:qpsaewu50nnm9gjn7e0ejmusrflfd8lrdy8szg2564'
},
{
blockchain: 'BCH',
type: 'slpAddr',
address: 'simpleledger:qpsaewu50nnm9gjn7e0ejmusrflfd8lrdyttfnl5yt'
}
],
encryptPubKey:
'0338122208e2842f39afabd23deadbe2acfdcbe69d127c24835e05603771f1e85d',
jsonLd: {
'@context': 'https://schema.org/',
'@type': 'WebAPI',
name: 'ipfs-relay-tokyo-pfs-0945772',
version: '1.3.0',
protocol: 'generic-service',
description:
'This is a generic IPFS Serivice Provider that uses JSON RPC over IPFS to communicate with it. This instance has not been customized. Source code: https://github.com/Permissionless-Software-Foundation/ipfs-service-provider',
documentation: 'https://ipfs-service-provider.fullstack.cash/',
provider: {
'@type': 'Organization',
name: 'Permissionless Software Foundation',
url: 'https://PSFoundation.cash'
},
identifier: 'QmaKzQTAtoJWYMiG5ATx41uWsMajr1kSxRdtg919s8fK77'
},
updatedAt: '2021-10-11T15:59:59.857Z'
}
},
{
from: 'QmcewynF2DMxuvK7zk1E5es1cvBwZrfnYEaiN995KVYaKp',
channel: 'psf-ipfs-coordination-001',
data: {
apiName: 'ipfs-coord-announce',
apiVersion: '1.3.2',
apiInfo:
'You should put an IPFS hash or web URL here to your documentation.',
broadcastedAt: '2021-10-11T15:59:51.277Z',
ipfsId: 'QmcewynF2DMxuvK7zk1E5es1cvBwZrfnYEaiN995KVYaKp',
type: 'node.js',
ipfsMultiaddrs: [
'/ip4/10.124.0.2/tcp/4001/p2p/QmcewynF2DMxuvK7zk1E5es1cvBwZrfnYEaiN995KVYaKp',
'/ip4/10.124.0.2/tcp/4003/ws/p2p/QmcewynF2DMxuvK7zk1E5es1cvBwZrfnYEaiN995KVYaKp',
'/ip4/10.48.0.5/tcp/4001/p2p/QmcewynF2DMxuvK7zk1E5es1cvBwZrfnYEaiN995KVYaKp',
'/ip4/10.48.0.5/tcp/4003/ws/p2p/QmcewynF2DMxuvK7zk1E5es1cvBwZrfnYEaiN995KVYaKp',
'/ip4/127.0.0.1/tcp/4001/p2p/QmcewynF2DMxuvK7zk1E5es1cvBwZrfnYEaiN995KVYaKp',
'/ip4/127.0.0.1/tcp/4003/ws/p2p/QmcewynF2DMxuvK7zk1E5es1cvBwZrfnYEaiN995KVYaKp',
'/ip4/143.198.60.119/tcp/4001/p2p/QmcewynF2DMxuvK7zk1E5es1cvBwZrfnYEaiN995KVYaKp',
'/ip4/143.198.60.119/tcp/4003/ws/p2p/QmcewynF2DMxuvK7zk1E5es1cvBwZrfnYEaiN995KVYaKp'
],
orbitdb:
'/orbitdb/zdpuAxU8itEdbqjDxCeF3C5pRN9HSXmtivJi7ygMhnew3nAPf/QmcewynF2DMxuvK7zk1E5es1cvBwZrfnYEaiN995KVYaKp21101011',
circuitRelays: [],
isCircuitRelay: true,
circuitRelayInfo: {
ip4: '143.198.60.119',
tcpPort: '4001',
crDomain: 'relayer.fullstackcash.nl'
},
cryptoAddresses: [
{
blockchain: 'BCH',
type: 'cashAddr',
address: 'bitcoincash:qzyvlftxcmwwca6qgg3l0zqqrk33hlcxhcpuv84awv'
},
{
blockchain: 'BCH',
type: 'slpAddr',
address: 'simpleledger:qzyvlftxcmwwca6qgg3l0zqqrk33hlcxhcd88uqasj'
}
],
encryptPubKey:
'038264a85c945601ce96a5727f6ec524f16b3228fffd7c2d26ce047111be5598ad',
jsonLd: {
'@context': 'https://schema.org/',
'@type': 'WebAPI',
name: 'trout-dev-railgun-relay',
version: '1.0.1',
protocol: 'railgun-relayer',
description:
'This is a generic Railgun Relayer. It has not been customized.',
documentation: 'https://www.railgun.org/',
provider: {
'@type': 'Organization',
name: 'Railgun DAO',
url: 'https://www.railgun.org/'
},
identifier: 'QmcewynF2DMxuvK7zk1E5es1cvBwZrfnYEaiN995KVYaKp'
},
updatedAt: '2021-10-11T15:59:51.430Z'
}
}
]
const ipfsMockPeers = [
{
addr: '/ip4/139.162.76.54/tcp/5269/ws/p2p/QmaKzQTAtoJWYMiG5ATx41uWsMajr1kSxRdtg919s8fK77',
peer: 'QmaKzQTAtoJWYMiG5ATx41uWsMajr1kSxRdtg919s8fK77',
direction: 'outbound',
muxer: '/mplex/6.7.0',
latency: 'n/a',
streams: []
},
{
addr: '/ip4/143.198.60.119/tcp/4003/ws/p2p/QmcewynF2DMxuvK7zk1E5es1cvBwZrfnYEaiN995KVYaKp',
peer: 'QmcewynF2DMxuvK7zk1E5es1cvBwZrfnYEaiN995KVYaKp',
direction: 'outbound',
muxer: '/mplex/6.7.0',
latency: 'n/a',
streams: []
},
// This data is used to exercise some of the exception code paths.
{
addr: '/ip4/143.198.60.119/tcp/4003/ws/p2p/QmcewynF2DMxuvK7zk1E5es1cvBwZrfnYEaiN995KVYaKo',
peer: 'QmcewynF2DMxuvK7zk1E5es1cvBwZrfnYEaiN995KVYaKo',
direction: 'outbound',
muxer: '/mplex/6.7.0',
latency: 'n/a',
streams: []
}
]
module.exports = {
rpcData,
mockRelayData,
mockPeerData,
ipfsMockPeers
}
+165
View File
@@ -0,0 +1,165 @@
/*
Unit tests for the src/lib/users.js business logic library.
TODO: verify that an admin can change the type of a user
*/
// Public npm libraries
const assert = require('chai').assert
const sinon = require('sinon')
const EventEmitter = require('events')
const cloneDeep = require('lodash.clonedeep')
// Local support libraries
// const testUtils = require('../../utils/test-utils')
// Unit under test (uut)
const BchUseCases = require('../../../src/use-cases/bch')
const adapters = require('../mocks/adapters')
const eventEmitter = new EventEmitter()
const mockDataLib = require('../mocks/use-cases/rest-api-mocks')
describe('#bch-use-case', () => {
let uut
let sandbox
let mockData
before(async () => {
// Delete all previous users in the database.
// await testUtils.deleteAllUsers()
})
beforeEach(() => {
sandbox = sinon.createSandbox()
mockData = cloneDeep(mockDataLib)
uut = new BchUseCases({ adapters, eventEmitter })
})
afterEach(() => sandbox.restore())
describe('#constructor', () => {
it('should throw an error if adapters are not passed in', () => {
try {
uut = new BchUseCases()
assert.fail('Unexpected code path')
} catch (err) {
assert.include(
err.message,
'Instance of adapters must be passed in when instantiating BCH Use Cases library.'
)
}
})
it('should throw an error if adapters are not passed in', () => {
try {
uut = new BchUseCases({ adapters })
assert.fail('Unexpected code path')
} catch (err) {
assert.include(
err.message,
'An instance of an EventEmitter must be passed when instantiating the BCH Use Cases library.'
)
}
})
})
describe('#waitForRPCResponse', () => {
it('should should resolve when data is received', async () => {
// Mock dependencies
uut.adapters.ipfs.ipfsCoordAdapter.bchjs = {
Util: {
sleep: () => {}
}
}
// Mock data.
const rpcId = '123'
uut.rpcDataQueue.push(mockData.rpcData)
const result = await uut.waitForRPCResponse(rpcId)
// console.log('result: ', result)
assert.property(result, 'success')
assert.equal(result.success, true)
assert.property(result, 'balances')
assert.isArray(result.balances)
})
it('should catch and throw an error', async () => {
try {
// Force an error
uut.adapters.ipfs.ipfsCoordAdapter.bchjs = {
Util: {
sleep: () => {
throw new Error('test error')
}
}
}
// Mock data.
const rpcId = '123'
uut.rpcDataQueue.push(mockData.rpcData)
await uut.waitForRPCResponse(rpcId)
assert.fail('Unexpected code path')
} catch (err) {
// console.log('error: ', err)
assert.include(err.message, 'test error')
}
})
})
describe('#rpcHandler', () => {
it('should add RPC data to queue', () => {
const data = {
payload: {
id: '123'
}
}
uut.rpcHandler(data)
})
})
describe('#getStatus', () => {
it('should get the status from ipfs-coord', async () => {
const result = await uut.getStatus()
console.log('result: ', result)
})
})
describe('#getBalances', () => {
it('should get the balance of an address', async () => {
// Force connection to a wallet service
uut.adapters.ipfs.ipfsCoordAdapter.state = {
selectedServiceProvider: 'abc123'
}
// Mock depenencies
sandbox.stub(uut, 'waitForRPCResponse').resolves({ key: 'value' })
const addrs = ['addr1']
const result = await uut.getBalances(addrs)
// console.log('result: ', result)
assert.equal(result.key, 'value')
})
it('should catch and throw an error', async () => {
try {
await uut.getBalances()
assert.fail('Unexpected code path')
} catch (err) {
// console.log(err)
assert.equal(err.message, 'test error')
}
})
})
})