feat(ecash): Minibits @minibits.cash Lightning address on Cashu receive #156
@@ -0,0 +1,66 @@
|
|||||||
|
// Real vue-i18n instance (unlike ReceiveBitcoinModal.test.ts, which mocks
|
||||||
|
// `t` to a no-op and so cannot catch a bad message string). Operator report
|
||||||
|
// (2026-09-08): clicking the Ecash tab closed the whole Receive modal, in
|
||||||
|
// both the browser and the Android companion's WebView. Root cause: vue-i18n
|
||||||
|
// treats a bare `@` as the start of "linked message" syntax — `en.json`'s
|
||||||
|
// `receiveBitcoin.lnAddressLabel` ("Your @minibits.cash address:") isn't
|
||||||
|
// valid linked-message syntax, so *compiling* that message throws a
|
||||||
|
// SyntaxError the instant it's first rendered (i.e. the moment the address
|
||||||
|
// loads), and the uncaught render-function error blanks the whole teleported
|
||||||
|
// modal. Fixed by escaping it as `{'@'}` (the same pattern already used for
|
||||||
|
// `settings.domainNamePlaceholder`). This test uses the real compiler so a
|
||||||
|
// future bad interpolation string in this component fails fast in `npm test`
|
||||||
|
// instead of only in a live browser.
|
||||||
|
import { flushPromises, mount } from '@vue/test-utils'
|
||||||
|
import { describe, expect, it, vi } from 'vitest'
|
||||||
|
import ReceiveBitcoinModal from '../ReceiveBitcoinModal.vue'
|
||||||
|
import { rpcClient } from '@/api/rpc-client'
|
||||||
|
import i18n from '@/i18n'
|
||||||
|
|
||||||
|
vi.mock('@/api/rpc-client', () => ({
|
||||||
|
rpcClient: { call: vi.fn() },
|
||||||
|
}))
|
||||||
|
|
||||||
|
vi.mock('@/composables/useLightningRequired', () => ({
|
||||||
|
useLightningRequired: () => ({
|
||||||
|
requireLightningReady: vi.fn().mockResolvedValue(true),
|
||||||
|
handleLightningFailure: vi.fn().mockReturnValue(false),
|
||||||
|
}),
|
||||||
|
}))
|
||||||
|
|
||||||
|
describe('ReceiveBitcoinModal — ecash tab with the real vue-i18n compiler', () => {
|
||||||
|
it('renders the Minibits address label without an uncaught render error', async () => {
|
||||||
|
vi.mocked(rpcClient.call).mockImplementation(async ({ method }: { method: string }) => {
|
||||||
|
if (method === 'wallet.ecash-lnaddress') {
|
||||||
|
return { address: 'someone@minibits.cash' } as never
|
||||||
|
}
|
||||||
|
return { claimed_count: 0, received_sats: 0, failed_count: 0 } as never
|
||||||
|
})
|
||||||
|
|
||||||
|
const wrapper = mount(ReceiveBitcoinModal, {
|
||||||
|
props: { show: true },
|
||||||
|
attachTo: document.body,
|
||||||
|
global: { plugins: [i18n] },
|
||||||
|
})
|
||||||
|
let captured: unknown = null
|
||||||
|
wrapper.vm.$.appContext.app.config.errorHandler = (err) => { captured = err }
|
||||||
|
await flushPromises()
|
||||||
|
|
||||||
|
const ecashTab = Array.from(document.body.querySelectorAll('button')).find((b) =>
|
||||||
|
b.textContent?.toLowerCase().includes('ecash'),
|
||||||
|
)
|
||||||
|
expect(ecashTab).toBeTruthy()
|
||||||
|
ecashTab!.dispatchEvent(new Event('click', { bubbles: true }))
|
||||||
|
await flushPromises()
|
||||||
|
await flushPromises()
|
||||||
|
|
||||||
|
expect(captured).toBeNull()
|
||||||
|
expect(wrapper.emitted('close')).toBeFalsy()
|
||||||
|
const dialog = document.body.querySelector('[role="dialog"]')
|
||||||
|
expect(dialog).toBeTruthy()
|
||||||
|
expect(dialog?.textContent).toContain('minibits.cash')
|
||||||
|
expect(dialog?.textContent).toContain('someone@minibits.cash')
|
||||||
|
|
||||||
|
wrapper.unmount()
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -777,7 +777,7 @@
|
|||||||
"pasteEcashToken": "Paste ecash token",
|
"pasteEcashToken": "Paste ecash token",
|
||||||
"lnAddressTitle": "Or share your Minibits Lightning address",
|
"lnAddressTitle": "Or share your Minibits Lightning address",
|
||||||
"lnAddressHint": "Anyone can pay you sats with any Lightning wallet by sending to this address — the sats arrive as ecash. Keep this screen open to receive them.",
|
"lnAddressHint": "Anyone can pay you sats with any Lightning wallet by sending to this address — the sats arrive as ecash. Keep this screen open to receive them.",
|
||||||
"lnAddressLabel": "Your @minibits.cash address:",
|
"lnAddressLabel": "Your {'@'}minibits.cash address:",
|
||||||
"lnAddressLoading": "Setting up your Lightning address…",
|
"lnAddressLoading": "Setting up your Lightning address…",
|
||||||
"lnAddressUnavailable": "Lightning address unavailable — you can still paste a token below.",
|
"lnAddressUnavailable": "Lightning address unavailable — you can still paste a token below.",
|
||||||
"lnAddressReceived": "Received {amount} sats to your Lightning address!",
|
"lnAddressReceived": "Received {amount} sats to your Lightning address!",
|
||||||
|
|||||||
@@ -758,7 +758,7 @@
|
|||||||
"pasteEcashToken": "Pegar token Ecash",
|
"pasteEcashToken": "Pegar token Ecash",
|
||||||
"lnAddressTitle": "O comparte tu direcci\u00f3n Lightning de Minibits",
|
"lnAddressTitle": "O comparte tu direcci\u00f3n Lightning de Minibits",
|
||||||
"lnAddressHint": "Cualquier persona puede pagarte sats con cualquier billetera Lightning enviando a esta direcci\u00f3n \u2014 los sats llegan como ecash. Mant\u00e9n esta pantalla abierta para recibirlos.",
|
"lnAddressHint": "Cualquier persona puede pagarte sats con cualquier billetera Lightning enviando a esta direcci\u00f3n \u2014 los sats llegan como ecash. Mant\u00e9n esta pantalla abierta para recibirlos.",
|
||||||
"lnAddressLabel": "Su direcci\u00f3n @minibits.cash:",
|
"lnAddressLabel": "Su direcci\u00f3n {'@'}minibits.cash:",
|
||||||
"lnAddressLoading": "Configurando su direcci\u00f3n Lightning\u2026",
|
"lnAddressLoading": "Configurando su direcci\u00f3n Lightning\u2026",
|
||||||
"lnAddressUnavailable": "Direcci\u00f3n Lightning no disponible \u2014 a\u00fan puede pegar un token abajo.",
|
"lnAddressUnavailable": "Direcci\u00f3n Lightning no disponible \u2014 a\u00fan puede pegar un token abajo.",
|
||||||
"lnAddressReceived": "\u00a1Recibi\u00f3 {amount} sats en su direcci\u00f3n Lightning!",
|
"lnAddressReceived": "\u00a1Recibi\u00f3 {amount} sats en su direcci\u00f3n Lightning!",
|
||||||
|
|||||||
Reference in New Issue
Block a user