mirror of
https://github.com/Permissionless-Software-Foundation/psf-memo.git
synced 2026-09-21 16:52:01 -07:00
Deduplicate the new like-result acceptance steps behind one render helper, and extract the bch.loping.net transaction link shared by the New Post result modal, the post options menu, and the like/tip result into a block-explorer service. Cover the LikeTipPage open/parse/handler failure branches and add property tests for the explorer URL, the LikeResult markup, and the result modal state machine. CRAP is at or below 5 with full coverage on the changed services; every changed/new plain source file scans at 21 or fewer mutation sites. The existing mutation manifests are left for the mutation tool to refresh. By refactorer.
187 lines
5.6 KiB
JavaScript
187 lines
5.6 KiB
JavaScript
/*
|
|
Unit tests for the like/tip page controller's broadcast result.
|
|
|
|
After a like is broadcast, the like/tip modal no longer closes
|
|
automatically. The controller records the successful result and keeps the
|
|
modal open so the modal can show a broadcast result (message, txid, and
|
|
explorer link). Dismissing the result closes the modal.
|
|
*/
|
|
|
|
'use strict'
|
|
|
|
const test = require('node:test')
|
|
const assert = require('node:assert/strict')
|
|
const LikeTipPage = require('../../src/services/like-tip-page')
|
|
const MemoLike = require('../../src/services/memo-like')
|
|
|
|
const MY_ADDRESS = 'bitcoincash:qqlrzp23w08434twmvr4fxw672whkjy0py26r63g3d'
|
|
const AUTHOR_ADDRESS = 'bitcoincash:qz7v6ztvzu2f2xd2ww8pnx9vwk0g4ncvfvavktg0jc'
|
|
const SAMPLE_TXID = '1111111111111111111111111111111111111111111111111111111111111111'
|
|
const LIKE_TXID = 'ab'.repeat(32)
|
|
|
|
function makeWallet () {
|
|
return {
|
|
walletInfo: { cashAddress: MY_ADDRESS },
|
|
utxos: [{ txid: 'utxo', value: 100000 }],
|
|
broadcasts: [],
|
|
async getUtxos () {
|
|
return this.utxos
|
|
},
|
|
async sendOpReturn (msg, prefix, bchOutput = []) {
|
|
this.broadcasts.push({ msg, prefix, bchOutput })
|
|
if (this.failWith) throw new Error(this.failWith)
|
|
return LIKE_TXID
|
|
}
|
|
}
|
|
}
|
|
|
|
function makePage (opts = {}) {
|
|
const wallet = makeWallet()
|
|
if (opts.failWith) wallet.failWith = opts.failWith
|
|
const memoLike = new MemoLike({ wallet })
|
|
return { wallet, page: new LikeTipPage({ memoLike }) }
|
|
}
|
|
|
|
test('the result modal starts hidden', () => {
|
|
const { page } = makePage()
|
|
|
|
assert.equal(page.showResultModal, false)
|
|
assert.equal(page.lastResult, null)
|
|
})
|
|
|
|
test('explorerUrl builds a bch.loping.net transaction link', () => {
|
|
assert.equal(
|
|
LikeTipPage.explorerUrl(SAMPLE_TXID),
|
|
`https://bch.loping.net/tx/${SAMPLE_TXID}`
|
|
)
|
|
assert.equal(LikeTipPage.explorerUrl(''), '')
|
|
|
|
const { page } = makePage()
|
|
assert.equal(page.explorerUrl(SAMPLE_TXID), LikeTipPage.explorerUrl(SAMPLE_TXID))
|
|
})
|
|
|
|
test('SUCCESS_MESSAGE announces the broadcast', () => {
|
|
assert.equal(typeof LikeTipPage.SUCCESS_MESSAGE, 'string')
|
|
assert.match(LikeTipPage.SUCCESS_MESSAGE, /broadcast/i)
|
|
})
|
|
|
|
test('a successful like keeps the modal open and shows the result', async () => {
|
|
const { page } = makePage()
|
|
page.open(SAMPLE_TXID, AUTHOR_ADDRESS)
|
|
page.setTip('')
|
|
|
|
const result = await page.submit()
|
|
|
|
assert.equal(result.ok, true)
|
|
assert.equal(result.txid, LIKE_TXID)
|
|
assert.equal(page.modalOpen, true)
|
|
assert.equal(page.showResultModal, true)
|
|
assert.equal(page.lastResult.txid, LIKE_TXID)
|
|
assert.equal(page.getBroadcastMessage(), LikeTipPage.SUCCESS_MESSAGE)
|
|
})
|
|
|
|
test('dismissing the result closes the like/tip modal', async () => {
|
|
const { page } = makePage()
|
|
page.open(SAMPLE_TXID, AUTHOR_ADDRESS)
|
|
page.setTip('')
|
|
await page.submit()
|
|
|
|
page.dismissResult()
|
|
|
|
assert.equal(page.showResultModal, false)
|
|
assert.equal(page.modalOpen, false)
|
|
})
|
|
|
|
test('opening the modal clears any previous result', async () => {
|
|
const { page } = makePage()
|
|
page.open(SAMPLE_TXID, AUTHOR_ADDRESS)
|
|
page.setTip('')
|
|
await page.submit()
|
|
|
|
page.open(SAMPLE_TXID, AUTHOR_ADDRESS)
|
|
|
|
assert.equal(page.showResultModal, false)
|
|
assert.equal(page.lastResult, null)
|
|
})
|
|
|
|
test('a validation failure stays on the form and opens no result', async () => {
|
|
const { page } = makePage()
|
|
page.open(SAMPLE_TXID, AUTHOR_ADDRESS)
|
|
page.setTip('abc')
|
|
|
|
const result = await page.submit()
|
|
|
|
assert.equal(result.ok, false)
|
|
assert.equal(result.error, 'like_validation')
|
|
assert.equal(page.modalOpen, true)
|
|
assert.equal(page.showResultModal, false)
|
|
assert.equal(page.lastResult.ok, false)
|
|
})
|
|
|
|
test('a broadcast failure stays on the form and opens no result', async () => {
|
|
const { page } = makePage({ failWith: 'Insufficient balance' })
|
|
page.open(SAMPLE_TXID, AUTHOR_ADDRESS)
|
|
page.setTip('')
|
|
|
|
const result = await page.submit()
|
|
|
|
assert.equal(result.ok, false)
|
|
assert.equal(result.error, 'broadcast')
|
|
assert.match(page.broadcastError, /Insufficient balance/)
|
|
assert.equal(page.modalOpen, true)
|
|
assert.equal(page.showResultModal, false)
|
|
assert.equal(page.getBroadcastMessage(), '')
|
|
})
|
|
|
|
test('open reports a validation error without a memo like handler', () => {
|
|
const page = new LikeTipPage({})
|
|
|
|
const result = page.open(SAMPLE_TXID, AUTHOR_ADDRESS)
|
|
|
|
assert.equal(result.ok, false)
|
|
assert.equal(result.error, 'like_validation')
|
|
assert.match(result.message, /memo like handler/)
|
|
assert.equal(page.modalOpen, true)
|
|
assert.equal(page.showResultModal, false)
|
|
})
|
|
|
|
test('open reports an empty-balance error below the dust limit', () => {
|
|
const wallet = makeWallet()
|
|
wallet.utxos = [{ txid: 'utxo', value: 100 }]
|
|
const memoLike = new MemoLike({ wallet })
|
|
const page = new LikeTipPage({ memoLike })
|
|
|
|
const result = page.open(SAMPLE_TXID, AUTHOR_ADDRESS)
|
|
|
|
assert.equal(result.ok, false)
|
|
assert.equal(result.error, 'like_empty_balance')
|
|
assert.match(page.broadcastError, /add BCH/)
|
|
assert.equal(page.showResultModal, false)
|
|
})
|
|
|
|
test('submit fails without a memo like handler', async () => {
|
|
const page = new LikeTipPage({})
|
|
page.setTip('')
|
|
|
|
const result = await page.submit()
|
|
|
|
assert.equal(result.ok, false)
|
|
assert.equal(result.error, 'broadcast')
|
|
assert.match(page.broadcastError, /memo like handler/)
|
|
assert.equal(page.showResultModal, false)
|
|
})
|
|
|
|
test('a like with a positive tip sends the tip to the author', async () => {
|
|
const { wallet, page } = makePage()
|
|
page.open(SAMPLE_TXID, AUTHOR_ADDRESS)
|
|
page.setTip('600')
|
|
|
|
const result = await page.submit()
|
|
|
|
assert.equal(result.ok, true)
|
|
assert.equal(wallet.broadcasts.length, 1)
|
|
assert.deepEqual(wallet.broadcasts[0].bchOutput, [
|
|
{ address: AUTHOR_ADDRESS, amountSat: 600 }
|
|
])
|
|
})
|