2026-08-25 19:50:27 -07:00
|
|
|
/*
|
|
|
|
|
Unit tests for the Set Name Page behavior slice (src/services/set-name-page.js).
|
|
|
|
|
|
|
|
|
|
Expresses the observable behavior described by specs/set-name.feature:
|
|
|
|
|
- setting a valid name broadcasts an OP_RETURN with the Memo set-name prefix
|
|
|
|
|
and navigates the user to the account page.
|
|
|
|
|
- an empty name is rejected with a validation error; nothing is broadcast.
|
|
|
|
|
- an over-long name is rejected with a length error; nothing is broadcast.
|
|
|
|
|
- the byte counter counts down from the name limit.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
'use strict'
|
|
|
|
|
|
|
|
|
|
const test = require('node:test')
|
|
|
|
|
const assert = require('node:assert/strict')
|
|
|
|
|
|
|
|
|
|
const MemoSetName = require('../../src/services/memo-set-name')
|
|
|
|
|
const SetNamePage = require('../../src/services/set-name-page')
|
2026-08-25 20:30:24 -07:00
|
|
|
const { fakeProfiles } = require('../helpers/fake-profiles')
|
|
|
|
|
const { registerPageControllerTests } = require('./page-controller-helpers')
|
|
|
|
|
const { buildPage } = require('./page-build-helpers')
|
2026-08-25 19:50:27 -07:00
|
|
|
|
|
|
|
|
const MAX = MemoSetName.MAX_NAME_BYTES // 77
|
|
|
|
|
|
|
|
|
|
function build () {
|
2026-08-25 20:30:24 -07:00
|
|
|
return buildPage({
|
|
|
|
|
Page: SetNamePage,
|
|
|
|
|
Action: MemoSetName,
|
|
|
|
|
actionKey: 'memoSetName',
|
|
|
|
|
storeKey: 'profiles',
|
|
|
|
|
storeFactory: fakeProfiles
|
2026-08-25 19:50:27 -07:00
|
|
|
})
|
2026-08-25 20:30:24 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function buildBarePage (navigations) {
|
|
|
|
|
return new SetNamePage({ navigate: (p) => navigations.push(p) })
|
2026-08-25 19:50:27 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
test('SET_NAME_PATH and ACCOUNT_PATH constants', () => {
|
|
|
|
|
assert.equal(SetNamePage.SET_NAME_PATH, '/memo/set-name')
|
|
|
|
|
assert.equal(SetNamePage.ACCOUNT_PATH, '/account')
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
test('the byte counter counts down from the name limit for an empty name', () => {
|
|
|
|
|
const { page } = build()
|
|
|
|
|
page.setInput('')
|
|
|
|
|
assert.equal(page.remainingCount(), MAX)
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
test('the byte counter counts multi-byte characters by bytes, not characters', () => {
|
|
|
|
|
const { page } = build()
|
|
|
|
|
page.setInput('é')
|
|
|
|
|
assert.equal(page.remainingCount(), MAX - 2)
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
test('the byte counter reaches zero at the byte limit with multi-byte characters', () => {
|
|
|
|
|
const { page } = build()
|
|
|
|
|
page.setInput('é'.repeat(38))
|
|
|
|
|
assert.equal(page.remainingCount(), 1)
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
test('the byte counter counts down from the name limit for a short name', () => {
|
|
|
|
|
const { page } = build()
|
|
|
|
|
page.setInput('trout')
|
|
|
|
|
assert.equal(page.remainingCount(), MAX - 5)
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
test('the byte counter reaches zero at the name limit', () => {
|
|
|
|
|
const { page } = build()
|
|
|
|
|
page.setInput('x'.repeat(MAX))
|
|
|
|
|
assert.equal(page.remainingCount(), 0)
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
test('setting a valid name broadcasts the Memo set-name prefix and navigates to the account page', async () => {
|
2026-08-25 20:30:24 -07:00
|
|
|
const { wallet, store, page, navigations } = build()
|
2026-08-25 19:50:27 -07:00
|
|
|
page.setInput('trout')
|
|
|
|
|
|
|
|
|
|
const result = await page.submit()
|
|
|
|
|
|
|
|
|
|
assert.equal(result.ok, true)
|
|
|
|
|
assert.equal(page.settingName, false)
|
|
|
|
|
assert.equal(wallet.broadcasts.length, 1)
|
|
|
|
|
assert.equal(wallet.broadcasts[0].prefix, '6d01')
|
|
|
|
|
assert.equal(wallet.broadcasts[0].msg, 'trout')
|
|
|
|
|
assert.deepEqual(navigations, ['/account'])
|
2026-08-25 20:30:24 -07:00
|
|
|
assert.equal(store.getName(wallet.walletInfo.cashAddress), 'trout')
|
2026-08-25 19:50:27 -07:00
|
|
|
})
|
|
|
|
|
|
|
|
|
|
test('setting an empty name is rejected with a validation error and nothing is broadcast', async () => {
|
2026-08-25 20:30:24 -07:00
|
|
|
const { wallet, store, page, navigations } = build()
|
2026-08-25 19:50:27 -07:00
|
|
|
page.setInput('')
|
|
|
|
|
|
|
|
|
|
const result = await page.submit()
|
|
|
|
|
|
|
|
|
|
assert.equal(result.ok, false)
|
|
|
|
|
assert.equal(result.error, 'name_validation')
|
|
|
|
|
assert.equal(page.submitError, 'name_validation')
|
|
|
|
|
assert.equal(page.settingName, false)
|
|
|
|
|
assert.equal(wallet.broadcasts.length, 0)
|
2026-08-25 20:30:24 -07:00
|
|
|
assert.equal(store.getName(wallet.walletInfo.cashAddress), null)
|
2026-08-25 19:50:27 -07:00
|
|
|
assert.deepEqual(navigations, [])
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
test('setting an over-long name is rejected with a length error and nothing is broadcast', async () => {
|
2026-08-25 20:30:24 -07:00
|
|
|
const { wallet, store, page, navigations } = build()
|
2026-08-25 19:50:27 -07:00
|
|
|
page.setInput('y'.repeat(MAX + 1))
|
|
|
|
|
|
|
|
|
|
const result = await page.submit()
|
|
|
|
|
|
|
|
|
|
assert.equal(result.ok, false)
|
|
|
|
|
assert.equal(result.error, 'name_length')
|
|
|
|
|
assert.equal(page.submitError, 'name_length')
|
|
|
|
|
assert.equal(page.settingName, false)
|
|
|
|
|
assert.equal(wallet.broadcasts.length, 0)
|
2026-08-25 20:30:24 -07:00
|
|
|
assert.equal(store.getName(wallet.walletInfo.cashAddress), null)
|
2026-08-25 19:50:27 -07:00
|
|
|
assert.deepEqual(navigations, [])
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
test('the set name page starts idle (not setting name)', () => {
|
|
|
|
|
const { page } = build()
|
|
|
|
|
assert.equal(page.settingName, false)
|
|
|
|
|
})
|
|
|
|
|
|
2026-08-25 20:30:24 -07:00
|
|
|
registerPageControllerTests({
|
|
|
|
|
buildPage: build,
|
|
|
|
|
buildBarePage,
|
|
|
|
|
busyFlag: 'settingName',
|
|
|
|
|
prefix: '6d01'
|
2026-08-25 19:50:27 -07:00
|
|
|
})
|