mirror of
https://github.com/Permissionless-Software-Foundation/bch-dex.git
synced 2026-09-21 16:52:00 -07:00
feat(offer): Trigger createOffer() from Nostr topic
This commit is contained in:
@@ -34,7 +34,8 @@ const Offer = new mongoose.Schema({
|
||||
// SWaP Protocol Properties
|
||||
lokadId: { type: String },
|
||||
messageType: { type: Number },
|
||||
messageClass: { type: Number }
|
||||
messageClass: { type: Number },
|
||||
nostrEventId: { type: String } // Nostr Event Id.
|
||||
|
||||
})
|
||||
|
||||
|
||||
@@ -29,13 +29,12 @@ class TimerControllers {
|
||||
this.gcOrders = this.gcOrders.bind(this)
|
||||
this.gcOffers = this.gcOffers.bind(this)
|
||||
this.checkDupOffers = this.checkDupOffers.bind(this)
|
||||
|
||||
this.loadOffers = this.loadOffers.bind(this)
|
||||
// State
|
||||
this.gcOrdersInt = null
|
||||
this.gcOffersInt = null
|
||||
this.checkDupOffersInt = null
|
||||
|
||||
this.startTimers()
|
||||
this.loadOffersInt = null
|
||||
}
|
||||
|
||||
// Start all the time-based controllers.
|
||||
@@ -43,6 +42,8 @@ class TimerControllers {
|
||||
this.gcOrdersInt = setInterval(this.gcOrders, 60000 * 5)
|
||||
this.gcOffersInt = setInterval(this.gcOffers, 60000 * 5)
|
||||
this.checkDupOffersInt = setInterval(this.checkDupOffers, 60000 * 4.5)
|
||||
this.loadOffersInt = setInterval(this.loadOffers, 60000 * 2)
|
||||
return true
|
||||
}
|
||||
|
||||
stopTimers () {
|
||||
@@ -55,9 +56,11 @@ class TimerControllers {
|
||||
gcOrders () {
|
||||
try {
|
||||
this.useCases.order.removeStaleOrders()
|
||||
return true
|
||||
} catch (err) {
|
||||
// Do not throw an error. This is a top-level function.
|
||||
console.log('Error in timer-controllers.js/gcOrders(): ', err)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,9 +68,11 @@ class TimerControllers {
|
||||
gcOffers () {
|
||||
try {
|
||||
this.useCases.offer.removeStaleOffers()
|
||||
return true
|
||||
} catch (err) {
|
||||
// Do not throw an error. This is a top-level function.
|
||||
console.log('Error in timer-controllers.js/gcOffers(): ', err)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,9 +80,23 @@ class TimerControllers {
|
||||
checkDupOffers () {
|
||||
try {
|
||||
this.useCases.offer.removeDuplicateOffers()
|
||||
return true
|
||||
} catch (err) {
|
||||
// Do not throw an error. This is a top-level function.
|
||||
console.log('Error in timer-controllers.js/checkDupOffers(): ', err)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// Load offers From nostr .
|
||||
async loadOffers () {
|
||||
try {
|
||||
await this.useCases.offer.loadOffers()
|
||||
return true
|
||||
} catch (err) {
|
||||
// Do not throw an error. This is a top-level function.
|
||||
console.log('Error in timer-controllers.js/loadOffers(): ', err)
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ class OfferUseCases {
|
||||
this.orderUseCase = localConfig.order
|
||||
if (!this.orderUseCase) {
|
||||
throw new Error(
|
||||
'Instance of Offer Use Cases must be passed in when instantiating Offer Use Cases library.'
|
||||
'Instance of Order Use Cases must be passed in when instantiating Offer Use Cases library.'
|
||||
)
|
||||
}
|
||||
|
||||
@@ -50,17 +50,19 @@ class OfferUseCases {
|
||||
|
||||
// Bind 'this' object to functions
|
||||
this.detectNsfw = this.detectNsfw.bind(this)
|
||||
this.loadOffers = this.loadOffers.bind(this)
|
||||
}
|
||||
|
||||
// This method is called by the POST /offer REST API controller, which is
|
||||
// triggered by a P2WDB webhook.
|
||||
// <This method is called by the POST /offer REST API controller, which is
|
||||
// triggered by a P2WDB webhook. ( DEPRECATED)>
|
||||
// This method is called by timer controller to load offers fron nostr server
|
||||
async createOffer (offerObj) {
|
||||
try {
|
||||
console.log('Use Case createOffer(offerObj): ', offerObj)
|
||||
|
||||
// Return if Offer already exists in database with the same P2WDB CID.
|
||||
// Return if Offer already exists in database with the same utxo transaction id.
|
||||
try {
|
||||
await this.findOfferByHash(offerObj.hash)
|
||||
await this.findOfferByTxid(offerObj.data.utxoTxid)
|
||||
|
||||
console.log('Offer already found in local database.')
|
||||
return false
|
||||
@@ -71,9 +73,9 @@ class OfferUseCases {
|
||||
// Input Validation
|
||||
// TODO: This is a hack. Find a better way to protect against the corner-
|
||||
// case of counter-offers getting routed here.
|
||||
if (offerObj.data.dataType === 'counter-offer') {
|
||||
console.log('WARN: Counter Offer innappropriately routed to createOffer()')
|
||||
}
|
||||
// if (offerObj.data.dataType === 'counter-offer') {
|
||||
// console.log('WARN: Counter Offer innappropriately routed to createOffer()')
|
||||
// }
|
||||
|
||||
// Verify that UTXO in offer is unspent. If it is spent, then ignore the
|
||||
// offer.
|
||||
@@ -90,6 +92,9 @@ class OfferUseCases {
|
||||
// A new offer gets a status of 'posted'
|
||||
offerObj.data.offerStatus = 'posted'
|
||||
|
||||
// Set timestamp
|
||||
offerObj.timestamp = new Date().getTime()
|
||||
|
||||
const offerEntity = this.offerEntity.validate(offerObj)
|
||||
console.log('offerEntity: ', offerEntity)
|
||||
|
||||
@@ -117,7 +122,7 @@ class OfferUseCases {
|
||||
|
||||
return true
|
||||
} catch (err) {
|
||||
console.error('Error in createOffer()')
|
||||
console.error('Error in createOffer()', err.message)
|
||||
throw err
|
||||
}
|
||||
}
|
||||
@@ -140,7 +145,7 @@ class OfferUseCases {
|
||||
// Retrieve the mutable data from Filecoin/IPFS.
|
||||
// const url = `https://${cid}.ipfs.w3s.link/data.json`
|
||||
const url = `${this.config.ipfsGateway}${cid}/data.json`
|
||||
const result = await axios.get(url)
|
||||
const result = await this.axios.get(url)
|
||||
const mutableData = result.data
|
||||
console.log(`mutableData: ${JSON.stringify(mutableData, null, 2)}`)
|
||||
|
||||
@@ -207,11 +212,11 @@ class OfferUseCases {
|
||||
async listOffers (page = 0) {
|
||||
try {
|
||||
const data = await this.OfferModel.find({})
|
||||
// Sort entries so newest entries show first.
|
||||
// Sort entries so newest entries show first.
|
||||
.sort('-timestamp')
|
||||
// Skip to the start of the selected page.
|
||||
// Skip to the start of the selected page.
|
||||
.skip(page * DEFAULT_ENTRIES_PER_PAGE)
|
||||
// Only return 20 results.
|
||||
// Only return 20 results.
|
||||
.limit(DEFAULT_ENTRIES_PER_PAGE)
|
||||
|
||||
return data
|
||||
@@ -227,11 +232,11 @@ class OfferUseCases {
|
||||
displayCategory: { $ne: 'fungible' },
|
||||
nsfw
|
||||
})
|
||||
// Sort entries so newest entries show first.
|
||||
// Sort entries so newest entries show first.
|
||||
.sort('-timestamp')
|
||||
// Skip to the start of the selected page.
|
||||
// Skip to the start of the selected page.
|
||||
.skip(page * NFT_ENTRIES_PER_PAGE)
|
||||
// Only return 20 results.
|
||||
// Only return 20 results.
|
||||
.limit(NFT_ENTRIES_PER_PAGE)
|
||||
|
||||
// console.log('listNftOffers() returning this data: ', data)
|
||||
@@ -246,11 +251,11 @@ class OfferUseCases {
|
||||
async listFungibleOffers (page = 0) {
|
||||
try {
|
||||
const data = await this.OfferModel.find({ displayCategory: 'fungible' })
|
||||
// Sort entries so newest entries show first.
|
||||
// Sort entries so newest entries show first.
|
||||
.sort('-timestamp')
|
||||
// Skip to the start of the selected page.
|
||||
// Skip to the start of the selected page.
|
||||
.skip(page * FUNGIBLE_ENTRIES_PER_PAGE)
|
||||
// Only return 20 results.
|
||||
// Only return 20 results.
|
||||
.limit(FUNGIBLE_ENTRIES_PER_PAGE)
|
||||
|
||||
// console.log('listFungibleOffers() returning this data: ', data)
|
||||
@@ -398,7 +403,7 @@ class OfferUseCases {
|
||||
throw new Error('App wallet does not control enough BCH to purchase the tokens.')
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
} else {
|
||||
// Buy Offer
|
||||
throw new Error('Buy offers are not supported yet.')
|
||||
@@ -437,10 +442,30 @@ class OfferUseCases {
|
||||
// return offerObject
|
||||
// } catch (err) {
|
||||
// // console.error('Error in findOffer(): ', err)
|
||||
// throw err
|
||||
// throw errByHash
|
||||
// }
|
||||
}
|
||||
|
||||
async findOfferByTxid (utxoTxid) {
|
||||
try {
|
||||
// try {
|
||||
if (typeof utxoTxid !== 'string' || !utxoTxid) {
|
||||
throw new Error('utxoTxid must be a string')
|
||||
}
|
||||
|
||||
const offer = await this.OfferModel.findOne({ utxoTxid })
|
||||
|
||||
if (!offer) {
|
||||
throw new Error('offer not found')
|
||||
}
|
||||
|
||||
return offer
|
||||
} catch (error) {
|
||||
console.error('Error in use-cases/offer/findOfferByTxid(): ')
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
// This function is called by the P2WDB webhook REST API handler. When a
|
||||
// Counter Offer is passed to bch-dex by the P2WDB, the data is then passed
|
||||
// to this function. It does due dilligence on the Counter Offer, then signs
|
||||
@@ -627,6 +652,30 @@ class OfferUseCases {
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// Get offers data from nostr.
|
||||
async loadOffers () {
|
||||
try {
|
||||
// Retrieve offers array.
|
||||
const offers = await this.adapters.nostr.read()
|
||||
for (let i = 0; i < offers.length; i++) {
|
||||
try {
|
||||
const offer = offers[i]
|
||||
|
||||
// offer data
|
||||
const offerObj = JSON.parse(offer)
|
||||
|
||||
// Try to create new offer
|
||||
await this.createOffer(offerObj)
|
||||
} catch (error) {
|
||||
/* exit quietly */
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error in loadOffers(): ', error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default OfferUseCases
|
||||
|
||||
@@ -56,27 +56,70 @@ describe('#Timer-Controllers', () => {
|
||||
})
|
||||
})
|
||||
|
||||
// describe('#startTimers', () => {
|
||||
// it('should start the timers', () => {
|
||||
// const result = uut.startTimers()
|
||||
//
|
||||
// // uut.stopTimers()
|
||||
//
|
||||
// assert.equal(result, true)
|
||||
// })
|
||||
// })
|
||||
describe('#startTimers', () => {
|
||||
it('should start the timers', () => {
|
||||
const result = uut.startTimers()
|
||||
|
||||
// describe('#exampleTimerFunc', () => {
|
||||
// it('should kick off the Use Case', async () => {
|
||||
// const result = await uut.exampleTimerFunc()
|
||||
//
|
||||
// assert.equal(result, true)
|
||||
// })
|
||||
//
|
||||
// it('should return false on error', async () => {
|
||||
// const result = await uut.exampleTimerFunc(true)
|
||||
//
|
||||
// assert.equal(result, false)
|
||||
// })
|
||||
// })
|
||||
// uut.stopTimers()
|
||||
|
||||
assert.equal(result, true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('#gcOrders', () => {
|
||||
it('should kick off the Use Case', async () => {
|
||||
const result = await uut.gcOrders()
|
||||
|
||||
assert.equal(result, true)
|
||||
})
|
||||
|
||||
it('should return false on error', async () => {
|
||||
sandbox.stub(uut.useCases.order, 'removeStaleOrders').throws(new Error('test error'))
|
||||
const result = await uut.gcOrders()
|
||||
|
||||
assert.equal(result, false)
|
||||
})
|
||||
})
|
||||
describe('#gcOffers', () => {
|
||||
it('should kick off the Use Case', async () => {
|
||||
const result = await uut.gcOffers()
|
||||
|
||||
assert.equal(result, true)
|
||||
})
|
||||
|
||||
it('should return false on error', async () => {
|
||||
sandbox.stub(uut.useCases.offer, 'removeStaleOffers').throws(new Error('test error'))
|
||||
const result = await uut.gcOffers()
|
||||
|
||||
assert.equal(result, false)
|
||||
})
|
||||
})
|
||||
describe('#checkDupOffers', () => {
|
||||
it('should kick off the Use Case', async () => {
|
||||
const result = await uut.checkDupOffers()
|
||||
|
||||
assert.equal(result, true)
|
||||
})
|
||||
|
||||
it('should return false on error', async () => {
|
||||
sandbox.stub(uut.useCases.offer, 'removeDuplicateOffers').throws(new Error('test error'))
|
||||
const result = await uut.checkDupOffers()
|
||||
|
||||
assert.equal(result, false)
|
||||
})
|
||||
})
|
||||
describe('#loadOffers', () => {
|
||||
it('should kick off the Use Case', async () => {
|
||||
const result = await uut.loadOffers()
|
||||
|
||||
assert.equal(result, true)
|
||||
})
|
||||
|
||||
it('should return false on error', async () => {
|
||||
sandbox.stub(uut.useCases.offer, 'loadOffers').throws(new Error('test error'))
|
||||
const result = await uut.loadOffers()
|
||||
|
||||
assert.equal(result, false)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -41,12 +41,24 @@ class Offer {
|
||||
async createOffer() {
|
||||
return {}
|
||||
}
|
||||
async removeStaleOffers(){
|
||||
|
||||
}
|
||||
async removeDuplicateOffers(){
|
||||
|
||||
}
|
||||
async loadOffers(){
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class Order {
|
||||
async createOrder() {
|
||||
return {}
|
||||
}
|
||||
async removeStaleOrders(){
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class UseCasesMock {
|
||||
|
||||
@@ -126,11 +126,30 @@ const fungibleTokenData01 = {
|
||||
"mutableData": ""
|
||||
}
|
||||
|
||||
const offerMockData ={
|
||||
data: {
|
||||
messageType: 1,
|
||||
messageClass: 1,
|
||||
tokenId:
|
||||
'38e97c5d7d3585a2cbf3f9580c82ca33985f9cb0845d4dcce220cb709f9538b0',
|
||||
buyOrSell: 'sell',
|
||||
rateInBaseUnit: 1000,
|
||||
minUnitsToExchange: 10,
|
||||
numTokens: 0.02,
|
||||
utxoTxid:
|
||||
'241c06bf61384b8623477e419bf4779edbcc7e3bc862f0f179a9ed2967069b87',
|
||||
utxoVout: 0,
|
||||
makerAddr: 'address',
|
||||
tokenType: 1
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
nftOffer01,
|
||||
nftTokenData01,
|
||||
simpleNftOffer01,
|
||||
simpleNftTokenData01,
|
||||
fungibleOffer01,
|
||||
fungibleTokenData01
|
||||
fungibleTokenData01,
|
||||
offerMockData
|
||||
};
|
||||
|
||||
@@ -48,79 +48,67 @@ describe('#offer-use-case', () => {
|
||||
)
|
||||
}
|
||||
})
|
||||
it('should throw an error if order use cases are not passed in', () => {
|
||||
try {
|
||||
uut = new OfferLib({ adapters })
|
||||
|
||||
assert.fail('Unexpected code path')
|
||||
console.log(uut) // linter
|
||||
} catch (err) {
|
||||
assert.include(
|
||||
err.message,
|
||||
'Instance of Order Use Cases must be passed in when instantiating Offer Use Cases library.'
|
||||
)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('#createOffer', () => {
|
||||
// it('should ignore an offer if utxo has been spent', async () => {
|
||||
// const offerObj = {
|
||||
// appId: 'swapTest555',
|
||||
// data: {
|
||||
// messageType: 1,
|
||||
// messageClass: 1,
|
||||
// tokenId:
|
||||
// '38e97c5d7d3585a2cbf3f9580c82ca33985f9cb0845d4dcce220cb709f9538b0',
|
||||
// buyOrSell: 'sell',
|
||||
// rateInSats: 1000,
|
||||
// minSatsToExchange: 10,
|
||||
// numTokens: 0.02,
|
||||
// utxoTxid:
|
||||
// '241c06bf61384b8623477e419bf4779edbcc7e3bc862f0f179a9ed2967069b87',
|
||||
// utxoVout: 0
|
||||
// },
|
||||
// timestamp: '2021-09-20T17:54:26.395Z',
|
||||
// localTimeStamp: '9/20/2021, 10:54:26 AM',
|
||||
// txid: '46f50f2a0cf44e3ed70dfb0618ef3ebfee57aabcf229b5d2d17c07322b54a8d7',
|
||||
// hash: 'zdpuB2X25AZCKo3wpr4sSbw44vqPWJRqcxWQRHZccK5BdtoGD'
|
||||
// }
|
||||
//
|
||||
// // Mock dependencies
|
||||
// // sandbox.stub(uut.adapters.wallet.bchWallet, 'utxoIsValid').resolves(false)
|
||||
// sandbox.stub(uut.adapters.wallet.bchWallet, 'getTokenData').resolves({})
|
||||
// sandbox.stub(uut, 'categorizeToken').resolves('nft')
|
||||
// sandbox.stub(uut, 'detectNsfw').resolves(false)
|
||||
//
|
||||
// const result = await uut.createOffer(offerObj)
|
||||
// // console.log('result: ', result)
|
||||
//
|
||||
// assert.equal(result, false)
|
||||
// })
|
||||
it('should handle error', async () => {
|
||||
try {
|
||||
await uut.createOffer()
|
||||
assert.fail('unexpected code path')
|
||||
} catch (error) {
|
||||
assert.include(error.message, 'Cannot read properties of undefined')
|
||||
}
|
||||
})
|
||||
it('should return false if offer already exist', async () => {
|
||||
const offerObj = mockData.offerMockData
|
||||
|
||||
// it('should create an offer and return the hash', async () => {
|
||||
// const offerObj = {
|
||||
// appId: 'swapTest555',
|
||||
// data: {
|
||||
// messageType: 1,
|
||||
// messageClass: 1,
|
||||
// tokenId:
|
||||
// '38e97c5d7d3585a2cbf3f9580c82ca33985f9cb0845d4dcce220cb709f9538b0',
|
||||
// buyOrSell: 'sell',
|
||||
// rateInBaseUnit: 1000,
|
||||
// minUnitsToExchange: 10,
|
||||
// numTokens: 0.02,
|
||||
// utxoTxid:
|
||||
// '241c06bf61384b8623477e419bf4779edbcc7e3bc862f0f179a9ed2967069b87',
|
||||
// utxoVout: 0,
|
||||
// makerAddr: 'bitcoincash:qzl0d3gcqeypv4cy7gh8rgdszxa9vvm2acv7fqtd00',
|
||||
// ticker: 'TROUT',
|
||||
// tokenType: 1
|
||||
// },
|
||||
// timestamp: '2021-09-20T17:54:26.395Z',
|
||||
// localTimeStamp: '9/20/2021, 10:54:26 AM',
|
||||
// txid: '46f50f2a0cf44e3ed70dfb0618ef3ebfee57aabcf229b5d2d17c07322b54a8d7',
|
||||
// hash: 'zdpuB2X25AZCKo3wpr4sSbw44vqPWJRqcxWQRHZccK5BdtoGD'
|
||||
// }
|
||||
//
|
||||
// // Mock dependencies
|
||||
// // sandbox.stub(uut.adapters.wallet.bchWallet, 'utxoIsValid').resolves(true)
|
||||
// sandbox.stub(uut, 'categorizeToken').resolves('fungible')
|
||||
// sandbox.stub(uut.adapters.wallet.bchWallet, 'getTokenData').resolves({})
|
||||
// sandbox.stub(uut, 'detectNsfw').resolves(false)
|
||||
//
|
||||
// const result = await uut.createOffer(offerObj)
|
||||
// // console.log('result: ', result)
|
||||
//
|
||||
// assert.equal(result, true)
|
||||
// })
|
||||
// Mock dependencies
|
||||
// sandbox.stub(uut.adapters.wallet.bchWallet, 'utxoIsValid').resolves(false)
|
||||
sandbox.stub(uut, 'findOfferByTxid').resolves({})
|
||||
|
||||
const result = await uut.createOffer(offerObj)
|
||||
assert.isFalse(result)
|
||||
})
|
||||
it('should return false for invalid utxo', async () => {
|
||||
const offerObj = mockData.offerMockData
|
||||
|
||||
// Mock dependencies
|
||||
// sandbox.stub(uut.adapters.wallet.bchWallet, 'utxoIsValid').resolves(false)
|
||||
sandbox.stub(uut, 'findOfferByTxid').throws(new Error('offer not found'))
|
||||
sandbox.stub(uut.retryQueue, 'addToQueue').resolves(null)
|
||||
|
||||
const result = await uut.createOffer(offerObj)
|
||||
assert.isFalse(result)
|
||||
})
|
||||
|
||||
it('should create offer', async () => {
|
||||
const tokenDataMock = mockData.simpleNftTokenData01
|
||||
const offerObj = mockData.offerMockData
|
||||
|
||||
// Mock dependencies
|
||||
// sandbox.stub(uut.adapters.wallet.bchWallet, 'utxoIsValid').resolves(false)
|
||||
sandbox.stub(uut, 'findOfferByTxid').throws(new Error('offer not found'))
|
||||
sandbox.stub(uut.retryQueue, 'addToQueue')
|
||||
.onCall(0).resolves({}) // Utxo Status call
|
||||
.onCall(1).resolves(tokenDataMock) // Token Data call
|
||||
.onCall(2).resolves(false) // detectNsfw call
|
||||
|
||||
const result = await uut.createOffer(offerObj)
|
||||
assert.isTrue(result)
|
||||
})
|
||||
})
|
||||
|
||||
describe('#categorizeToken', () => {
|
||||
@@ -159,15 +147,28 @@ describe('#offer-use-case', () => {
|
||||
|
||||
assert.equal(result, 'fungible')
|
||||
})
|
||||
it('should unknow type', async () => {
|
||||
try {
|
||||
// Mock dependencies
|
||||
const offerData = mockData.fungibleOffer01
|
||||
const tokenData = { genesisData: {} }
|
||||
|
||||
await uut.categorizeToken(offerData, tokenData)
|
||||
|
||||
assert.fail('unexpected code path')
|
||||
} catch (error) {
|
||||
assert.include(error.message, 'Unknown token type:')
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('#removeDuplicateOffers', () => {
|
||||
it('should remove duplicate entries and return true', async () => {
|
||||
// Mock dependencies and force desired code path.
|
||||
sandbox.stub(uut.OfferModel, 'find').resolves([
|
||||
{ p2wdbHash: 'a', remove: async () => {} },
|
||||
{ p2wdbHash: 'a', remove: async () => {} },
|
||||
{ p2wdbHash: 'b', remove: async () => {} }
|
||||
{ p2wdbHash: 'a', remove: async () => { } },
|
||||
{ p2wdbHash: 'a', remove: async () => { } },
|
||||
{ p2wdbHash: 'b', remove: async () => { } }
|
||||
])
|
||||
// sandbox.stub(uut.OfferModel, 'remove').resolves()
|
||||
|
||||
@@ -180,8 +181,8 @@ describe('#offer-use-case', () => {
|
||||
it('should return false if there are no duplicate entries', async () => {
|
||||
// Mock dependencies and force desired code path.
|
||||
sandbox.stub(uut.OfferModel, 'find').resolves([
|
||||
{ p2wdbHash: 'a', remove: async () => {} },
|
||||
{ p2wdbHash: 'b', remove: async () => {} }
|
||||
{ p2wdbHash: 'a', remove: async () => { } },
|
||||
{ p2wdbHash: 'b', remove: async () => { } }
|
||||
])
|
||||
// sandbox.stub(uut.OfferModel, 'remove').resolves()
|
||||
|
||||
@@ -191,4 +192,68 @@ describe('#offer-use-case', () => {
|
||||
assert.equal(result, false)
|
||||
})
|
||||
})
|
||||
describe('#findOfferByTxid', () => {
|
||||
it('should throw an error if input is not provided', async () => {
|
||||
try {
|
||||
await uut.findOfferByTxid()
|
||||
assert.fail('unexpected code path')
|
||||
} catch (error) {
|
||||
assert.equal(error.message, 'utxoTxid must be a string')
|
||||
}
|
||||
})
|
||||
it('should throw an error if offer is not found', async () => {
|
||||
try {
|
||||
// Mock dependencies and force desired code path.
|
||||
sandbox.stub(uut.OfferModel, 'findOne').resolves(null)
|
||||
|
||||
await uut.findOfferByTxid('241c06bf61384b8623477e419bf4779edbcc7e3bc862f0f179a9ed2967069b87')
|
||||
assert.fail('unexpected code path')
|
||||
} catch (error) {
|
||||
assert.equal(error.message, 'offer not found')
|
||||
}
|
||||
})
|
||||
|
||||
it('should return offer', async () => {
|
||||
// Mock dependencies and force desired code path.
|
||||
sandbox.stub(uut.OfferModel, 'findOne').resolves(mockData.nftOffer01)
|
||||
|
||||
const result = await uut.findOfferByTxid('241c06bf61384b8623477e419bf4779edbcc7e3bc862f0f179a9ed2967069b87')
|
||||
assert.isObject(result)
|
||||
})
|
||||
})
|
||||
describe('#detectNsfw', () => {
|
||||
it('should return false for wrong cid format', async () => {
|
||||
const result = await uut.detectNsfw({ mutableData: '' })
|
||||
assert.isFalse(result)
|
||||
})
|
||||
|
||||
it('should return true if nft boolean detected', async () => {
|
||||
// Mock dependencies and force desired code path.
|
||||
sandbox.stub(uut.axios, 'get').resolves({ data: { nsfw: true } })
|
||||
|
||||
const result = await uut.detectNsfw({ mutableData: 'ipfs://bafybeibqnsmmh6bkf2wwextetki4tly65z4r4qkrrpl5xwgvzdzjley6wm' })
|
||||
assert.isTrue(result)
|
||||
})
|
||||
it('should return true if nft string detected', async () => {
|
||||
// Mock dependencies and force desired code path.
|
||||
sandbox.stub(uut.axios, 'get').resolves({ data: { nsfw: 'true' } })
|
||||
|
||||
const result = await uut.detectNsfw({ mutableData: 'ipfs://bafybeibqnsmmh6bkf2wwextetki4tly65z4r4qkrrpl5xwgvzdzjley6wm' })
|
||||
assert.isTrue(result)
|
||||
})
|
||||
it('should return false if nfsw property does not exist', async () => {
|
||||
// Mock dependencies and force desired code path.
|
||||
sandbox.stub(uut.axios, 'get').resolves({ data: {} })
|
||||
|
||||
const result = await uut.detectNsfw({ mutableData: 'ipfs://bafybeibqnsmmh6bkf2wwextetki4tly65z4r4qkrrpl5xwgvzdzjley6wm' })
|
||||
assert.isFalse(result)
|
||||
})
|
||||
it('should return false on error', async () => {
|
||||
// Mock dependencies and force desired code path.
|
||||
sandbox.stub(uut.axios, 'get').throws(new Error('test error'))
|
||||
|
||||
const result = await uut.detectNsfw({ mutableData: 'ipfs://bafybeibqnsmmh6bkf2wwextetki4tly65z4r4qkrrpl5xwgvzdzjley6wm' })
|
||||
assert.isFalse(result)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user