Fix tests and add placeholder tests for all packages

- Fix noffer.ts encodeUint64BE to use division instead of bit shifts
  (JS bitwise ops only work on 32-bit integers)
- Update noffer.test.ts to use amountSats instead of amountMsat
- Update client.test.ts to remove serviceUrl (no longer in config)
- Add decodeInvoice tests for different BOLT11 amount formats
- Add placeholder tests for @lamassu/cashu package
- Add placeholder tests for @lamassu/ui-shared package

All 43 tests now pass across 6 packages.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Patrick Mulligan 2026-01-23 06:22:18 -05:00
commit 92b0182523
5 changed files with 79 additions and 13 deletions

View file

@ -0,0 +1,17 @@
import { describe, it, expect } from 'vitest'
import { version } from '../index.js'
describe('@lamassu/cashu', () => {
describe('exports', () => {
it('should export version', () => {
expect(version).toBe('0.1.0')
})
})
// TODO: Add tests when cashu functionality is implemented
describe('placeholder', () => {
it('should pass placeholder test', () => {
expect(true).toBe(true)
})
})
})

View file

@ -22,7 +22,7 @@ describe('noffer encoding/decoding', () => {
const offer: CLINKOffer = { const offer: CLINKOffer = {
...sampleOffer, ...sampleOffer,
priceType: 'fixed', priceType: 'fixed',
amountMsat: 1000000, amountSats: 1000,
} }
const noffer = encodeNoffer(offer) const noffer = encodeNoffer(offer)
@ -45,14 +45,14 @@ describe('noffer encoding/decoding', () => {
const offer: CLINKOffer = { const offer: CLINKOffer = {
...sampleOffer, ...sampleOffer,
priceType: 'fixed', priceType: 'fixed',
amountMsat: 50000, amountSats: 50000,
} }
const noffer = encodeNoffer(offer) const noffer = encodeNoffer(offer)
const decoded = decodeNoffer(noffer) const decoded = decodeNoffer(noffer)
expect(decoded.priceType).toBe('fixed') expect(decoded.priceType).toBe('fixed')
expect(decoded.amountMsat).toBe(50000) expect(decoded.amountSats).toBe(50000)
}) })
it('should throw on invalid prefix', () => { it('should throw on invalid prefix', () => {

View file

@ -177,9 +177,12 @@ function decodePriceType(byte: number): PriceType {
} }
function encodeUint64BE(value: number): number[] { function encodeUint64BE(value: number): number[] {
const bytes: number[] = [] // Use division instead of bit shifts because JS bitwise ops only work on 32-bit ints
for (let i = 7; i >= 0; i--) { const bytes: number[] = new Array(8).fill(0)
bytes.push((value >> (i * 8)) & 0xff) let remaining = value
for (let i = 7; i >= 0 && remaining > 0; i--) {
bytes[i] = remaining % 256
remaining = Math.floor(remaining / 256)
} }
return bytes return bytes
} }

View file

@ -1,9 +1,8 @@
import { describe, it, expect, vi } from 'vitest' import { describe, it, expect } from 'vitest'
import { LightningPubClient } from '../client.js' import { LightningPubClient } from '../client.js'
describe('LightningPubClient', () => { describe('LightningPubClient', () => {
const config = { const config = {
serviceUrl: 'https://lightning.pub',
accountPubkey: 'a'.repeat(64), accountPubkey: 'a'.repeat(64),
relays: ['wss://relay.example.com'], relays: ['wss://relay.example.com'],
} }
@ -13,6 +12,15 @@ describe('LightningPubClient', () => {
const client = new LightningPubClient(config) const client = new LightningPubClient(config)
expect(client).toBeDefined() expect(client).toBeDefined()
}) })
it('should accept optional timeout and appId', () => {
const client = new LightningPubClient({
...config,
timeout: 60000,
appId: 'test-app',
})
expect(client).toBeDefined()
})
}) })
describe('getExchangeRate', () => { describe('getExchangeRate', () => {
@ -33,26 +41,47 @@ describe('LightningPubClient', () => {
expect(usdRate.satsPerUnit).not.toBe(eurRate.satsPerUnit) expect(usdRate.satsPerUnit).not.toBe(eurRate.satsPerUnit)
}) })
it('should return default rate for unknown currency', async () => {
const client = new LightningPubClient(config)
const rate = await client.getExchangeRate('XYZ')
expect(rate.currency).toBe('XYZ')
expect(rate.satsPerUnit).toBe(2500) // default rate
})
}) })
describe('decodeInvoice', () => { describe('decodeInvoice', () => {
it('should decode a basic invoice', () => { it('should decode invoice with micro-BTC amount', () => {
const client = new LightningPubClient(config) const client = new LightningPubClient(config)
// This is a simplified test since we have basic parsing
const result = client.decodeInvoice('lnbc100u1...') const result = client.decodeInvoice('lnbc100u1...')
expect(result).toBeDefined() expect(result).toBeDefined()
expect(result.amountSats).toBe(10000) // 100 micro-BTC = 10000 sats
expect(result.expiresAt).toBeGreaterThan(Date.now() / 1000) expect(result.expiresAt).toBeGreaterThan(Date.now() / 1000)
}) })
it('should decode invoice with milli-BTC amount', () => {
const client = new LightningPubClient(config)
const result = client.decodeInvoice('lnbc1m1...')
expect(result.amountSats).toBe(100000) // 1 milli-BTC = 100000 sats
})
it('should return null amount for invoice without amount', () => {
const client = new LightningPubClient(config)
const result = client.decodeInvoice('lnbcrt1...')
expect(result.amountSats).toBeNull()
})
}) })
describe('initialize', () => { describe('initialize', () => {
it('should require nostrClient and identity', () => { it('should require nostrClient and identity', async () => {
const client = new LightningPubClient(config) const client = new LightningPubClient(config)
// Without initialization, operations should fail // Without initialization, operations should fail
expect(client.getBalance()).rejects.toThrow('Client not initialized') await expect(client.getBalance()).rejects.toThrow('Client not initialized')
}) })
}) })

View file

@ -0,0 +1,17 @@
import { describe, it, expect } from 'vitest'
import { version } from '../index.js'
describe('@lamassu/ui-shared', () => {
describe('exports', () => {
it('should export version', () => {
expect(version).toBe('0.1.0')
})
})
// TODO: Add tests when Vue components are implemented
describe('placeholder', () => {
it('should pass placeholder test', () => {
expect(true).toBe(true)
})
})
})