From fc99cafb1d0d80d48cd36e0f4d322796db64231e Mon Sep 17 00:00:00 2001 From: Daniel Gonzalez Date: Wed, 24 Sep 2025 17:22:05 -0400 Subject: [PATCH] Added more tests --- src/controllers/json-rpc/index.js | 2 +- src/use-cases/ipfs-use-cases.js | 3 +- .../unit/controllers/json-rpc/a10-rpc.unit.js | 59 +++++ .../rest-api/bch/bch.rest.controller.unit.js | 75 ++++++ .../rest-api/bch/bch.rest.router.unit.js | 106 ++++++++- .../p2wdb/p2wdb.rest.controller.unit.js | 223 ++++++++++++++++++ .../rest-api/p2wdb/p2wdb.rest.router.unit.js | 110 +++++++++ .../price/price.rest.controller.unit.js | 157 ++++++++++++ .../rest-api/price/price.rest.router.unit.js | 102 ++++++++ test/unit/mocks/adapters/index.js | 17 +- test/unit/mocks/use-cases/index.js | 4 + test/unit/use-cases/ipfs.use-case.unit.js | 14 +- 12 files changed, 867 insertions(+), 5 deletions(-) create mode 100644 test/unit/controllers/rest-api/p2wdb/p2wdb.rest.controller.unit.js create mode 100644 test/unit/controllers/rest-api/p2wdb/p2wdb.rest.router.unit.js create mode 100644 test/unit/controllers/rest-api/price/price.rest.controller.unit.js create mode 100644 test/unit/controllers/rest-api/price/price.rest.router.unit.js diff --git a/src/controllers/json-rpc/index.js b/src/controllers/json-rpc/index.js index eb7b005..1552b9c 100644 --- a/src/controllers/json-rpc/index.js +++ b/src/controllers/json-rpc/index.js @@ -107,7 +107,7 @@ class JSONRPC { // Default return string let retObj = _this.defaultResponse() - + console.log('parsedData ', parsedData) // Forward data on to bch adapter if this is the response of a BCH query. try { if (parsedData.payload.result.method === 'bch') { diff --git a/src/use-cases/ipfs-use-cases.js b/src/use-cases/ipfs-use-cases.js index cff9db0..3080018 100644 --- a/src/use-cases/ipfs-use-cases.js +++ b/src/use-cases/ipfs-use-cases.js @@ -155,7 +155,8 @@ class IpfsUseCases { // Periodically re-validate the write-price (by re-instantiating the // PSFFPP library) in case it's changed. const now = new Date() - const sixHours = now.getTime() * 1000 * 60 * 60 * 6 + const sixHours = 1000 * 60 * 60 * 6 + if (this.lastWritePriceUpdate + sixHours < now.getTime()) { this.psffpp = new PSFFPP({ wallet }) diff --git a/test/unit/controllers/json-rpc/a10-rpc.unit.js b/test/unit/controllers/json-rpc/a10-rpc.unit.js index 777ee4e..cb20933 100644 --- a/test/unit/controllers/json-rpc/a10-rpc.unit.js +++ b/test/unit/controllers/json-rpc/a10-rpc.unit.js @@ -162,6 +162,40 @@ describe('#JSON RPC', () => { assert.equal(obj.result.method, 'auth') assert.equal(obj.id, id) }) + it('should route to bch handler on success payload', async () => { + const id = uid() + const json = jsonrpc.success(id, { method: 'bch' }) + const str = JSON.stringify(json) + + // Mock the controller. + sandbox.stub(uut.adapters.bch, 'rpcHandler').resolves('true') + + const result = await uut.router(str, 'peerA') + // console.log(result) + + const obj = JSON.parse(result.retStr) + // console.log('obj: ', obj) + + assert.equal(obj.result.value, 'true') + assert.equal(obj.id, id) + }) + it('should route to bch handler on success payload', async () => { + const id = uid() + const json = jsonrpc.success(id, { method: 'file-pin' }) + const str = JSON.stringify(json) + + // Mock the controller. + sandbox.stub(uut.adapters.ipfsFiles, 'rpcHandler').resolves('true') + + const result = await uut.router(str, 'peerA') + // console.log(result) + + const obj = JSON.parse(result.retStr) + // console.log('obj: ', obj) + + assert.equal(obj.result.value, 'true') + assert.equal(obj.id, id) + }) it('should route to about handler', async () => { const id = uid() @@ -188,6 +222,31 @@ describe('#JSON RPC', () => { assert.equal(obj.result.method, 'about') assert.equal(obj.id, id) }) + it('should route to bch handler', async () => { + const id = uid() + const userCall = jsonrpc.request(id, 'bch', { endpoint: 'getAll' }) + const jsonStr = JSON.stringify(userCall, null, 2) + + // Mock the controller. + sandbox.stub(uut.adapters.bch, 'rpcHandler').resolves('true') + + // Force ipfs-coord communication. + uut.ipfsCoord.ipfs = { + orbitdb: { + sendToDb: () => {} + } + } + + const result = await uut.router(jsonStr, 'peerA') + // console.log(result) + + const obj = JSON.parse(result.retStr) + // console.log('obj: ', obj) + + assert.equal(obj.result.value, 'true') + assert.equal(obj.result.method, 'bch') + assert.equal(obj.id, id) + }) it('should exit quietly for duplicate RPC message', async () => { const id = uid() diff --git a/test/unit/controllers/rest-api/bch/bch.rest.controller.unit.js b/test/unit/controllers/rest-api/bch/bch.rest.controller.unit.js index 9c3ca1a..165e4af 100644 --- a/test/unit/controllers/rest-api/bch/bch.rest.controller.unit.js +++ b/test/unit/controllers/rest-api/bch/bch.rest.controller.unit.js @@ -62,6 +62,18 @@ describe('#BCH-REST-Controller', () => { }) describe('#handleError', () => { + it('should pass an error message', () => { + try { + const err = { + status: 422, + message: 'Unprocessable Entity' + } + + uut.handleError(ctx, err) + } catch (err) { + assert.include(err.message, 'Unprocessable Entity') + } + }) it('should still throw error if there is no message', () => { try { const err = { @@ -467,4 +479,67 @@ describe('#BCH-REST-Controller', () => { assert.equal(ctx.status, 200) }) }) + + describe('#getService', () => { + it('should return 422 status on arbitrary error', async () => { + try { + sandbox.stub(uut.adapters.ipfs.ipfsCoordAdapter, 'state').value(null) + ctx.request.body = { + service: 'blah' + } + + await uut.getService(ctx) + + assert.fail('Unexpected result') + } catch (err) { + console.log('err: ', err) + assert.equal(err.status, 422) + assert.include(err.message, 'Cannot read') + } + }) + + it('should return 200 status on success', async () => { + sandbox.stub(uut.adapters.ipfs.ipfsCoordAdapter, 'state').value({ selectedServiceProvider: 'selected service' }) + ctx.request.body = { + service: 'selected service' + } + + await uut.getService(ctx) + + // Assert the expected HTTP response + assert.equal(ctx.status, 200) + }) + }) + + describe('#postProvider', () => { + it('should return 422 status on arbitrary error', async () => { + try { + uut.config.freezeProvider = true + ctx.request.body = { + providerId: 'selected provider id' + } + + await uut.postProvider(ctx) + + assert.fail('Unexpected result') + } catch (err) { + console.log('err: ', err) + assert.equal(err.status, 422) + assert.include(err.message, 'Consumer has preferredProvider set in environment variable. Refusing to switch providers.') + } + }) + + it('should return 200 status on success', async () => { + uut.config.freezeProvider = false + ctx.request.body = { + providerId: 'selected provider id' + } + + sandbox.stub(uut.adapters.bch, 'selectProvider').resolves(true) + await uut.postProvider(ctx) + + // Assert the expected HTTP response + assert.equal(ctx.status, 200) + }) + }) }) diff --git a/test/unit/controllers/rest-api/bch/bch.rest.router.unit.js b/test/unit/controllers/rest-api/bch/bch.rest.router.unit.js index f7851b7..03aaeaa 100644 --- a/test/unit/controllers/rest-api/bch/bch.rest.router.unit.js +++ b/test/unit/controllers/rest-api/bch/bch.rest.router.unit.js @@ -18,7 +18,7 @@ let sandbox // const mockContext = require('../../../../unit/mocks/ctx-mock').context -describe('#Users-REST-Router', () => { +describe('#BCH-REST-Router', () => { // const testUser = {} beforeEach(() => { @@ -75,4 +75,108 @@ describe('#Users-REST-Router', () => { } }) }) + describe('#getStatus', () => { + it('should route to controller', async () => { + const spy = sandbox.stub(uut.bchRESTController, 'getStatus').resolves(true) + + await uut.getStatus() + assert.isTrue(spy.calledOnce) + }) + }) + describe('#postProvider', () => { + it('should route to controller', async () => { + const spy = sandbox.stub(uut.bchRESTController, 'postProvider').resolves(true) + + await uut.postProvider() + assert.isTrue(spy.calledOnce) + }) + }) + describe('#postBalance', () => { + it('should route to controller', async () => { + const spy = sandbox.stub(uut.bchRESTController, 'balance').resolves(true) + + await uut.postBalance() + assert.isTrue(spy.calledOnce) + }) + }) + describe('#postUtxos', () => { + it('should route to controller', async () => { + const spy = sandbox.stub(uut.bchRESTController, 'utxos').resolves(true) + + await uut.postUtxos() + assert.isTrue(spy.calledOnce) + }) + }) + describe('#postUtxosBulk', () => { + it('should route to controller', async () => { + const spy = sandbox.stub(uut.bchRESTController, 'utxosBulk').resolves(true) + + await uut.postUtxosBulk() + assert.isTrue(spy.calledOnce) + }) + }) + describe('#postBroadcast', () => { + it('should route to controller', async () => { + const spy = sandbox.stub(uut.bchRESTController, 'broadcast').resolves(true) + + await uut.postBroadcast() + assert.isTrue(spy.calledOnce) + }) + }) + describe('#postTxHistory', () => { + it('should route to controller', async () => { + const spy = sandbox.stub(uut.bchRESTController, 'txHistory').resolves(true) + + await uut.postTxHistory() + assert.isTrue(spy.calledOnce) + }) + }) + describe('#postTxData', () => { + it('should route to controller', async () => { + const spy = sandbox.stub(uut.bchRESTController, 'txData').resolves(true) + + await uut.postTxData() + assert.isTrue(spy.calledOnce) + }) + }) + describe('#postPubKey', () => { + it('should route to controller', async () => { + const spy = sandbox.stub(uut.bchRESTController, 'pubKey').resolves(true) + + await uut.postPubKey() + assert.isTrue(spy.calledOnce) + }) + }) + describe('#utxoIsValid', () => { + it('should route to controller', async () => { + const spy = sandbox.stub(uut.bchRESTController, 'utxoIsValid').resolves(true) + + await uut.utxoIsValid() + assert.isTrue(spy.calledOnce) + }) + }) + describe('#getTokenData', () => { + it('should route to controller', async () => { + const spy = sandbox.stub(uut.bchRESTController, 'getTokenData').resolves(true) + + await uut.getTokenData() + assert.isTrue(spy.calledOnce) + }) + }) + describe('#getTokenData2', () => { + it('should route to controller', async () => { + const spy = sandbox.stub(uut.bchRESTController, 'getTokenData2').resolves(true) + + await uut.getTokenData2() + assert.isTrue(spy.calledOnce) + }) + }) + describe('#getService', () => { + it('should route to controller', async () => { + const spy = sandbox.stub(uut.bchRESTController, 'getService').resolves(true) + + await uut.getService() + assert.isTrue(spy.calledOnce) + }) + }) }) diff --git a/test/unit/controllers/rest-api/p2wdb/p2wdb.rest.controller.unit.js b/test/unit/controllers/rest-api/p2wdb/p2wdb.rest.controller.unit.js new file mode 100644 index 0000000..4ab363c --- /dev/null +++ b/test/unit/controllers/rest-api/p2wdb/p2wdb.rest.controller.unit.js @@ -0,0 +1,223 @@ +/* + Unit tests for the REST API handler for the /p2wdb endpoints. +*/ + +// Public npm libraries +import { assert } from 'chai' +import sinon from 'sinon' + +// Local support libraries +import adapters from '../../../mocks/adapters/index.js' +import UseCasesMock from '../../../mocks/use-cases/index.js' + +import P2wdbController from '../../../../../src/controllers/rest-api/p2wdb/controller.js' +import { context } from '../../../mocks/ctx-mock.js' +// import blah '../../../../unit/mocks/ctx-mock.js' +// console.log('blah: ', blah) +let uut +let sandbox +let ctx + +describe('#P2WDB-REST-Controller', () => { + // const testUser = {} + + beforeEach(() => { + const useCases = new UseCasesMock() + uut = new P2wdbController({ adapters, useCases }) + + sandbox = sinon.createSandbox() + + // Mock the context object. + ctx = context() + }) + + afterEach(() => sandbox.restore()) + + describe('#constructor', () => { + it('should throw an error if adapters are not passed in', () => { + try { + uut = new P2wdbController() + + assert.fail('Unexpected code path') + } catch (err) { + assert.include( + err.message, + 'Instance of Adapters library required when instantiating /p2wdb REST Controller.' + ) + } + }) + + it('should throw an error if useCases are not passed in', () => { + try { + uut = new P2wdbController({ adapters }) + + assert.fail('Unexpected code path') + } catch (err) { + assert.include( + err.message, + 'Instance of Use Cases library required when instantiating /p2wdb REST Controller.' + ) + } + }) + }) + + describe('#handleError', () => { + it('should pass an error message', () => { + try { + const err = { + status: 422, + message: 'Unprocessable Entity' + } + + uut.handleError(ctx, err) + } catch (err) { + assert.include(err.message, 'Unprocessable Entity') + } + }) + 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.adapters.p2wdb, '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.adapters.p2wdb, 'getStatus').resolves('p2wdb') + + 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, 'p2wdb') + }) + }) + + describe('#postProvider', () => { + it('should return 422 status on arbitrary error', async () => { + try { + // Force an error + sandbox + .stub(uut.adapters.p2wdb, 'selectProvider') + .rejects(new Error('test error')) + + ctx.request.body = { + addresses: 'blah' + } + + await uut.postProvider(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.adapters.p2wdb, 'selectProvider').resolves({ status: 200 }) + + ctx.request.body = { + addresses: 'blah' + } + + await uut.postProvider(ctx) + + // Assert the expected HTTP response + assert.equal(ctx.status, 200) + }) + }) + describe('#getEntryByHash', () => { + it('should return 422 status on arbitrary error', async () => { + try { + // Force an error + sandbox + .stub(uut.adapters.p2wdb, 'getEntryByHash') + .rejects(new Error('test error')) + + ctx.request.body = { + hash: 'blah' + } + + await uut.getEntryByHash(ctx) + } catch (err) { + assert.equal(err.status, 422) + assert.include(err.message, 'test error') + } + }) + + it('should return 200 status on success', async () => { + sandbox.stub(uut.adapters.p2wdb, 'getEntryByHash').resolves({ status: 200 }) + + ctx.request.body = { + hash: 'blah' + } + + await uut.getEntryByHash(ctx) + assert.equal(ctx.status, 200) + }) + }) + + describe('#writeEntry', () => { + it('should return 422 status on arbitrary error', async () => { + try { + // Force an error + sandbox + .stub(uut.adapters.p2wdb, 'writeEntry') + .rejects(new Error('test error')) + + ctx.request.body = { + txid: 'blah', + signature: 'blah', + message: 'blah', + data: 'blah' + } + + await uut.writeEntry(ctx) + } catch (err) { + assert.equal(err.status, 422) + assert.include(err.message, 'test error') + } + }) + + it('should return 200 status on success', async () => { + sandbox.stub(uut.adapters.p2wdb, 'writeEntry').resolves({ status: 200 }) + + ctx.request.body = { + txid: 'blah', + signature: 'blah', + message: 'blah', + data: 'blah' + } + + await uut.writeEntry(ctx) + assert.equal(ctx.status, 200) + }) + }) +}) diff --git a/test/unit/controllers/rest-api/p2wdb/p2wdb.rest.router.unit.js b/test/unit/controllers/rest-api/p2wdb/p2wdb.rest.router.unit.js new file mode 100644 index 0000000..f136fed --- /dev/null +++ b/test/unit/controllers/rest-api/p2wdb/p2wdb.rest.router.unit.js @@ -0,0 +1,110 @@ +/* + Unit tests for the REST API handler for the /users endpoints. +*/ + +// Public npm libraries +import { assert } from 'chai' +import sinon from 'sinon' + +// Local support libraries +import adapters from '../../../mocks/adapters/index.js' +import UseCasesMock from '../../../mocks/use-cases/index.js' +// const app = require('../../../mocks/app-mock') + +import P2wdbRouter from '../../../../../src/controllers/rest-api/p2wdb/index.js' +let uut +let sandbox +// let ctx + +// const mockContext = require('../../../../unit/mocks/ctx-mock').context + +describe('#P2WDB-REST-Router', () => { + // const testUser = {} + + beforeEach(() => { + const useCases = new UseCasesMock() + uut = new P2wdbRouter({ 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 P2wdbRouter() + + assert.fail('Unexpected code path') + } catch (err) { + assert.include( + err.message, + 'Instance of Adapters library required when instantiating P2WDB REST Controller.' + ) + } + }) + + it('should throw an error if useCases are not passed in', () => { + try { + uut = new P2wdbRouter({ adapters }) + + assert.fail('Unexpected code path') + } catch (err) { + assert.include( + err.message, + 'Instance of Use Cases library required when instantiating P2WDB 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.' + ) + } + }) + }) + describe('#getStatus', () => { + it('should route to controller', async () => { + const spy = sandbox.stub(uut.p2wdbRESTController, 'getStatus').resolves(true) + + await uut.getStatus() + assert.isTrue(spy.calledOnce) + }) + }) + describe('#postProvider', () => { + it('should route to controller', async () => { + const spy = sandbox.stub(uut.p2wdbRESTController, 'postProvider').resolves(true) + + await uut.postProvider() + assert.isTrue(spy.calledOnce) + }) + }) + describe('#entryFromHash', () => { + it('should route to controller', async () => { + const spy = sandbox.stub(uut.p2wdbRESTController, 'getEntryByHash').resolves(true) + + await uut.entryFromHash() + assert.isTrue(spy.calledOnce) + }) + }) + describe('#write', () => { + it('should route to controller', async () => { + const spy = sandbox.stub(uut.p2wdbRESTController, 'writeEntry').resolves(true) + + await uut.write() + assert.isTrue(spy.calledOnce) + }) + }) +}) diff --git a/test/unit/controllers/rest-api/price/price.rest.controller.unit.js b/test/unit/controllers/rest-api/price/price.rest.controller.unit.js new file mode 100644 index 0000000..6df9dad --- /dev/null +++ b/test/unit/controllers/rest-api/price/price.rest.controller.unit.js @@ -0,0 +1,157 @@ +/* + Unit tests for the REST API handler for the /price endpoints. +*/ + +// Public npm libraries +import { assert } from 'chai' +import sinon from 'sinon' + +// Local support libraries +import adapters from '../../../mocks/adapters/index.js' +import UseCasesMock from '../../../mocks/use-cases/index.js' + +import PriceController from '../../../../../src/controllers/rest-api/price/controller.js' +import { context } from '../../../mocks/ctx-mock.js' +// import blah '../../../../unit/mocks/ctx-mock.js' +// console.log('blah: ', blah) +let uut +let sandbox +let ctx + +describe('#PRICE-REST-Controller', () => { + // const testUser = {} + + beforeEach(() => { + const useCases = new UseCasesMock() + uut = new PriceController({ adapters, useCases }) + + sandbox = sinon.createSandbox() + + // Mock the context object. + ctx = context() + }) + + afterEach(() => sandbox.restore()) + + describe('#constructor', () => { + it('should throw an error if adapters are not passed in', () => { + try { + uut = new PriceController() + + assert.fail('Unexpected code path') + } catch (err) { + assert.include( + err.message, + 'Instance of Adapters library required when instantiating /price REST Controller.' + ) + } + }) + + it('should throw an error if useCases are not passed in', () => { + try { + uut = new PriceController({ adapters }) + + assert.fail('Unexpected code path') + } catch (err) { + assert.include( + err.message, + 'Instance of Use Cases library required when instantiating /price REST Controller.' + ) + } + }) + }) + + describe('#handleError', () => { + it('should pass an error message', () => { + try { + const err = { + status: 422, + message: 'Unprocessable Entity' + } + + uut.handleError(ctx, err) + } catch (err) { + assert.include(err.message, 'Unprocessable Entity') + } + }) + 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('#getUSD', () => { + it('should return 422 status on arbitrary biz logic error', async () => { + try { + // Force an error + sandbox + .stub(uut.axios, 'request') + .rejects(new Error('test error')) + + await uut.getUSD(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.axios, 'request').resolves({ data: { data: { rates: { USD: 1.00 } } } }) + + await uut.getUSD(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.usd, 1.00) + }) + }) + + describe('#getXecPrice', () => { + it('should return 422 status on arbitrary biz logic error', async () => { + try { + sandbox.stub(uut.axios, 'request').rejects(new Error('test error')) + await uut.getXecPrice(ctx) + assert.fail('Unexpected result') + } catch (err) { + assert.equal(err.status, 422) + assert.include(err.message, 'test error') + } + }) + it('should return 200 status on success', async () => { + sandbox.stub(uut.axios, 'request').resolves({ data: { data: { ticker: { last: 1.00 } } } }) + await uut.getXecPrice(ctx) + assert.equal(ctx.status, 200) + assert.equal(ctx.response.body.usd, 1.00) + }) + }) + describe('#getPsffppWritePrice', () => { + it('should return 200 status on success', async () => { + sandbox.stub(uut.useCases.ipfs, 'getWritePrice').resolves(1.00) + await uut.getPsffppWritePrice(ctx) + assert.equal(ctx.status, 200) + assert.equal(ctx.response.body.psfPrice, 1.00) + }) + it('should return 422 status on arbitrary biz logic error', async () => { + try { + sandbox.stub(uut.useCases.ipfs, 'getWritePrice').rejects(new Error('test error')) + await uut.getPsffppWritePrice(ctx) + assert.fail('Unexpected result') + } catch (err) { + assert.equal(err.status, 422) + assert.include(err.message, 'test error') + } + }) + }) +}) diff --git a/test/unit/controllers/rest-api/price/price.rest.router.unit.js b/test/unit/controllers/rest-api/price/price.rest.router.unit.js new file mode 100644 index 0000000..a0fb333 --- /dev/null +++ b/test/unit/controllers/rest-api/price/price.rest.router.unit.js @@ -0,0 +1,102 @@ +/* + Unit tests for the REST API handler for the /users endpoints. +*/ + +// Public npm libraries +import { assert } from 'chai' +import sinon from 'sinon' + +// Local support libraries +import adapters from '../../../mocks/adapters/index.js' +import UseCasesMock from '../../../mocks/use-cases/index.js' +// const app = require('../../../mocks/app-mock') + +import PriceRouter from '../../../../../src/controllers/rest-api/price/index.js' +let uut +let sandbox +// let ctx + +// const mockContext = require('../../../../unit/mocks/ctx-mock').context + +describe('#Price-REST-Router', () => { + // const testUser = {} + + beforeEach(() => { + const useCases = new UseCasesMock() + uut = new PriceRouter({ 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 PriceRouter() + + assert.fail('Unexpected code path') + } catch (err) { + assert.include( + err.message, + 'Instance of Adapters library required when instantiating Price REST Controller.' + ) + } + }) + + it('should throw an error if useCases are not passed in', () => { + try { + uut = new PriceRouter({ adapters }) + + assert.fail('Unexpected code path') + } catch (err) { + assert.include( + err.message, + 'Instance of Use Cases library required when instantiating Price 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.' + ) + } + }) + }) + describe('#getPrice', () => { + it('should route to controller', async () => { + const spy = sandbox.stub(uut.priceRESTController, 'getUSD').resolves(true) + + await uut.getPrice() + assert.isTrue(spy.calledOnce) + }) + }) + + describe('#getXecPrice', () => { + it('should route to controller', async () => { + const spy = sandbox.stub(uut.priceRESTController, 'getXecPrice').resolves(true) + + await uut.getXecPrice() + assert.isTrue(spy.calledOnce) + }) + }) + describe('#getPsffppWritePrice', () => { + it('should route to controller', async () => { + const spy = sandbox.stub(uut.priceRESTController, 'getPsffppWritePrice').resolves(true) + await uut.getPsffppWritePrice() + assert.isTrue(spy.calledOnce) + }) + }) +}) diff --git a/test/unit/mocks/adapters/index.js b/test/unit/mocks/adapters/index.js index cdd465c..109e853 100644 --- a/test/unit/mocks/adapters/index.js +++ b/test/unit/mocks/adapters/index.js @@ -187,6 +187,9 @@ class BchUseCaseMock { async waitForRPCResponse () { return {} } + async selectProvider (){ + return true + } } const bch = new BchUseCaseMock() const wallet = { @@ -212,6 +215,18 @@ const ipfsFiles = { success: true, message: 'Pins' } + }, + rpcHandler: () => { + return { + success: true, + message: 'RPC handler' + } } } -export default { ipfs, localdb, bch, wallet, ipfsFiles } +const p2wdb = { + getStatus: async () => {}, + selectProvider: async () => {}, + getEntryByHash: async () => {}, + writeEntry: async () => {} +} +export default { ipfs, localdb, bch, wallet, ipfsFiles, p2wdb } diff --git a/test/unit/mocks/use-cases/index.js b/test/unit/mocks/use-cases/index.js index eef55c6..e7df4a5 100644 --- a/test/unit/mocks/use-cases/index.js +++ b/test/unit/mocks/use-cases/index.js @@ -95,6 +95,10 @@ class IpfsUseCaseMock { async pinClaim() { return {} } + + async getWritePrice() { + return 1.00 + } } class UseCasesMock { diff --git a/test/unit/use-cases/ipfs.use-case.unit.js b/test/unit/use-cases/ipfs.use-case.unit.js index ca81a37..9b91bdd 100644 --- a/test/unit/use-cases/ipfs.use-case.unit.js +++ b/test/unit/use-cases/ipfs.use-case.unit.js @@ -14,7 +14,6 @@ import sinon from 'sinon' import UseCases from '../../../src/use-cases/ipfs-use-cases.js' import adapters from '../mocks/adapters/index.js' - describe('#ipfs-use-cases', () => { let uut let sandbox @@ -92,15 +91,28 @@ describe('#ipfs-use-cases', () => { const result = await uut.getWritePrice() assert.isNumber(result) }) + it('should re-instantiate psffpp instance', async () => { + const psffppMock = {} + uut.psffpp = psffppMock + const lastWritePriceUpdate = new Date() + lastWritePriceUpdate.setHours(lastWritePriceUpdate.getHours() - 10) + uut.lastWritePriceUpdate = lastWritePriceUpdate.getTime() + const result = await uut.getWritePrice() + assert.isNumber(result) + assert.notEqual(uut.lastWritePriceUpdate, lastWritePriceUpdate.getTime()) + assert.notEqual(uut.psffpp, psffppMock) + }) it('should handle error ', async () => { try { + uut.lastWritePriceUpdate = new Date().getTime() uut.psffpp = { getMcWritePrice: () => { throw new Error('test error') } } await uut.getWritePrice() + assert.fail('Unexpected code path') } catch (error) { assert.include(error.message, 'test error') }