mirror of
https://github.com/Permissionless-Software-Foundation/bch-dex.git
synced 2026-09-21 16:52:00 -07:00
Merge pull request #106 from Permissionless-Software-Foundation/dh-unit-test-coverage
feat(tests): Added more unit test coverage
This commit is contained in:
@@ -64,6 +64,7 @@ class P2WDBRESTControllerLib {
|
||||
await _this.useCases.offer.flagOffer(flagData)
|
||||
} else {
|
||||
console.log('Could not route P2WDB webhook data.')
|
||||
// NOTE: Should we throw an error here?
|
||||
}
|
||||
|
||||
// const orderObj = ctx.request.body.order
|
||||
|
||||
@@ -12,13 +12,13 @@ class SmAccountRESTControllerLib {
|
||||
this.adapters = localConfig.adapters
|
||||
if (!this.adapters) {
|
||||
throw new Error(
|
||||
'Instance of Adapters library required when instantiating /order REST Controller.'
|
||||
'Instance of Adapters library required when instantiating /sm REST Controller.'
|
||||
)
|
||||
}
|
||||
this.useCases = localConfig.useCases
|
||||
if (!this.useCases) {
|
||||
throw new Error(
|
||||
'Instance of Use Cases library required when instantiating /order REST Controller.'
|
||||
'Instance of Use Cases library required when instantiating /sm REST Controller.'
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -40,7 +40,6 @@ class SmAccountRouter {
|
||||
const baseUrl = '/sm'
|
||||
this.router = new Router({ prefix: baseUrl })
|
||||
|
||||
this.listAccounts = this.listAccounts.bind(this)
|
||||
_this = this
|
||||
}
|
||||
|
||||
@@ -60,11 +59,6 @@ class SmAccountRouter {
|
||||
app.use(_this.router.routes())
|
||||
app.use(_this.router.allowedMethods())
|
||||
}
|
||||
|
||||
async listAccounts (ctx, next) {
|
||||
// await _this.validators.ensureUser(ctx, next)
|
||||
await _this.smAccountRESTController.listAccounts(ctx, next)
|
||||
}
|
||||
}
|
||||
|
||||
export default SmAccountRouter
|
||||
|
||||
@@ -105,6 +105,7 @@ class TimerControllers {
|
||||
console.error('Error in time-controller.js/cleanUsage(): ', err)
|
||||
|
||||
this.cleanUsageHandle = setInterval(this.cleanUsage, this.cleanUsageInterval)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
/*
|
||||
Entry Entity
|
||||
|
||||
TODO: Explain what an entry is and how it works.
|
||||
*/
|
||||
|
||||
class Entry {
|
||||
validate ({
|
||||
entry,
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
/*
|
||||
Entry use-case library.
|
||||
|
||||
TODO: Explain what an entry is and how it works.
|
||||
*/
|
||||
|
||||
// local libraries
|
||||
import wlogger from '../adapters/wlogger.js'
|
||||
@@ -30,11 +35,12 @@ class EntryLib {
|
||||
if (!isValidSignature) {
|
||||
throw new Error('Invalid signature')
|
||||
}
|
||||
|
||||
// Verify psf tokens balance
|
||||
// const psfBalance = await this.bch.getPSFTokenBalance(
|
||||
// entryEntity.slpAddress
|
||||
// )
|
||||
// NOTE: this.bch.getPSFTokenBalance , does not exist , should be created?
|
||||
|
||||
const psfBalance = 1
|
||||
|
||||
if (psfBalance < 10) {
|
||||
|
||||
@@ -598,7 +598,9 @@ class OfferUseCases {
|
||||
throw new Error('Could not calculate the amount of BCH offered in the Counter Offer')
|
||||
}
|
||||
const satsOut = this.adapters.wallet.bchWallet.bchjs.BitcoinCash.toSatoshi(txObj.vout[2].value)
|
||||
|
||||
const hasRequiredAmount = satsOut === satsToReceive
|
||||
|
||||
if (!hasRequiredAmount) {
|
||||
throw new Error(`The Counter Offer has an output of ${satsOut}, which does not match the required ${satsToReceive} in the Offer.`)
|
||||
}
|
||||
@@ -615,25 +617,25 @@ class OfferUseCases {
|
||||
|
||||
// Ensure the 3rd output (vout=2) is going to the maker address specified
|
||||
// in the Offer.
|
||||
|
||||
const addrInCounterOffer = txObj.vout[2].scriptPubKey.addresses[0]
|
||||
const makerAddr = orderData.makerAddr
|
||||
const hasCorrectAddr = makerAddr === addrInCounterOffer
|
||||
|
||||
if (!hasCorrectAddr) {
|
||||
throw new Error(`The Counter Offer has an output address of ${addrInCounterOffer}, which does not match the Maker address of ${makerAddr} in the Offer.`)
|
||||
}
|
||||
|
||||
// Ensure the 4th output (vout=3) is going to the operator address specified in the Offer.
|
||||
// NOTE: This is the operator of the bch-dex intance, NOT the seller of the token.
|
||||
const operatorAddr = orderData.operatorAddress
|
||||
|
||||
const hasCorrectOperatorAddr = operatorAddr === txObj.vout[3].scriptPubKey.addresses[0]
|
||||
if (!hasCorrectOperatorAddr) {
|
||||
throw new Error(`The Counter Offer has an output address of ${txObj.vout[3].scriptPubKey.addresses[0]}, which does not match the Operator address of ${operatorAddr} in the Offer.`)
|
||||
}
|
||||
|
||||
// Ensure the 4th output (vout=3) contains the required amount of BCH.
|
||||
const operatorSatsToReceive = Math.ceil(orderData.numTokens * parseInt(orderData.rateInBaseUnit))
|
||||
if (isNaN(operatorSatsToReceive)) {
|
||||
throw new Error('Could not calculate the amount of BCH offered in the Counter Offer')
|
||||
}
|
||||
const operatorSatsOut = this.adapters.wallet.bchWallet.bchjs.BitcoinCash.toSatoshi(txObj.vout[3].value)
|
||||
let estimatedOperatorFee = Math.floor(txObj.vout[3].value * orderData.operatorPercentage / 100)
|
||||
if (estimatedOperatorFee < 546) estimatedOperatorFee = 546
|
||||
@@ -814,7 +816,7 @@ class OfferUseCases {
|
||||
try {
|
||||
// Retrieve offers array.
|
||||
const offers = await this.adapters.nostr.read()
|
||||
// console.log('offers: ', offers)
|
||||
console.log('offers: ', offers)
|
||||
|
||||
for (let i = 0; i < offers.length; i++) {
|
||||
try {
|
||||
@@ -825,7 +827,7 @@ class OfferUseCases {
|
||||
|
||||
// Append the Nostr Event ID to the offer object
|
||||
offerObj.data.nostrEventId = offer.eventId
|
||||
// console.log('loadOffers() offerObj: ', offerObj)
|
||||
console.log('loadOffers() offerObj: ', offerObj)
|
||||
|
||||
if (offerObj.data.dataType === 'offer') {
|
||||
// Try to create new offer
|
||||
|
||||
@@ -10,7 +10,7 @@ class smAccountUseCases {
|
||||
this.adapters = localConfig.adapters
|
||||
if (!this.adapters) {
|
||||
throw new Error(
|
||||
'Instance of adapters must be passed in when instantiating Order Use Cases library.'
|
||||
'Instance of adapters must be passed in when instantiating SM Account Use Cases library.'
|
||||
)
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ class smAccountUseCases {
|
||||
console.log('Checking for new Social Media Accounts...')
|
||||
|
||||
const messages = await this.adapters.nostr.readGlobalFeed()
|
||||
console.log('messages: ', messages)
|
||||
for (let i = 0; i < messages.length; i++) {
|
||||
const msg = messages[i]
|
||||
// const { content, id, tags, npub, pubkey } = msg
|
||||
@@ -122,6 +123,7 @@ class smAccountUseCases {
|
||||
const followerCnt = followList.length
|
||||
await SmAccount.updateOne({ _id: account._id }, { $set: { followerCnt } })
|
||||
}
|
||||
return true
|
||||
} catch (err) {
|
||||
console.error('Error in smAccount-use-cases.js/updateSmAccounts(): ', err)
|
||||
throw err
|
||||
|
||||
@@ -91,25 +91,143 @@ describe('#Offer-REST-Router', () => {
|
||||
// assert.equal(ctx.body.hash, 'testHash')
|
||||
})
|
||||
|
||||
// it('should catch and throw an error', async () => {
|
||||
// try {
|
||||
// ctx.request.body = {
|
||||
// offer: {}
|
||||
// }
|
||||
//
|
||||
// // Force an error
|
||||
// sandbox
|
||||
// .stub(uut.useCases.offer, 'createOffer')
|
||||
// .rejects(new Error('test error'))
|
||||
//
|
||||
// await uut.createOffer(ctx)
|
||||
//
|
||||
// assert.fail('Unexpected code path')
|
||||
// } catch (err) {
|
||||
// // console.log('err: ', err)
|
||||
// assert.include(err.message, 'test error')
|
||||
// }
|
||||
// })
|
||||
it('should catch and throw an error', async () => {
|
||||
try {
|
||||
ctx.request.body = {
|
||||
offer: {}
|
||||
}
|
||||
|
||||
// Force an error
|
||||
sandbox
|
||||
.stub(uut.useCases.offer, 'createOffer')
|
||||
.rejects(new Error('test error'))
|
||||
|
||||
await uut.createOffer(ctx)
|
||||
|
||||
assert.fail('Unexpected code path')
|
||||
} catch (err) {
|
||||
// console.log('err: ', err)
|
||||
assert.include(err.message, 'test error')
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('#listOffers', () => {
|
||||
it('should list offers', async () => {
|
||||
ctx.params = { page: 0 }
|
||||
sandbox.stub(uut.useCases.offer, 'listOffers').resolves([])
|
||||
await uut.listOffers(ctx)
|
||||
assert.isArray(ctx.body)
|
||||
})
|
||||
it('should catch and throw an error', async () => {
|
||||
try {
|
||||
ctx.params = { }
|
||||
sandbox
|
||||
.stub(uut.useCases.offer, 'listOffers')
|
||||
.throws(new Error('test error'))
|
||||
|
||||
await uut.listOffers(ctx)
|
||||
assert.fail('Unexpected code path')
|
||||
} catch (err) {
|
||||
assert.include(err.message, 'test error')
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('#listNftOffers', () => {
|
||||
it('should list nft offers', async () => {
|
||||
ctx.params = { page: 0 }
|
||||
sandbox.stub(uut.useCases.offer, 'listNftOffers').resolves([])
|
||||
await uut.listNftOffers(ctx)
|
||||
assert.isArray(ctx.body)
|
||||
})
|
||||
it('should catch and throw an error', async () => {
|
||||
try {
|
||||
ctx.params = { page: 0 }
|
||||
sandbox
|
||||
.stub(uut.useCases.offer, 'listNftOffers')
|
||||
.throws(new Error('test error'))
|
||||
|
||||
await uut.listNftOffers(ctx)
|
||||
assert.fail('Unexpected code path')
|
||||
} catch (err) {
|
||||
assert.include(err.message, 'test error')
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('#listFungibleOffers', () => {
|
||||
it('should list fungible offers', async () => {
|
||||
ctx.params = { page: 0 }
|
||||
sandbox.stub(uut.useCases.offer, 'listFungibleOffers').resolves([])
|
||||
await uut.listFungibleOffers(ctx)
|
||||
assert.isArray(ctx.body)
|
||||
})
|
||||
it('should catch and throw an error', async () => {
|
||||
try {
|
||||
ctx.params = { page: 0 }
|
||||
sandbox
|
||||
.stub(uut.useCases.offer, 'listFungibleOffers')
|
||||
.throws(new Error('test error'))
|
||||
|
||||
await uut.listFungibleOffers(ctx)
|
||||
assert.fail('Unexpected code path')
|
||||
} catch (err) {
|
||||
assert.include(err.message, 'test error')
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('#takeOffer', () => {
|
||||
it('should take an offer', async () => {
|
||||
ctx.request.body = {
|
||||
nostrEventId: 'testEventId'
|
||||
}
|
||||
|
||||
sandbox.stub(uut.useCases.offer, 'takeOffer').resolves({ eventId: 'testEventId', noteId: 'testNoteId' })
|
||||
await uut.takeOffer(ctx)
|
||||
assert.isObject(ctx.body)
|
||||
assert.property(ctx.body, 'eventId')
|
||||
assert.property(ctx.body, 'noteId')
|
||||
})
|
||||
it('should catch and throw an error', async () => {
|
||||
try {
|
||||
ctx.request.body = {
|
||||
nostrEventId: 'testEventId'
|
||||
}
|
||||
|
||||
sandbox
|
||||
.stub(uut.useCases.offer, 'takeOffer')
|
||||
.throws(new Error('test error'))
|
||||
|
||||
await uut.takeOffer(ctx)
|
||||
assert.fail('Unexpected code path')
|
||||
} catch (err) {
|
||||
assert.include(err.message, 'test error')
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('#listOffersByAddress', () => {
|
||||
it('should list offers by address', async () => {
|
||||
ctx.params = { addr: 'testAddress' }
|
||||
sandbox.stub(uut.useCases.offer, 'listOffersByAddress').resolves([])
|
||||
await uut.listOffersByAddress(ctx)
|
||||
assert.isArray(ctx.body)
|
||||
})
|
||||
it('should catch and throw an error', async () => {
|
||||
try {
|
||||
ctx.params = { addr: 'testAddress' }
|
||||
sandbox
|
||||
.stub(uut.useCases.offer, 'listOffersByAddress')
|
||||
.throws(new Error('test error'))
|
||||
|
||||
await uut.listOffersByAddress(ctx)
|
||||
assert.fail('Unexpected code path')
|
||||
} catch (err) {
|
||||
assert.include(err.message, 'test error')
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('#handleError', () => {
|
||||
|
||||
@@ -101,7 +101,47 @@ describe('#Order-REST-Router', () => {
|
||||
}
|
||||
})
|
||||
})
|
||||
describe('#listOrders', () => {
|
||||
it('should list orders', async () => {
|
||||
ctx.params = { page: 0 }
|
||||
sandbox.stub(uut.useCases.order, 'listOrders').resolves([])
|
||||
await uut.listOrders(ctx)
|
||||
assert.isArray(ctx.body)
|
||||
})
|
||||
it('should catch and throw an error', async () => {
|
||||
try {
|
||||
ctx.params = { page: 0 }
|
||||
sandbox.stub(uut.useCases.order, 'listOrders').throws(new Error('test error'))
|
||||
await uut.listOrders(ctx)
|
||||
assert.fail('Unexpected code path')
|
||||
} catch (err) {
|
||||
assert.include(err.message, 'test error')
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('#deleteOrder', () => {
|
||||
it('should delete an order', async () => {
|
||||
ctx.request.body = {
|
||||
nostrEventId: 'testEventId'
|
||||
}
|
||||
sandbox.stub(uut.useCases.order, 'deleteOrder').resolves('testTxid')
|
||||
await uut.deleteOrder(ctx)
|
||||
assert.equal(ctx.body.txid, 'testTxid')
|
||||
})
|
||||
it('should catch and throw an error', async () => {
|
||||
try {
|
||||
ctx.request.body = {
|
||||
nostrEventId: 'testEventId'
|
||||
}
|
||||
sandbox.stub(uut.useCases.order, 'deleteOrder').throws(new Error('test error'))
|
||||
await uut.deleteOrder(ctx)
|
||||
assert.fail('Unexpected code path')
|
||||
} catch (err) {
|
||||
assert.include(err.message, 'test error')
|
||||
}
|
||||
})
|
||||
})
|
||||
describe('#handleError', () => {
|
||||
it('should still throw error if there is no message', () => {
|
||||
try {
|
||||
|
||||
@@ -74,4 +74,13 @@ describe('#Order-REST-Router', () => {
|
||||
}
|
||||
})
|
||||
})
|
||||
describe('#createOrder', () => {
|
||||
it('should route to controller', async () => {
|
||||
sandbox.stub(uut.validators, 'ensureUser').resolves(true)
|
||||
const spy = sandbox.stub(uut.orderRESTController, 'createOrder').resolves(true)
|
||||
|
||||
await uut.createOrder()
|
||||
assert.isTrue(spy.calledOnce)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
Unit tests for the REST API handler for the /sm 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 P2WDBRESTController from '../../../../../src/controllers/rest-api/p2wdb/controller.js'
|
||||
|
||||
import { context as mockContext } from '../../../../unit/mocks/ctx-mock.js'
|
||||
|
||||
let uut
|
||||
let sandbox
|
||||
let ctx
|
||||
|
||||
describe('#P2WDB-REST-Router', () => {
|
||||
// const testUser = {}
|
||||
|
||||
beforeEach(() => {
|
||||
const useCases = new UseCasesMock()
|
||||
uut = new P2WDBRESTController({ adapters, useCases })
|
||||
|
||||
sandbox = sinon.createSandbox()
|
||||
|
||||
// Mock the context object.
|
||||
ctx = mockContext()
|
||||
ctx.params = { }
|
||||
})
|
||||
|
||||
afterEach(() => sandbox.restore())
|
||||
|
||||
describe('#constructor', () => {
|
||||
it('should throw an error if adapters are not passed in', () => {
|
||||
try {
|
||||
uut = new P2WDBRESTController()
|
||||
|
||||
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 P2WDBRESTController({ adapters })
|
||||
|
||||
assert.fail('Unexpected code path')
|
||||
} catch (err) {
|
||||
assert.include(
|
||||
err.message,
|
||||
'Instance of Use Cases library required when instantiating /p2wdb REST Controller.'
|
||||
)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('#routeWebhook', () => {
|
||||
it('should route the webhook for a new counter offer', async () => {
|
||||
ctx.request = {
|
||||
body: {
|
||||
data: {
|
||||
dataType: 'counter-offer'
|
||||
}
|
||||
}
|
||||
}
|
||||
sandbox.stub(uut.useCases.offer, 'acceptCounterOffer').resolves()
|
||||
|
||||
await uut.routeWebhook(ctx)
|
||||
|
||||
assert.isTrue(true)
|
||||
})
|
||||
it('should route the webhook for a new offer', async () => {
|
||||
ctx.request = {
|
||||
body: {
|
||||
data: {
|
||||
dataType: 'offer'
|
||||
}
|
||||
}
|
||||
}
|
||||
sandbox.stub(uut.useCases.offer, 'createOffer').resolves()
|
||||
|
||||
await uut.routeWebhook(ctx)
|
||||
|
||||
assert.isTrue(true)
|
||||
})
|
||||
it('should route the webhook flag', async () => {
|
||||
ctx.request = {
|
||||
body: {
|
||||
data: {
|
||||
dataType: 'flag'
|
||||
}
|
||||
}
|
||||
}
|
||||
sandbox.stub(uut.useCases.offer, 'flagOffer').resolves()
|
||||
|
||||
await uut.routeWebhook(ctx)
|
||||
|
||||
assert.isTrue(true)
|
||||
})
|
||||
it('should handle unknown data type', async () => {
|
||||
ctx.request = {
|
||||
body: {
|
||||
data: {
|
||||
dataType: 'unknown'
|
||||
}
|
||||
}
|
||||
}
|
||||
sandbox.stub(uut.useCases.offer, 'flagOffer').resolves()
|
||||
|
||||
await uut.routeWebhook(ctx)
|
||||
|
||||
assert.isTrue(true)
|
||||
})
|
||||
|
||||
it('should catch and throw an error', async () => {
|
||||
try {
|
||||
ctx.request.body = {}
|
||||
|
||||
await uut.routeWebhook(ctx)
|
||||
|
||||
assert.fail('Unexpected code path')
|
||||
} catch (err) {
|
||||
// console.log('err: ', err)
|
||||
assert.include(err.message, 'Cannot read properties of undefined')
|
||||
}
|
||||
})
|
||||
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')
|
||||
}
|
||||
})
|
||||
it('should catch error if message is provided', () => {
|
||||
try {
|
||||
const err = {
|
||||
status: 422,
|
||||
message: 'Unprocessable Entity'
|
||||
}
|
||||
|
||||
uut.handleError(ctx, err)
|
||||
} catch (err) {
|
||||
assert.include(err.message, 'Unprocessable Entity')
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
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 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 attached REST API controllers.'
|
||||
)
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,203 @@
|
||||
/*
|
||||
Unit tests for the REST API handler for the /sm 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 SmAccountRESTController from '../../../../../src/controllers/rest-api/smAccount/controller.js'
|
||||
|
||||
import { context as mockContext } from '../../../../unit/mocks/ctx-mock.js'
|
||||
|
||||
let uut
|
||||
let sandbox
|
||||
let ctx
|
||||
|
||||
describe('#SmAccount-REST-Router', () => {
|
||||
// const testUser = {}
|
||||
|
||||
beforeEach(() => {
|
||||
const useCases = new UseCasesMock()
|
||||
uut = new SmAccountRESTController({ adapters, useCases })
|
||||
|
||||
sandbox = sinon.createSandbox()
|
||||
|
||||
// Mock the context object.
|
||||
ctx = mockContext()
|
||||
ctx.params = { }
|
||||
})
|
||||
|
||||
afterEach(() => sandbox.restore())
|
||||
|
||||
describe('#constructor', () => {
|
||||
it('should throw an error if adapters are not passed in', () => {
|
||||
try {
|
||||
uut = new SmAccountRESTController()
|
||||
|
||||
assert.fail('Unexpected code path')
|
||||
} catch (err) {
|
||||
assert.include(
|
||||
err.message,
|
||||
'Instance of Adapters library required when instantiating /sm REST Controller.'
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
it('should throw an error if useCases are not passed in', () => {
|
||||
try {
|
||||
uut = new SmAccountRESTController({ adapters })
|
||||
|
||||
assert.fail('Unexpected code path')
|
||||
} catch (err) {
|
||||
assert.include(
|
||||
err.message,
|
||||
'Instance of Use Cases library required when instantiating /sm REST Controller.'
|
||||
)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('#listAccounts', () => {
|
||||
it('should list all social media accounts', async () => {
|
||||
ctx.params.page = 0
|
||||
|
||||
// Mock dependencies
|
||||
sandbox.stub(uut.useCases.smAccount, 'listAccounts').resolves([])
|
||||
|
||||
await uut.listAccounts(ctx)
|
||||
|
||||
assert.isArray(ctx.body)
|
||||
})
|
||||
|
||||
it('should catch and throw an error', async () => {
|
||||
try {
|
||||
ctx.params.page = 0
|
||||
|
||||
// Force an error
|
||||
sandbox.stub(uut.useCases.smAccount, 'listAccounts')
|
||||
.throws(new Error('test error'))
|
||||
|
||||
await uut.listAccounts(ctx)
|
||||
|
||||
assert.fail('Unexpected code path')
|
||||
} catch (err) {
|
||||
// console.log('err: ', err)
|
||||
assert.include(err.message, 'test error')
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('#getAccountByNpub', () => {
|
||||
it('should get a social media account by npub', async () => {
|
||||
sandbox.stub(uut.useCases.smAccount, 'getAccountByNpub').resolves({ npub: 'testNpub' })
|
||||
ctx.params.npub = 'testNpub'
|
||||
|
||||
await uut.getAccountByNpub(ctx)
|
||||
})
|
||||
it('should throw 400 if npub is not provided', async () => {
|
||||
try {
|
||||
await uut.getAccountByNpub(ctx)
|
||||
|
||||
assert.fail('Unexpected code path')
|
||||
} catch (err) {
|
||||
assert.include(err.message, 'Npub is required')
|
||||
}
|
||||
})
|
||||
it('should throw 400 if npub is not found', async () => {
|
||||
try {
|
||||
sandbox.stub(uut.useCases.smAccount, 'getAccountByNpub').resolves(null)
|
||||
ctx.params.npub = 'testNpub'
|
||||
await uut.getAccountByNpub(ctx)
|
||||
|
||||
assert.fail('Unexpected code path')
|
||||
} catch (err) {
|
||||
assert.include(err.message, 'Account not found')
|
||||
}
|
||||
})
|
||||
it('should catch and throw an error', async () => {
|
||||
try {
|
||||
sandbox.stub(uut.useCases.smAccount, 'getAccountByNpub').throws(new Error('test error'))
|
||||
ctx.params.npub = 'testNpub'
|
||||
|
||||
await uut.getAccountByNpub(ctx)
|
||||
|
||||
assert.fail('Unexpected code path')
|
||||
} catch (err) {
|
||||
assert.include(err.message, 'test error')
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('#getAccountByBchAddr', () => {
|
||||
it('should get a social media account by npub', async () => {
|
||||
sandbox.stub(uut.useCases.smAccount, 'getAccountByBchAddr').resolves({ bchAddr: 'testBchAddr' })
|
||||
ctx.params.bchAddr = 'testBchAddr'
|
||||
|
||||
await uut.getAccountByBchAddr(ctx)
|
||||
})
|
||||
|
||||
it('should throw 400 if bchAddr is not provided', async () => {
|
||||
try {
|
||||
await uut.getAccountByBchAddr(ctx)
|
||||
|
||||
assert.fail('Unexpected code path')
|
||||
} catch (err) {
|
||||
assert.include(err.message, 'BCH address is required')
|
||||
}
|
||||
})
|
||||
|
||||
it('should throw 400 if bchAddr is not found', async () => {
|
||||
try {
|
||||
sandbox.stub(uut.useCases.smAccount, 'getAccountByBchAddr').resolves(null)
|
||||
ctx.params.bchAddr = 'testBchAddr'
|
||||
await uut.getAccountByBchAddr(ctx)
|
||||
|
||||
assert.fail('Unexpected code path')
|
||||
} catch (err) {
|
||||
assert.include(err.message, 'Account not found')
|
||||
}
|
||||
})
|
||||
it('should catch and throw an error', async () => {
|
||||
try {
|
||||
sandbox.stub(uut.useCases.smAccount, 'getAccountByBchAddr').throws(new Error('test error'))
|
||||
ctx.params.bchAddr = 'testBchAddr'
|
||||
|
||||
await uut.getAccountByBchAddr(ctx)
|
||||
|
||||
assert.fail('Unexpected code path')
|
||||
} catch (err) {
|
||||
assert.include(err.message, 'test error')
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
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')
|
||||
}
|
||||
})
|
||||
it('should catch error if message is provided', () => {
|
||||
try {
|
||||
const err = {
|
||||
status: 422,
|
||||
message: 'Unprocessable Entity'
|
||||
}
|
||||
|
||||
uut.handleError(ctx, err)
|
||||
} catch (err) {
|
||||
assert.include(err.message, 'Unprocessable Entity')
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
Unit tests for the REST API handler for the /sm 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 SmAccountRouter from '../../../../../src/controllers/rest-api/smAccount/index.js'
|
||||
|
||||
let uut
|
||||
let sandbox
|
||||
// let ctx
|
||||
|
||||
// const mockContext = require('../../../../unit/mocks/ctx-mock').context
|
||||
|
||||
describe('#SmAccount-REST-Router', () => {
|
||||
// const testUser = {}
|
||||
|
||||
beforeEach(() => {
|
||||
const useCases = new UseCasesMock()
|
||||
uut = new SmAccountRouter({ 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 SmAccountRouter()
|
||||
|
||||
assert.fail('Unexpected code path')
|
||||
} catch (err) {
|
||||
assert.include(
|
||||
err.message,
|
||||
'Instance of Adapters library required when instantiating /sm REST Controller.'
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
it('should throw an error if useCases are not passed in', () => {
|
||||
try {
|
||||
uut = new SmAccountRouter({ adapters })
|
||||
|
||||
assert.fail('Unexpected code path')
|
||||
} catch (err) {
|
||||
assert.include(
|
||||
err.message,
|
||||
'Instance of Use Cases library required when instantiating /sm 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 attached REST API controllers.'
|
||||
)
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -108,25 +108,25 @@ describe('#Users-REST-Router', () => {
|
||||
})
|
||||
})
|
||||
|
||||
// describe('#getAll', () => {
|
||||
// it('should route to controller', async () => {
|
||||
// sandbox.stub(uut.validators, 'ensureUser').resolves(true)
|
||||
// const spy = sandbox.stub(uut.userRESTController, 'getUsers').resolves(true)
|
||||
describe('#getAll', () => {
|
||||
it('should route to controller', async () => {
|
||||
sandbox.stub(uut.validators, 'ensureAdmin').resolves(true)
|
||||
const spy = sandbox.stub(uut.userRESTController, 'getUsers').resolves(true)
|
||||
|
||||
// await uut.getAll()
|
||||
// assert.isTrue(spy.calledOnce)
|
||||
// })
|
||||
// })
|
||||
await uut.getAll()
|
||||
assert.isTrue(spy.calledOnce)
|
||||
})
|
||||
})
|
||||
|
||||
// describe('#getById', () => {
|
||||
// it('should route to controller', async () => {
|
||||
// sandbox.stub(uut.validators, 'ensureUser').resolves(true)
|
||||
// const spy = sandbox.stub(uut.userRESTController, 'getUser').resolves(true)
|
||||
describe('#getById', () => {
|
||||
it('should route to controller', async () => {
|
||||
sandbox.stub(uut.validators, 'ensureTargetUserOrAdmin').resolves(true)
|
||||
const spy = sandbox.stub(uut.userRESTController, 'getUser').resolves(true)
|
||||
|
||||
// await uut.getById()
|
||||
// assert.isTrue(spy.calledOnce)
|
||||
// })
|
||||
// })
|
||||
await uut.getById()
|
||||
assert.isTrue(spy.calledOnce)
|
||||
})
|
||||
})
|
||||
|
||||
describe('#updateUser', () => {
|
||||
it('should route to controller', async () => {
|
||||
|
||||
@@ -130,12 +130,12 @@ describe('#Timer-Controllers', () => {
|
||||
assert.equal(result, true)
|
||||
})
|
||||
|
||||
// it('should return false on error', async () => {
|
||||
// sandbox.stub(uut.useCases.usage, 'cleanUsage').throws(new Error('test error'))
|
||||
// const result = await uut.cleanUsage()
|
||||
it('should return false on error', async () => {
|
||||
sandbox.stub(uut.useCases.usage, 'cleanUsage').throws(new Error('test error'))
|
||||
const result = await uut.cleanUsage()
|
||||
|
||||
// assert.equal(result, false)
|
||||
// })
|
||||
assert.equal(result, false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('#backupUsage', () => {
|
||||
@@ -154,4 +154,37 @@ describe('#Timer-Controllers', () => {
|
||||
assert.equal(result, false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('#newSmAccounts', () => {
|
||||
it('should kick off the Use Case', async () => {
|
||||
const result = await uut.newSmAccounts()
|
||||
|
||||
assert.equal(result, true)
|
||||
})
|
||||
|
||||
it('should return false on error', async () => {
|
||||
sandbox.stub(uut.useCases.smAccount, 'checkForNewSmAccounts').throws(new Error('test error'))
|
||||
// sandbox.stub(uut.useCases.usage, 'saveUsage').throws(new Error('test error'))
|
||||
|
||||
const result = await uut.newSmAccounts()
|
||||
|
||||
assert.equal(result, false)
|
||||
})
|
||||
})
|
||||
describe('#updateSmAccounts', () => {
|
||||
it('should kick off the Use Case', async () => {
|
||||
const result = await uut.updateSmAccounts()
|
||||
|
||||
assert.equal(result, true)
|
||||
})
|
||||
|
||||
it('should return false on error', async () => {
|
||||
sandbox.stub(uut.useCases.smAccount, 'updateSmAccounts').throws(new Error('test error'))
|
||||
// sandbox.stub(uut.useCases.usage, 'saveUsage').throws(new Error('test error'))
|
||||
|
||||
const result = await uut.updateSmAccounts()
|
||||
|
||||
assert.equal(result, false)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -237,6 +237,113 @@ describe('#Offer-Entity', () => {
|
||||
}
|
||||
})
|
||||
|
||||
it('should throw an error if makerAddr is not included', () => {
|
||||
try {
|
||||
const offerData = {
|
||||
data: {
|
||||
messageType: 1,
|
||||
messageClass: 1,
|
||||
tokenId: 'fakeId',
|
||||
buyOrSell: 'buy',
|
||||
rateInBaseUnit: 1000,
|
||||
minUnitsToExchange: 350,
|
||||
numTokens: 1,
|
||||
utxoTxid: 'fakeTxid',
|
||||
utxoVout: 0,
|
||||
offerStatus: 'posted',
|
||||
operatorAddress: 'bitcoincash:qzl0d3gcqeypv4cy7gh8rgdszxa9vvm2acv7fqtd00',
|
||||
operatorPercentage: 10
|
||||
}
|
||||
}
|
||||
uut.validate(offerData)
|
||||
|
||||
assert.fail('Unexpected code path')
|
||||
} catch (err) {
|
||||
// console.log(err)
|
||||
assert.include(err.message, "Property 'makerAddr' must be a string.")
|
||||
}
|
||||
})
|
||||
it('should throw an error if makerAddr is not a string', () => {
|
||||
try {
|
||||
const offerData = {
|
||||
data: {
|
||||
messageType: 1,
|
||||
messageClass: 1,
|
||||
tokenId: 'fakeId',
|
||||
buyOrSell: 'buy',
|
||||
rateInBaseUnit: 1000,
|
||||
minUnitsToExchange: 350,
|
||||
numTokens: 1,
|
||||
utxoTxid: 'fakeTxid',
|
||||
utxoVout: 0,
|
||||
offerStatus: 'posted',
|
||||
makerAddr: 1234567890
|
||||
}
|
||||
}
|
||||
uut.validate(offerData)
|
||||
|
||||
assert.fail('Unexpected code path')
|
||||
} catch (err) {
|
||||
// console.log(err)
|
||||
assert.include(err.message, "Property 'makerAddr' must be a string.")
|
||||
}
|
||||
})
|
||||
|
||||
it('should throw an error if tokenType is not included', () => {
|
||||
try {
|
||||
const offerData = {
|
||||
data: {
|
||||
messageType: 1,
|
||||
messageClass: 1,
|
||||
tokenId: 'fakeId',
|
||||
buyOrSell: 'buy',
|
||||
rateInBaseUnit: 1000,
|
||||
minUnitsToExchange: 350,
|
||||
numTokens: 1,
|
||||
utxoTxid: 'fakeTxid',
|
||||
utxoVout: 0,
|
||||
offerStatus: 'posted',
|
||||
makerAddr: 'bitcoincash:qzl0d3gcqeypv4cy7gh8rgdszxa9vvm2acv7fqtd00',
|
||||
operatorAddress: 'bitcoincash:qzl0d3gcqeypv4cy7gh8rgdszxa9vvm2acv7fqtd00',
|
||||
operatorPercentage: 10
|
||||
}
|
||||
}
|
||||
uut.validate(offerData)
|
||||
|
||||
assert.fail('Unexpected code path')
|
||||
} catch (err) {
|
||||
// console.log(err)
|
||||
assert.include(err.message, "Property 'tokenType' must be a number.")
|
||||
}
|
||||
})
|
||||
|
||||
it('should throw an error if tokenType is not a number', () => {
|
||||
try {
|
||||
const offerData = {
|
||||
data: {
|
||||
messageType: 1,
|
||||
messageClass: 1,
|
||||
tokenId: 'fakeId',
|
||||
buyOrSell: 'buy',
|
||||
rateInBaseUnit: 1000,
|
||||
minUnitsToExchange: 350,
|
||||
numTokens: 1,
|
||||
utxoTxid: 'fakeTxid',
|
||||
utxoVout: 0,
|
||||
offerStatus: 'posted',
|
||||
makerAddr: 'bitcoincash:qzl0d3gcqeypv4cy7gh8rgdszxa9vvm2acv7fqtd00',
|
||||
tokenType: 'notANumber'
|
||||
}
|
||||
}
|
||||
uut.validate(offerData)
|
||||
|
||||
assert.fail('Unexpected code path')
|
||||
} catch (err) {
|
||||
// console.log(err)
|
||||
assert.include(err.message, "Property 'tokenType' must be a number.")
|
||||
}
|
||||
})
|
||||
|
||||
it('should throw an error if nostrEventId is not included', () => {
|
||||
try {
|
||||
const offerData = {
|
||||
@@ -267,6 +374,124 @@ describe('#Offer-Entity', () => {
|
||||
}
|
||||
})
|
||||
|
||||
it('should throw an error if operatorAddress is not included', () => {
|
||||
try {
|
||||
const offerData = {
|
||||
data: {
|
||||
messageType: 1,
|
||||
messageClass: 1,
|
||||
tokenId: 'fakeId',
|
||||
buyOrSell: 'buy',
|
||||
rateInBaseUnit: 1000,
|
||||
minUnitsToExchange: 350,
|
||||
numTokens: 1,
|
||||
utxoTxid: 'fakeTxid',
|
||||
utxoVout: 0,
|
||||
offerStatus: 'posted',
|
||||
makerAddr: 'bitcoincash:qzl0d3gcqeypv4cy7gh8rgdszxa9vvm2acv7fqtd00',
|
||||
tokenType: 1,
|
||||
nostrEventId: 'test',
|
||||
operatorPercentage: 10
|
||||
}
|
||||
}
|
||||
uut.validate(offerData)
|
||||
|
||||
assert.fail('Unexpected code path')
|
||||
} catch (err) {
|
||||
// console.log(err)
|
||||
assert.include(err.message, "Property 'operatorAddress' must be a string.")
|
||||
}
|
||||
})
|
||||
|
||||
it('should throw an error if operatorAddress is not a string', () => {
|
||||
try {
|
||||
const offerData = {
|
||||
data: {
|
||||
messageType: 1,
|
||||
messageClass: 1,
|
||||
tokenId: 'fakeId',
|
||||
buyOrSell: 'buy',
|
||||
rateInBaseUnit: 1000,
|
||||
minUnitsToExchange: 350,
|
||||
numTokens: 1,
|
||||
utxoTxid: 'fakeTxid',
|
||||
utxoVout: 0,
|
||||
offerStatus: 'posted',
|
||||
makerAddr: 'bitcoincash:qzl0d3gcqeypv4cy7gh8rgdszxa9vvm2acv7fqtd00',
|
||||
tokenType: 1,
|
||||
nostrEventId: 'test',
|
||||
operatorAddress: 1234567890,
|
||||
operatorPercentage: 10
|
||||
}
|
||||
}
|
||||
uut.validate(offerData)
|
||||
|
||||
assert.fail('Unexpected code path')
|
||||
} catch (err) {
|
||||
// console.log(err)
|
||||
assert.include(err.message, "Property 'operatorAddress' must be a string.")
|
||||
}
|
||||
})
|
||||
|
||||
it('should throw an error if operatorPercentage is not included', () => {
|
||||
try {
|
||||
const offerData = {
|
||||
data: {
|
||||
messageType: 1,
|
||||
messageClass: 1,
|
||||
tokenId: 'fakeId',
|
||||
buyOrSell: 'buy',
|
||||
rateInBaseUnit: 1000,
|
||||
minUnitsToExchange: 350,
|
||||
numTokens: 1,
|
||||
utxoTxid: 'fakeTxid',
|
||||
utxoVout: 0,
|
||||
offerStatus: 'posted',
|
||||
makerAddr: 'bitcoincash:qzl0d3gcqeypv4cy7gh8rgdszxa9vvm2acv7fqtd00',
|
||||
tokenType: 1,
|
||||
nostrEventId: 'test',
|
||||
operatorAddress: 'bitcoincash:qzl0d3gcqeypv4cy7gh8rgdszxa9vvm2acv7fqtd00'
|
||||
}
|
||||
}
|
||||
uut.validate(offerData)
|
||||
|
||||
assert.fail('Unexpected code path')
|
||||
} catch (err) {
|
||||
// console.log(err)
|
||||
assert.include(err.message, "Property 'operatorPercentage' must be a number.")
|
||||
}
|
||||
})
|
||||
|
||||
it('should throw an error if operatorPercentage is not a number', () => {
|
||||
try {
|
||||
const offerData = {
|
||||
data: {
|
||||
messageType: 1,
|
||||
messageClass: 1,
|
||||
tokenId: 'fakeId',
|
||||
buyOrSell: 'buy',
|
||||
rateInBaseUnit: 1000,
|
||||
minUnitsToExchange: 350,
|
||||
numTokens: 1,
|
||||
utxoTxid: 'fakeTxid',
|
||||
utxoVout: 0,
|
||||
offerStatus: 'posted',
|
||||
makerAddr: 'bitcoincash:qzl0d3gcqeypv4cy7gh8rgdszxa9vvm2acv7fqtd00',
|
||||
tokenType: 1,
|
||||
nostrEventId: 'test',
|
||||
operatorAddress: 'bitcoincash:qzl0d3gcqeypv4cy7gh8rgdszxa9vvm2acv7fqtd00',
|
||||
operatorPercentage: 'notANumber'
|
||||
}
|
||||
}
|
||||
uut.validate(offerData)
|
||||
|
||||
assert.fail('Unexpected code path')
|
||||
} catch (err) {
|
||||
// console.log(err)
|
||||
assert.include(err.message, "Property 'operatorPercentage' must be a number.")
|
||||
}
|
||||
})
|
||||
|
||||
it('should validate a new offer', () => {
|
||||
const offerObj = {
|
||||
appId: 'swapTest555',
|
||||
|
||||
@@ -130,5 +130,71 @@ describe('#Order-Entity', () => {
|
||||
assert.include(err.message, "Property 'numTokens' must be a number.")
|
||||
}
|
||||
})
|
||||
it('should throw an error if numTokens is not a number', () => {
|
||||
try {
|
||||
const data = {
|
||||
messageType: 1,
|
||||
messageClass: 1,
|
||||
tokenId: 'fakeId',
|
||||
buyOrSell: 'buy',
|
||||
rateInBaseUnit: 1000,
|
||||
minUnitsToExchange: 350,
|
||||
numTokens: 'notANumber'
|
||||
}
|
||||
uut.inputValidate(data)
|
||||
} catch (err) {
|
||||
// console.log(err)
|
||||
assert.include(err.message, "Property 'numTokens' must be a number.")
|
||||
}
|
||||
})
|
||||
it('should throw an error if makerAddress is not included', () => {
|
||||
try {
|
||||
const data = {
|
||||
messageType: 1,
|
||||
messageClass: 1,
|
||||
tokenId: 'fakeId',
|
||||
buyOrSell: 'buy',
|
||||
rateInBaseUnit: 1000,
|
||||
minUnitsToExchange: 350,
|
||||
numTokens: 1000
|
||||
}
|
||||
uut.inputValidate(data)
|
||||
} catch (err) {
|
||||
// console.log(err)
|
||||
assert.include(err.message, "Property 'makerAddr' must be a string.")
|
||||
}
|
||||
})
|
||||
it('should throw an error if makerAddress is not a string', () => {
|
||||
try {
|
||||
const data = {
|
||||
messageType: 1,
|
||||
messageClass: 1,
|
||||
tokenId: 'fakeId',
|
||||
buyOrSell: 'buy',
|
||||
rateInBaseUnit: 1000,
|
||||
minUnitsToExchange: 350,
|
||||
numTokens: 1000,
|
||||
makerAddr: 1234567890
|
||||
}
|
||||
uut.inputValidate(data)
|
||||
} catch (err) {
|
||||
// console.log(err)
|
||||
assert.include(err.message, "Property 'makerAddr' must be a string.")
|
||||
}
|
||||
})
|
||||
it('should return the correct data', () => {
|
||||
const data = {
|
||||
messageType: 1,
|
||||
messageClass: 1,
|
||||
tokenId: 'fakeId',
|
||||
buyOrSell: 'buy',
|
||||
rateInBaseUnit: 1000,
|
||||
minUnitsToExchange: 350,
|
||||
numTokens: 1000,
|
||||
makerAddr: 'fakeAddr'
|
||||
}
|
||||
const result = uut.inputValidate(data)
|
||||
assert.deepEqual(result, data)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -150,6 +150,18 @@ const localdb = {
|
||||
static find () {}
|
||||
static findOne () {}
|
||||
|
||||
async save () {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
SmAccount: class SmAccount {
|
||||
constructor (obj) {}
|
||||
|
||||
static findById () {}
|
||||
static find () {}
|
||||
static findOne () {}
|
||||
static updateOne () {}
|
||||
|
||||
async save () {
|
||||
return {}
|
||||
}
|
||||
@@ -202,7 +214,9 @@ const p2wdb = {
|
||||
const nostr = {
|
||||
post: async () => {return true },
|
||||
read: async () => { return true },
|
||||
eventId2note: () => { return 'testNoteId' }
|
||||
eventId2note: () => { return 'testNoteId' },
|
||||
readGlobalFeed: async () => { return [] },
|
||||
getFollowers: async () => { return [] }
|
||||
}
|
||||
|
||||
export default { ipfs, localdb, bch, wallet, p2wdb, bchjs, nostr}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
|
||||
|
||||
const messagesMock = [
|
||||
{
|
||||
content: JSON.stringify("I'm testing so hard!!!"),
|
||||
id: '1',
|
||||
tags: [['u', 'bitcoincash:qzy97glp47ut7tstm5g0tlrmkhk742795gkmyc7477']],
|
||||
npub: 'npub1234567890',
|
||||
pubkey: '1234567890',
|
||||
}
|
||||
]
|
||||
const smAccountsMock = [
|
||||
{
|
||||
npub: 'npub1234567890',
|
||||
bchAddr: 'bitcoincash:qzy97glp47ut7tstm5g0tlrmkhk742795gkmyc7477',
|
||||
pubkey: '1234567890',
|
||||
pfp: '',
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
followerCnt: 0,
|
||||
followingCnt: 0,
|
||||
posts: 0,
|
||||
likes: 0,
|
||||
comments: 0,
|
||||
reposts: 0
|
||||
},
|
||||
{
|
||||
npub: 'npub1234567891',
|
||||
bchAddr: 'bitcoincash:qzy97glp47ut7tstm5g0tlrmkhk742795gkmyc7478',
|
||||
pubkey: '1234567891',
|
||||
pfp: '',
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
followerCnt: 0,
|
||||
followingCnt: 0,
|
||||
posts: 0,
|
||||
likes: 0,
|
||||
comments: 0,
|
||||
reposts: 0
|
||||
}
|
||||
]
|
||||
export default { messagesMock, smAccountsMock }
|
||||
@@ -50,6 +50,27 @@ class Offer {
|
||||
async loadOffers(){
|
||||
|
||||
}
|
||||
async listOffers() {
|
||||
return []
|
||||
}
|
||||
async listNftOffers() {
|
||||
return []
|
||||
}
|
||||
async listFungibleOffers() {
|
||||
return []
|
||||
}
|
||||
async takeOffer() {
|
||||
return []
|
||||
}
|
||||
async listOffersByAddress() {
|
||||
return []
|
||||
}
|
||||
async flagOffer() {
|
||||
return {}
|
||||
}
|
||||
async acceptCounterOffer() {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
|
||||
class Order {
|
||||
@@ -59,6 +80,12 @@ class Order {
|
||||
async removeStaleOrders(){
|
||||
return {}
|
||||
}
|
||||
async listOrders() {
|
||||
return []
|
||||
}
|
||||
async deleteOrder() {
|
||||
return 'testTxid'
|
||||
}
|
||||
}
|
||||
|
||||
class UsageUseCaseMock {
|
||||
@@ -87,6 +114,24 @@ class UsageUseCaseMock {
|
||||
}
|
||||
}
|
||||
|
||||
class SmAccountUseCaseMock {
|
||||
async listAccounts() {
|
||||
return []
|
||||
}
|
||||
async getAccountByNpub() {
|
||||
return {}
|
||||
}
|
||||
async getAccountByBchAddr() {
|
||||
return {}
|
||||
}
|
||||
async checkForNewSmAccounts() {
|
||||
return true
|
||||
}
|
||||
async updateSmAccounts() {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
class UseCasesMock {
|
||||
constuctor(localConfig = {}) {
|
||||
// this.user = new UserUseCaseMock(localConfig)
|
||||
@@ -97,6 +142,7 @@ class UseCasesMock {
|
||||
offer = new Offer()
|
||||
order = new Order()
|
||||
usage = new UsageUseCaseMock()
|
||||
smAccount = new SmAccountUseCaseMock()
|
||||
}
|
||||
|
||||
export default UseCasesMock;
|
||||
|
||||
@@ -169,6 +169,7 @@ const deserealizeTxMockNoOperatorOut = {
|
||||
addresses: ['bitcoincash:qzy97glp47ut7tstm5g0tlrmkhk742795gkmyc7478']
|
||||
}
|
||||
},
|
||||
|
||||
//...
|
||||
]
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
// Public npm libraries
|
||||
import { assert } from 'chai'
|
||||
import sinon from 'sinon'
|
||||
import RetryQueue from '@chris.troutner/retry-queue'
|
||||
|
||||
// Local support libraries
|
||||
// const testUtils = require('../../utils/test-utils')
|
||||
@@ -30,6 +31,7 @@ describe('#offer-use-case', () => {
|
||||
|
||||
const order = new OrderUseCase({ adapters })
|
||||
uut = new OfferLib({ adapters, order })
|
||||
uut.retryQueue = new RetryQueue({ retryPeriod: 1000, attempts: 1 })
|
||||
})
|
||||
|
||||
afterEach(() => sandbox.restore())
|
||||
@@ -85,6 +87,15 @@ describe('#offer-use-case', () => {
|
||||
assert.isFalse(result)
|
||||
})
|
||||
|
||||
it('should return false if offer already processed', async () => {
|
||||
const offerObj = mockData.offerMockData
|
||||
uut.seenOffers.push(offerObj.data.nostrEventId)
|
||||
// Mock dependencies
|
||||
|
||||
const result = await uut.createOffer(offerObj)
|
||||
assert.isFalse(result)
|
||||
})
|
||||
|
||||
it('should return false for invalid utxo', async () => {
|
||||
const offerObj = mockData.offerMockData
|
||||
|
||||
@@ -334,6 +345,14 @@ describe('#offer-use-case', () => {
|
||||
const result = await uut.detectNsfw({ mutableData: 'ipfs://bafybeibqnsmmh6bkf2wwextetki4tly65z4r4qkrrpl5xwgvzdzjley6wm' })
|
||||
assert.isFalse(result)
|
||||
})
|
||||
it('should fetch alternative url', async () => {
|
||||
// Mock dependencies and force desired code path.
|
||||
sandbox.stub(uut.axios, 'get').onCall(0).throws(new Error())
|
||||
.onCall(1).resolves({ data: { nsfw: true } })
|
||||
|
||||
const result = await uut.detectNsfw({ mutableData: 'ipfs://bafybeibqnsmmh6bkf2wwextetki4tly65z4r4qkrrpl5xwgvzdzjley6wm' })
|
||||
assert.isTrue(result)
|
||||
})
|
||||
})
|
||||
|
||||
describe('#listOffers', () => {
|
||||
@@ -597,7 +616,7 @@ describe('#offer-use-case', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('#findOrderByEvent', () => {
|
||||
describe('#findOfferByEvent', () => {
|
||||
it('should throw an error if hash is not provided', async () => {
|
||||
try {
|
||||
await uut.findOfferByEvent()
|
||||
@@ -629,6 +648,29 @@ describe('#offer-use-case', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('#listOffersByAddress', () => {
|
||||
it('should throw an error if order is not found!', async () => {
|
||||
try {
|
||||
// Mock dependencies
|
||||
sandbox.stub(uut.OfferModel, 'find').throws(new Error('test error'))
|
||||
|
||||
await uut.listOffersByAddress('eventId')
|
||||
|
||||
assert.fail('unexpected code path')
|
||||
} catch (err) {
|
||||
assert.include(err.message, 'test error')
|
||||
}
|
||||
})
|
||||
|
||||
it('should return offer by eventId', async () => {
|
||||
// Mock dependencies
|
||||
sandbox.stub(uut.OfferModel, 'find').resolves([])
|
||||
|
||||
const result = await uut.listOffersByAddress()
|
||||
assert.isArray(result)
|
||||
})
|
||||
})
|
||||
|
||||
describe('#flagOffer', () => {
|
||||
it('should throw an error if input is not provided', async () => {
|
||||
try {
|
||||
@@ -687,23 +729,84 @@ describe('#offer-use-case', () => {
|
||||
|
||||
it('should skip internal function errors ', async () => {
|
||||
// Mock dependencies
|
||||
sandbox.stub(uut.adapters.nostr, 'read').resolves([mockData.offerMockData])
|
||||
const nostrReadMock = [{ content: JSON.stringify(mockData.offerMockData) }]
|
||||
sandbox.stub(uut.adapters.nostr, 'read').resolves(nostrReadMock)
|
||||
|
||||
await uut.loadOffers()
|
||||
})
|
||||
|
||||
it('should review and load offers', async () => {
|
||||
it('should createOffer ', async () => {
|
||||
mockData.offerMockData.data.dataType = 'offer'
|
||||
// Mock dependencies
|
||||
sandbox.stub(uut.adapters.nostr, 'read').resolves([JSON.stringify(mockData.offerMockData)])
|
||||
const nostrReadMock = [{ content: JSON.stringify(mockData.offerMockData) }]
|
||||
sandbox.stub(uut.adapters.nostr, 'read').resolves(nostrReadMock)
|
||||
const spy = sandbox.stub(uut, 'createOffer').resolves(true)
|
||||
|
||||
await uut.loadOffers()
|
||||
assert.isTrue(spy.calledOnce)
|
||||
})
|
||||
it('should accept counter Offer ', async () => {
|
||||
mockData.offerMockData.data.dataType = 'counter-offer'
|
||||
// Mock dependencies
|
||||
const nostrReadMock = [{ content: JSON.stringify(mockData.offerMockData) }]
|
||||
sandbox.stub(uut.adapters.nostr, 'read').resolves(nostrReadMock)
|
||||
const spy = sandbox.stub(uut, 'acceptCounterOffer').resolves(true)
|
||||
|
||||
await uut.loadOffers()
|
||||
assert.isTrue(spy.calledOnce)
|
||||
})
|
||||
|
||||
it('should skip error inside loop', async () => {
|
||||
// Mock dependencies
|
||||
const nostrReadMock = [{ content: '' }]
|
||||
sandbox.stub(uut.adapters.nostr, 'read').resolves(nostrReadMock)
|
||||
await uut.loadOffers()
|
||||
})
|
||||
})
|
||||
|
||||
describe('#acceptCounterOffer', () => {
|
||||
it('should return false if order already processed', async () => {
|
||||
const offerObj = mockData.offerMockData
|
||||
uut.seenOffers.push(offerObj.data.nostrEventId)
|
||||
// Mock dependencies
|
||||
|
||||
const result = await uut.acceptCounterOffer(offerObj)
|
||||
assert.isFalse(result)
|
||||
})
|
||||
|
||||
it('should return if order is not found!', async () => {
|
||||
// Mock dependencies
|
||||
sandbox.stub(uut.orderUseCase, 'findOrderByEvent').throws(new Error('test error'))
|
||||
sandbox.stub(uut.orderUseCase, 'findOrderByUtxo').throws(new Error('test error'))
|
||||
|
||||
const result = await uut.acceptCounterOffer({ data: { /** .... */ } })
|
||||
assert.equal(result, 'N/A')
|
||||
})
|
||||
|
||||
it('should return if utxo cant be validated', async () => {
|
||||
// Mock dependencies
|
||||
const mock = Object.assign({}, mockData.offerMockData.data)
|
||||
sandbox.stub(uut.orderUseCase, 'findOrderByUtxo').resolves(mock)
|
||||
sandbox.stub(uut.adapters.wallet.bchWallet, 'utxoIsValid').throws(new Error('test error'))
|
||||
|
||||
const result = await uut.acceptCounterOffer({ data: { /** .... */ } })
|
||||
assert.equal(result, 'N/A')
|
||||
})
|
||||
|
||||
it('should handle axios error', async () => {
|
||||
// Mock dependencies
|
||||
const mock = Object.assign({}, mockData.offerMockData.data)
|
||||
const stubErr = new Error()
|
||||
stubErr.isAxiosError = true
|
||||
sandbox.stub(uut.orderUseCase, 'findOrderByUtxo').resolves(mock)
|
||||
sandbox.stub(uut.adapters.wallet.bchWallet, 'utxoIsValid').throws(stubErr)
|
||||
|
||||
const result = await uut.acceptCounterOffer({ data: { /** .... */ } })
|
||||
assert.equal(result, 'N/A')
|
||||
})
|
||||
it('should return if utxo is invalid', async () => {
|
||||
// Mock dependencies
|
||||
const mock = Object.assign({}, mockData.offerMockData.data)
|
||||
sandbox.stub(uut.orderUseCase, 'findOrderByUtxo').resolves(mock)
|
||||
sandbox.stub(uut.adapters.wallet.bchWallet, 'utxoIsValid').resolves(false)
|
||||
|
||||
const result = await uut.acceptCounterOffer({ data: { /** .... */ } })
|
||||
assert.equal(result, 'N/A')
|
||||
@@ -719,7 +822,7 @@ describe('#offer-use-case', () => {
|
||||
sandbox.stub(uut.orderUseCase, 'findOrderByEvent').resolves(mock)
|
||||
sandbox.stub(uut.orderUseCase, 'findOrderByUtxo').resolves(mock)
|
||||
|
||||
const result = await uut.acceptCounterOffer({ data: { /** .... */ } })
|
||||
const result = await uut.acceptCounterOffer({ data: {} })
|
||||
console.log('result: ', result)
|
||||
assert.fail('unexpected code path')
|
||||
} catch (err) {
|
||||
@@ -734,7 +837,6 @@ describe('#offer-use-case', () => {
|
||||
|
||||
// Mock dependencies
|
||||
sandbox.stub(uut.orderUseCase, 'findOrderByUtxo').resolves(mock)
|
||||
sandbox.stub(uut.orderUseCase, 'findOrderByEvent').resolves(mockData.offerMockData.data)
|
||||
sandbox.stub(uut.adapters.wallet.bchWallet.bchjs.BitcoinCash, 'toSatoshi').returns(0)
|
||||
sandbox.stub(uut.adapters.wallet, 'deseralizeTx').resolves(mockData.deserealizeTxMock)
|
||||
|
||||
@@ -754,7 +856,6 @@ describe('#offer-use-case', () => {
|
||||
mock.numTokens = 0
|
||||
|
||||
// Mock dependencies
|
||||
sandbox.stub(uut.orderUseCase, 'findOrderByEvent').resolves(mock)
|
||||
sandbox.stub(uut.orderUseCase, 'findOrderByUtxo').resolves(mock)
|
||||
sandbox.stub(uut.adapters.wallet.bchWallet.bchjs.BitcoinCash, 'toSatoshi').returns(0)
|
||||
|
||||
@@ -763,6 +864,27 @@ describe('#offer-use-case', () => {
|
||||
const result = await uut.acceptCounterOffer({ data: { /** .... */ } })
|
||||
assert.equal(result, 'N/A')
|
||||
})
|
||||
it('should skip transactions if operator address does not match', async () => {
|
||||
try {
|
||||
// Mock data
|
||||
const mock = Object.assign({}, mockData.offerMockData.data)
|
||||
mock.makerAddr = mockData.deserealizeTxMockNoOperatorOut.vout[2].scriptPubKey.addresses[0]
|
||||
mock.operatorAddress = 'bitcoincash:qzy97glp47ut7tstm5g0tlrmkhk742795gkmyc7477'
|
||||
mock.rateInBaseUnit = 0
|
||||
mock.numTokens = 0
|
||||
|
||||
// Mock dependencies
|
||||
sandbox.stub(uut.orderUseCase, 'findOrderByUtxo').resolves(mock)
|
||||
sandbox.stub(uut.adapters.wallet.bchWallet.bchjs.BitcoinCash, 'toSatoshi').returns(0)
|
||||
|
||||
sandbox.stub(uut.adapters.wallet, 'deseralizeTx').resolves(mockData.deserealizeTxMock)
|
||||
|
||||
await uut.acceptCounterOffer({ data: {} })
|
||||
assert.fail('unexpected code path')
|
||||
} catch (error) {
|
||||
assert.include(error.message, 'The Counter Offer has an output address of')
|
||||
}
|
||||
})
|
||||
|
||||
it('should handle error for wrong transaction output address', async () => {
|
||||
try {
|
||||
@@ -779,7 +901,7 @@ describe('#offer-use-case', () => {
|
||||
|
||||
sandbox.stub(uut.adapters.wallet, 'deseralizeTx').resolves(mockData.deserealizeTxMock)
|
||||
|
||||
await uut.acceptCounterOffer({ data: { /** .... */ } })
|
||||
await uut.acceptCounterOffer({ data: {} })
|
||||
assert.fail('unexpected code path')
|
||||
} catch (err) {
|
||||
assert.include(err.message, 'The Counter Offer has an output address of')
|
||||
@@ -787,21 +909,44 @@ describe('#offer-use-case', () => {
|
||||
}
|
||||
})
|
||||
|
||||
it('should return tx id', async () => {
|
||||
it('should handle error if operator sats to receive cant be calculated', async () => {
|
||||
// Mock data
|
||||
const mock = Object.assign({}, mockData.offerMockData.data)
|
||||
mock.makerAddr = mockData.deserealizeTxMock.vout[2].scriptPubKey.addresses[0] // Maker Address
|
||||
mock.makerAddr = mockData.deserealizeTxMock.vout[2].scriptPubKey.addresses[0]
|
||||
mock.operatorAddress = mockData.deserealizeTxMock.vout[3].scriptPubKey.addresses[0]
|
||||
mock.rateInBaseUnit = 0
|
||||
mock.numTokens = 0
|
||||
|
||||
// Mock dependencies
|
||||
sandbox.stub(uut.orderUseCase, 'findOrderByEvent').resolves(mock)
|
||||
sandbox.stub(uut.orderUseCase, 'findOrderByUtxo').resolves(mock)
|
||||
sandbox.stub(uut.adapters.wallet.bchWallet.bchjs.BitcoinCash, 'toSatoshi').returns(0)
|
||||
|
||||
sandbox.stub(uut.adapters.wallet, 'deseralizeTx').resolves(mockData.deserealizeTxMock)
|
||||
|
||||
const result = await uut.acceptCounterOffer({ data: {} })
|
||||
assert.equal(result, 'N/A')
|
||||
})
|
||||
|
||||
it('should return tx id', async () => {
|
||||
// Mock data
|
||||
const mock = Object.assign({}, mockData.offerMockData.data)
|
||||
mock.makerAddr = mockData.deserealizeTxMock.vout[2].scriptPubKey.addresses[0]
|
||||
mock.operatorAddress = mockData.deserealizeTxMock.vout[3].scriptPubKey.addresses[0]
|
||||
mock.rateInBaseUnit = 0
|
||||
mock.numTokens = 0
|
||||
|
||||
// Mock dependencies
|
||||
sandbox.stub(uut.orderUseCase, 'findOrderByEvent').resolves(mock)
|
||||
sandbox.stub(uut.orderUseCase, 'findOrderByUtxo').resolves(mock)
|
||||
sandbox.stub(uut.adapters.wallet.bchWallet.bchjs.BitcoinCash, 'toSatoshi').onCall(0).returns(0).onCall(1).returns(1000)
|
||||
sandbox.stub(uut.adapters.localdb.Users, 'findById').resolves({ mnemonic: 'test' })
|
||||
sandbox.stub(uut.adapters.wallet, 'deseralizeTx').resolves(mockData.deserealizeTxMock)
|
||||
|
||||
//
|
||||
const result = await uut.acceptCounterOffer({ data: { /** .... */ } })
|
||||
const result = await uut.acceptCounterOffer({ data: {} })
|
||||
assert.isString(result)
|
||||
assert.notEqual('N/A')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -158,6 +158,7 @@ describe('#order-use-case', () => {
|
||||
|
||||
describe('#createOrder', () => {
|
||||
it('should create an order and return the hash', async () => {
|
||||
uut.config.useFullStackCash = true
|
||||
const entryObj = {
|
||||
lokadId: 'SWP',
|
||||
messageType: 1,
|
||||
@@ -386,4 +387,55 @@ describe('#order-use-case', () => {
|
||||
assert.isString(result)
|
||||
})
|
||||
})
|
||||
|
||||
describe('#findOrderByUtxo', () => {
|
||||
it('should throw an error if data is not provided', async () => {
|
||||
try {
|
||||
await uut.findOrderByUtxo({})
|
||||
} catch (err) {
|
||||
assert.include(err.message, 'Cannot read properties of undefined')
|
||||
}
|
||||
})
|
||||
it('should throw an error if order is not found', async () => {
|
||||
try {
|
||||
sandbox.stub(uut.OrderModel, 'findOne').resolves(null)
|
||||
const offerData = {
|
||||
data: {
|
||||
utxoTxid: 'utxoTxid',
|
||||
utxoVout: 'utxoVout'
|
||||
}
|
||||
}
|
||||
await uut.findOrderByUtxo(offerData)
|
||||
assert.fail('unexpected code path')
|
||||
} catch (err) {
|
||||
assert.include(err.message, 'order not found')
|
||||
}
|
||||
})
|
||||
it('should throw an error if order event id is not found', async () => {
|
||||
try {
|
||||
sandbox.stub(uut.OrderModel, 'findOne').resolves({ nostrEventId: null })
|
||||
const offerData = {
|
||||
data: {
|
||||
utxoTxid: 'utxoTxid',
|
||||
utxoVout: 'utxoVout'
|
||||
}
|
||||
}
|
||||
await uut.findOrderByUtxo(offerData)
|
||||
assert.fail('unexpected code path')
|
||||
} catch (err) {
|
||||
assert.include(err.message, 'order not found')
|
||||
}
|
||||
})
|
||||
it('should return order by utxo', async () => {
|
||||
sandbox.stub(uut.OrderModel, 'findOne').resolves({ toObject: () => { return {} }, nostrEventId: 'nostrEventId' })
|
||||
const offerData = {
|
||||
data: {
|
||||
utxoTxid: 'utxoTxid',
|
||||
utxoVout: 'utxoVout'
|
||||
}
|
||||
}
|
||||
const result = await uut.findOrderByUtxo(offerData)
|
||||
assert.isObject(result)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
Unit tests for the SM Account Use Case library.
|
||||
*/
|
||||
|
||||
// Public npm libraries
|
||||
import { assert } from 'chai'
|
||||
import sinon from 'sinon'
|
||||
|
||||
// Unit under test (uut)
|
||||
import SMAccountLib from '../../../src/use-cases/smAccount-use-cases.js'
|
||||
import SMMock from '../mocks/social-media-mocks.js'
|
||||
// Local support libraries
|
||||
import adapters from '../mocks/adapters/index.js'
|
||||
|
||||
describe('#sm-account-use-case', () => {
|
||||
let uut
|
||||
let sandbox
|
||||
|
||||
before(async () => {
|
||||
// Delete all previous users in the database.
|
||||
// await testUtils.deleteAllUsers()
|
||||
})
|
||||
|
||||
beforeEach(() => {
|
||||
sandbox = sinon.createSandbox()
|
||||
|
||||
uut = new SMAccountLib({ adapters })
|
||||
})
|
||||
|
||||
afterEach(() => sandbox.restore())
|
||||
|
||||
describe('#constructor', () => {
|
||||
it('should throw an error if adapters are not passed in', () => {
|
||||
try {
|
||||
uut = new SMAccountLib()
|
||||
|
||||
assert.fail('Unexpected code path')
|
||||
console.log(uut) // linter
|
||||
} catch (err) {
|
||||
assert.include(
|
||||
err.message,
|
||||
'Instance of adapters must be passed in when instantiating SM Account Use Cases library.'
|
||||
)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('#checkForNewSmAccounts', () => {
|
||||
it('check for new SM accounts', async () => {
|
||||
// Mock dependencies
|
||||
sandbox.stub(uut.adapters.nostr, 'readGlobalFeed').resolves(SMMock.messagesMock)
|
||||
|
||||
const result = await uut.checkForNewSmAccounts()
|
||||
assert.isTrue(result)
|
||||
})
|
||||
it('should skip existing SM accounts', async () => {
|
||||
// Mock dependencies
|
||||
sandbox.stub(uut.adapters.localdb.SmAccount, 'findOne').resolves({ npub: SMMock.messagesMock[0].npub })
|
||||
sandbox.stub(uut.adapters.nostr, 'readGlobalFeed').resolves(SMMock.messagesMock)
|
||||
|
||||
const result = await uut.checkForNewSmAccounts()
|
||||
assert.isTrue(result)
|
||||
})
|
||||
it('should throw an error if the readGlobalFeed fails', async () => {
|
||||
// Mock dependencies
|
||||
sandbox.stub(uut.adapters.nostr, 'readGlobalFeed').rejects(new Error('Failed to read global feed'))
|
||||
|
||||
try {
|
||||
await uut.checkForNewSmAccounts()
|
||||
assert.fail('unexpected code path')
|
||||
} catch (err) {
|
||||
assert.include(err.message, 'Failed to read global feed')
|
||||
}
|
||||
})
|
||||
})
|
||||
describe('#listAccounts', () => {
|
||||
it('should return a list of SM accounts', async () => {
|
||||
// Mock dependencies
|
||||
sandbox.stub(uut.adapters.localdb.SmAccount, 'find').callsFake(() => {
|
||||
return {
|
||||
skip: () => {
|
||||
return {
|
||||
limit: () => {
|
||||
return SMMock.messagesMock
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const result = await uut.listAccounts()
|
||||
assert.isArray(result)
|
||||
})
|
||||
it('should throw an error if the find fails', async () => {
|
||||
// Mock dependencies
|
||||
sandbox.stub(uut.adapters.localdb.SmAccount, 'find').throws(new Error('Failed to find SM accounts'))
|
||||
|
||||
try {
|
||||
await uut.listAccounts()
|
||||
assert.fail('unexpected code path')
|
||||
} catch (err) {
|
||||
assert.include(err.message, 'Failed to find SM accounts')
|
||||
}
|
||||
})
|
||||
})
|
||||
describe('#getAccountByNpub', () => {
|
||||
it('should return a SM account by npub', async () => {
|
||||
// Mock dependencies
|
||||
sandbox.stub(uut.adapters.localdb.SmAccount, 'findOne').resolves(SMMock.messagesMock[0])
|
||||
|
||||
const result = await uut.getAccountByNpub(SMMock.messagesMock[0].npub)
|
||||
assert.isObject(result)
|
||||
})
|
||||
it('should catch error', async () => {
|
||||
// Mock dependencies
|
||||
sandbox.stub(uut.adapters.localdb.SmAccount, 'findOne').throws(new Error('Failed to find SM account by npub'))
|
||||
|
||||
try {
|
||||
await uut.getAccountByNpub(SMMock.messagesMock[0].npub)
|
||||
assert.fail('unexpected code path')
|
||||
} catch (err) {
|
||||
assert.include(err.message, 'Failed to find SM account by npub')
|
||||
}
|
||||
})
|
||||
})
|
||||
describe('#getAccountByBchAddr', () => {
|
||||
it('should return a SM account by bch addr', async () => {
|
||||
// Mock dependencies
|
||||
sandbox.stub(uut.adapters.localdb.SmAccount, 'findOne').resolves(SMMock.messagesMock[0])
|
||||
|
||||
const result = await uut.getAccountByBchAddr('bitcoincash:qzy97glp47ut7tstm5g0tlrmkhk742795gkmyc7477')
|
||||
assert.isObject(result)
|
||||
})
|
||||
it('should catch error', async () => {
|
||||
// Mock dependencies
|
||||
sandbox.stub(uut.adapters.localdb.SmAccount, 'findOne').throws(new Error('Failed to find SM account by bch addr'))
|
||||
|
||||
try {
|
||||
await uut.getAccountByBchAddr('bitcoincash:qzy97glp47ut7tstm5g0tlrmkhk742795gkmyc7477')
|
||||
assert.fail('unexpected code path')
|
||||
} catch (err) {
|
||||
assert.include(err.message, 'Failed to find SM account by bch addr')
|
||||
}
|
||||
})
|
||||
})
|
||||
describe('#updateSmAccounts', () => {
|
||||
it('should update the SM accounts', async () => {
|
||||
// Mock dependencies
|
||||
sandbox.stub(uut.adapters.localdb.SmAccount, 'find').resolves(SMMock.smAccountsMock)
|
||||
|
||||
const result = await uut.updateSmAccounts()
|
||||
assert.isTrue(result)
|
||||
})
|
||||
it('should catch error', async () => {
|
||||
// Mock dependencies
|
||||
sandbox.stub(uut.adapters.localdb.SmAccount, 'find').throws(new Error('Failed to find SM accounts'))
|
||||
|
||||
try {
|
||||
await uut.updateSmAccounts()
|
||||
assert.fail('unexpected code path')
|
||||
} catch (err) {
|
||||
assert.include(err.message, 'Failed to find SM accounts')
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user