From 263ee1b6e1f004a43419ea343ec34bb3f6a65c0e Mon Sep 17 00:00:00 2001 From: TRBC Date: Wed, 11 Nov 2020 15:05:33 -0400 Subject: [PATCH] solved issue #10 --- src/ninsight.js | 70 +++++++++++++++ test/integration/bchn/ninsight.js | 85 ++++++++++++++++++ test/integration/ninsight.js | 88 ++++++++++++++++++- test/unit/fixtures/ninsight-mock.js | 28 +++++- test/unit/ninsight.js | 129 ++++++++++++++++++++++++++-- 5 files changed, 390 insertions(+), 10 deletions(-) diff --git a/src/ninsight.js b/src/ninsight.js index fe2e0e5..baea6f5 100644 --- a/src/ninsight.js +++ b/src/ninsight.js @@ -314,6 +314,76 @@ class Ninsight { else throw error } } + /** + * @api Ninsight.details() details() + * @apiName Ninsight Details + * @apiGroup Ninsight + * @apiDescription Return details of address. + * + * @apiExample Example usage: + * (async () => { + * try { + * let details = await bchjs.Ninsight.details('bitcoincash:qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c'); + * let details = await bchjs.Ninsight.details(['bitcoincash:qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c','bitcoincash:qzs02v05l7qs5s24srqju498qu55dwuj0cx5ehjm2c']); + * console.log(details); + * } catch(error) { + * console.error(error) + * } + * })() + * + * // [ + * // { + * //"balance": 0.00001, + * //"balanceSat": 1000, + * //"totalReceived": 0.00001, + * //"totalReceivedSat": 1000, + * //"totalSent": 0, + * //"totalSentSat": 0, + * //"unconfirmedBalance": 0, + * //"unconfirmedBalanceSat": 0, + * //"unconfirmedTxApperances": 0, + * //"txApperances": 1, + * //"transactions": [ + * //"5f09d317e24c5d376f737a2711f3bd1d381abdb41743fff3819b4f76382e1eac" ], + * //"legacyAddress": "1FZrK8HohEKyKCTM24NkAzPnX9WD9Ujhw7", + * //"cashAddress": "bitcoincash:qz0us0z6ucpqt07jgpad0shgh7xmwxyr3ynlcsq0wr", + * //"slpAddress": "simpleledger:qz0us0z6ucpqt07jgpad0shgh7xmwxyr3ylynt40sa", + * //"currentPage": 0, + * //"pagesTotal": 1 + * // } + * // ] + * + */ + async details(address) { + try { + _this._validateParam(address) + return _this._callAxios(address, 'details') + } catch (e) { + _this._handleError(e) + } + } + + _validateParam(address) { + if (typeof address !== "string" && !Array.isArray(address)) + throw new Error(`Input address must be a string or array of strings.`) + } + + _handleError(error) { + if (error.response && error.response.data) throw error.response.data + else throw error + } + + async _callAxios(address, type) { + const response = await axios.post( + `${_this.ninsightURL}/address/${type}`, + { + addresses: Array.isArray(address) ? address : [address] + }, + _this.axiosOptions + ) + //console.log(`SAMPLE: ${response.data}`); + return response.data + } } module.exports = Ninsight diff --git a/test/integration/bchn/ninsight.js b/test/integration/bchn/ninsight.js index 75639af..0bc57b4 100644 --- a/test/integration/bchn/ninsight.js +++ b/test/integration/bchn/ninsight.js @@ -126,4 +126,89 @@ describe(`#Ninsight`, () => { assert.property(result[0], "vout") }) }) + + describe(`#detailsAddress`, () => { + it(`should throw an error for improper input`, async () => { + try { + const addr = 12345 + + await bchjs.Ninsight.details(addr) + assert.equal(true, false, "Unexpected result!") + } catch (err) { + //console.log(`err: `, err) + assert.include( + err.message, + `Input address must be a string or array of strings.` + ) + } + }) + + it(`should GET details for a single address`, async () => { + const addr = "bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7" + + const result = await bchjs.Ninsight.details(addr) + //console.log(`result: ${JSON.stringify(result, null, 2)}`) + assert.property(result[0], "balance") + assert.property(result[0], "balanceSat") + assert.property(result[0], "totalReceived") + assert.property(result[0], "totalReceivedSat") + assert.property(result[0], "totalSent") + assert.property(result[0], "totalSentSat") + assert.property(result[0], "unconfirmedBalance") + assert.property(result[0], "unconfirmedBalanceSat") + assert.property(result[0], "unconfirmedTxApperances") + assert.property(result[0], "txApperances") + assert.property(result[0], "transactions") + assert.property(result[0], "legacyAddress") + assert.property(result[0], "cashAddress") + assert.property(result[0], "slpAddress") + assert.property(result[0], "currentPage") + assert.property(result[0], "pagesTotal") + }) + + it(`should GET details for an array of addresses`, async () => { + const addr = [ + "bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7", + "bitcoincash:qz0us0z6ucpqt07jgpad0shgh7xmwxyr3ynlcsq0wr" + ] + + const result = await bchjs.Ninsight.details(addr) + //console.log(`result: ${JSON.stringify(result, null, 2)}`) + + assert.isArray(result) + assert.property(result[0], "balance") + assert.property(result[0], "balanceSat") + assert.property(result[0], "totalReceived") + assert.property(result[0], "totalReceivedSat") + assert.property(result[0], "totalSent") + assert.property(result[0], "totalSentSat") + assert.property(result[0], "unconfirmedBalance") + assert.property(result[0], "unconfirmedBalanceSat") + assert.property(result[0], "unconfirmedTxApperances") + assert.property(result[0], "txApperances") + assert.property(result[0], "transactions") + assert.property(result[0], "legacyAddress") + assert.property(result[1], "cashAddress") + assert.property(result[1], "slpAddress") + assert.property(result[1], "currentPage") + assert.property(result[1], "pagesTotal") + + /* + If in any way possible, I would like to refactor this test + according to the DRY principle to share it with the integration tests too + Would that make sense or does that implicate anything unwanted? + + assertDetails(result[0]) + + assertDetails(data) { + assert.property(data, "balance") + assert.property(data, "balanceSat") + assert.property(data, "totalReceived") + assert.property(data, "totalReceivedSat") + assert.property(data, "totalSent") + assert.property(data, "totalSentSat") + } + */ + }) + }) }) diff --git a/test/integration/ninsight.js b/test/integration/ninsight.js index 911fef0..b9286ed 100644 --- a/test/integration/ninsight.js +++ b/test/integration/ninsight.js @@ -3,7 +3,9 @@ const assert = chai.assert const sinon = require("sinon") const BCHJS = require("../../src/bch-js") -const bchjs = new BCHJS({ ninsightURL: "https://rest.bitcoin.com/v2" }) +const bchjs = new BCHJS({ + ninsightURL: "https://rest.bitcoin.com/v2" +}) describe(`#Ninsight`, () => { let sandbox @@ -131,6 +133,90 @@ describe(`#Ninsight`, () => { assert.property(result[0], "vout") }) }) + describe(`#detailsAddress`, () => { + it(`should throw an error for improper input`, async () => { + try { + const addr = 12345 + + await bchjs.Ninsight.details(addr) + assert.equal(true, false, "Unexpected result!") + } catch (err) { + //console.log(`err: `, err) + assert.include( + err.message, + `Input address must be a string or array of strings.` + ) + } + }) + + it(`should GET details for a single address`, async () => { + const addr = "bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7" + + const result = await bchjs.Ninsight.details(addr) + //console.log(`result: ${JSON.stringify(result, null, 2)}`) + assert.property(result[0], "balance") + assert.property(result[0], "balanceSat") + assert.property(result[0], "totalReceived") + assert.property(result[0], "totalReceivedSat") + assert.property(result[0], "totalSent") + assert.property(result[0], "totalSentSat") + assert.property(result[0], "unconfirmedBalance") + assert.property(result[0], "unconfirmedBalanceSat") + assert.property(result[0], "unconfirmedTxApperances") + assert.property(result[0], "txApperances") + assert.property(result[0], "transactions") + assert.property(result[0], "legacyAddress") + assert.property(result[0], "cashAddress") + assert.property(result[0], "slpAddress") + assert.property(result[0], "currentPage") + assert.property(result[0], "pagesTotal") + }) + + it(`should GET details for an array of addresses`, async () => { + const addr = [ + "bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7", + "bitcoincash:qz0us0z6ucpqt07jgpad0shgh7xmwxyr3ynlcsq0wr" + ] + + const result = await bchjs.Ninsight.details(addr) + //console.log(`result: ${JSON.stringify(result, null, 2)}`) + + assert.isArray(result) + assert.property(result[0], "balance") + assert.property(result[0], "balanceSat") + assert.property(result[0], "totalReceived") + assert.property(result[0], "totalReceivedSat") + assert.property(result[0], "totalSent") + assert.property(result[0], "totalSentSat") + assert.property(result[0], "unconfirmedBalance") + assert.property(result[0], "unconfirmedBalanceSat") + assert.property(result[0], "unconfirmedTxApperances") + assert.property(result[0], "txApperances") + assert.property(result[0], "transactions") + assert.property(result[0], "legacyAddress") + assert.property(result[1], "cashAddress") + assert.property(result[1], "slpAddress") + assert.property(result[1], "currentPage") + assert.property(result[1], "pagesTotal") + + /* + If in any way possible, I would like to refactor this test + according to the DRY principle to share it with the integration tests too + Would that make sense or does that implicate anything unwanted? + + assertDetails(result[0]) + + assertDetails(data) { + assert.property(data, "balance") + assert.property(data, "balanceSat") + assert.property(data, "totalReceived") + assert.property(data, "totalReceivedSat") + assert.property(data, "totalSent") + assert.property(data, "totalSentSat") + } + */ + }) + }) }) function sleep(ms) { diff --git a/test/unit/fixtures/ninsight-mock.js b/test/unit/fixtures/ninsight-mock.js index d261f7e..5baec0b 100644 --- a/test/unit/fixtures/ninsight-mock.js +++ b/test/unit/fixtures/ninsight-mock.js @@ -158,6 +158,30 @@ const details = { const detailsPost = [details, details] +const addrDetail = + { + "balance": 0.00001, + "balanceSat": 1000, + "totalReceived": 0.00001, + "totalReceivedSat": 1000, + "totalSent": 0, + "totalSentSat": 0, + "unconfirmedBalance": 0, + "unconfirmedBalanceSat": 0, + "unconfirmedTxApperances": 0, + "txApperances": 1, + "transactions": [ + "5f09d317e24c5d376f737a2711f3bd1d381abdb41743fff3819b4f76382e1eac" + ], + "legacyAddress": "1FZrK8HohEKyKCTM24NkAzPnX9WD9Ujhw7", + "cashAddress": "bitcoincash:qz0us0z6ucpqt07jgpad0shgh7xmwxyr3ynlcsq0wr", + "slpAddress": "simpleledger:qz0us0z6ucpqt07jgpad0shgh7xmwxyr3ylynt40sa", + "currentPage": 0, + "pagesTotal": 1 + } + +const addrDetailArray = [addrDetail, addrDetail] + module.exports = { utxo, utxoPost, @@ -166,5 +190,7 @@ module.exports = { transactions, transactionsPost, details, - detailsPost + detailsPost, + addrDetail, + addrDetailArray } diff --git a/test/unit/ninsight.js b/test/unit/ninsight.js index 9670586..4453776 100644 --- a/test/unit/ninsight.js +++ b/test/unit/ninsight.js @@ -31,7 +31,9 @@ describe(`#Ninsight`, () => { it(`should GET utxos for a single address`, async () => { // Stub the network call. - sandbox.stub(axios, "post").resolves({ data: mockData.utxo }) + sandbox.stub(axios, "post").resolves({ + data: mockData.utxo + }) const addr = "bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9" @@ -57,7 +59,9 @@ describe(`#Ninsight`, () => { it(`should POST utxo details for an array of addresses`, async () => { // Mock the network call. - sandbox.stub(axios, "post").resolves({ data: mockData.utxoPost }) + sandbox.stub(axios, "post").resolves({ + data: mockData.utxoPost + }) const addr = [ "bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7", @@ -96,7 +100,9 @@ describe(`#Ninsight`, () => { it(`should POST utxos for a single address`, async () => { // Stub the network call. - sandbox.stub(axios, "post").resolves({ data: mockData.unconfirmed }) + sandbox.stub(axios, "post").resolves({ + data: mockData.unconfirmed + }) const addr = "bitcoincash:qpkkjkhe29mqhqmu3evtq3dsnruuzl3rku6usknlh5" @@ -121,7 +127,9 @@ describe(`#Ninsight`, () => { it(`should POST utxo details for an array of addresses`, async () => { // Mock the network call. - sandbox.stub(axios, "post").resolves({ data: mockData.unconfirmedPost }) + sandbox.stub(axios, "post").resolves({ + data: mockData.unconfirmedPost + }) const addr = [ "bitcoincash:qpkkjkhe29mqhqmu3evtq3dsnruuzl3rku6usknlh5", @@ -159,7 +167,9 @@ describe(`#Ninsight`, () => { }) it(`should POST transaction history for a single address`, async () => { // Stub the network call. - sandbox.stub(axios, "post").resolves({ data: mockData.transactionsPost }) + sandbox.stub(axios, "post").resolves({ + data: mockData.transactionsPost + }) const addr = "bitcoincash:qqh793x9au6ehvh7r2zflzguanlme760wuzehgzjh9" @@ -177,7 +187,9 @@ describe(`#Ninsight`, () => { }) it(`should POST transaction history for an array of addresses`, async () => { // Mock the network call. - sandbox.stub(axios, "post").resolves({ data: mockData.transactionsPost }) + sandbox.stub(axios, "post").resolves({ + data: mockData.transactionsPost + }) const addr = [ "bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7", @@ -212,7 +224,9 @@ describe(`#Ninsight`, () => { }) it(`should POST transaction details for a single TxID`, async () => { // Stub the network call. - sandbox.stub(axios, "post").resolves({ data: mockData.detailsPost }) + sandbox.stub(axios, "post").resolves({ + data: mockData.detailsPost + }) const txid = "fe28050b93faea61fa88c4c630f0e1f0a1c24d0082dd0e10d369e13212128f33" @@ -236,7 +250,9 @@ describe(`#Ninsight`, () => { }) it(`should POST transaction details for an array of TxIDs`, async () => { // Stub the network call. - sandbox.stub(axios, "post").resolves({ data: mockData.detailsPost }) + sandbox.stub(axios, "post").resolves({ + data: mockData.detailsPost + }) const txid = [ "fe28050b93faea61fa88c4c630f0e1f0a1c24d0082dd0e10d369e13212128f33", @@ -252,4 +268,101 @@ describe(`#Ninsight`, () => { assert.property(result[0], "vout") }) }) + + describe(`#addrDetails`, () => { + it(`should throw an error for improper input`, async () => { + try { + const addr = 12345 + + await bchjs.Ninsight.details(addr) + assert.equal(true, false, "Unexpected result!") + } catch (err) { + //console.log(`err: `, err) + assert.include( + err.message, + `Input address must be a string or array of strings.` + ) + } + }) + + it(`should GET details for a single address`, async () => { + // Stub the network call. + sandbox.stub(axios, "post").resolves({ + data: mockData.addrDetail + }) + + const result = await bchjs.Ninsight.details("addr") + //console.log(`result: ${JSON.stringify(result, null, 2)}`) + + assert.property(result, "balance") + assert.property(result, "balanceSat") + assert.property(result, "totalReceived") + assert.property(result, "totalReceivedSat") + assert.property(result, "totalSent") + assert.property(result, "totalSentSat") + assert.property(result, "unconfirmedBalance") + assert.property(result, "unconfirmedBalanceSat") + assert.property(result, "unconfirmedTxApperances") + assert.property(result, "txApperances") + assert.property(result, "transactions") + assert.property(result, "legacyAddress") + assert.property(result, "cashAddress") + assert.property(result, "slpAddress") + assert.property(result, "currentPage") + assert.property(result, "pagesTotal") + }) + + it(`should GET details for an array of addresses`, async () => { + // Mock the network call. + sandbox.stub(axios, "post").resolves({ + data: mockData.addrDetailArray + }) + + const addr = [ + "bitcoincash:qp3sn6vlwz28ntmf3wmyra7jqttfx7z6zgtkygjhc7", + "bitcoincash:qz0us0z6ucpqt07jgpad0shgh7xmwxyr3ynlcsq0wr" + ] + + const result = await bchjs.Ninsight.details(addr) + // console.log(`result: ${JSON.stringify(result, null, 2)}`) + + assert.isArray(result) + + assert.property(result[0], "balance") + assert.property(result[0], "balanceSat") + assert.property(result[0], "totalReceived") + assert.property(result[0], "totalReceivedSat") + assert.property(result[0], "totalSent") + assert.property(result[0], "totalSentSat") + assert.property(result[0], "unconfirmedBalance") + assert.property(result[0], "unconfirmedBalanceSat") + assert.property(result[0], "unconfirmedTxApperances") + assert.property(result[0], "txApperances") + assert.property(result[0], "transactions") + assert.property(result[0], "legacyAddress") + assert.property(result[1], "cashAddress") + assert.property(result[1], "slpAddress") + assert.property(result[1], "currentPage") + assert.property(result[1], "pagesTotal") + + /* + If in any way possible, I would like to refactor this test + according to the DRY principle to share it with the integration tests too + Would that make sense or does that implicate anything unwanted? + + assertDetails(result[0]) + + assertDetails(data) { + assert.property(data, "satoshis") + assert.property(data, "height") + assert.property(data, "confirmations") + assert.property(data, "timestamp") + assert.property(data, "fees") + assert.property(data, "outputIndexes") + assert.property(data, "inputIndexes") + assert.property(data, "tx") + } + */ + }) + }) })