]> git.codecow.com Git - libnemo.git/commitdiff
Fix Ledger tests.
authorChris Duncan <chris@codecow.com>
Tue, 12 May 2026 20:24:58 +0000 (13:24 -0700)
committerChris Duncan <chris@codecow.com>
Tue, 12 May 2026 20:24:58 +0000 (13:24 -0700)
test/test.ledger.mjs

index e90957c715076a4baa6ad80fab137cf1279fa633..1004cb4d4484f45a26578c020ed65e2d6a68b3fe 100644 (file)
@@ -8,6 +8,7 @@ import { assert, click, env, isNode, suite, test } from './GLOBALS.mjs'
 import { CUSTOM_TEST_VECTORS, NANO_TEST_VECTORS } from './VECTORS.mjs'
 
 const rpc = new Rpc(env.NODE_URL ?? '', env.API_KEY_NAME)
+const isUnsupported = isNode || navigator?.usb == null
 
 /**
  * HID interactions require user gestures, so to reduce clicks, the variables
@@ -19,7 +20,7 @@ const rpc = new Rpc(env.NODE_URL ?? '', env.API_KEY_NAME)
  * addresses from their own Ledger hardware wallets.
  */
 await Promise.all([
-       suite('Ledger unsupported', { skip: !(isNode || navigator?.usb == null) }, async () => {
+       suite('Ledger unsupported', { skip: !isUnsupported }, async () => {
 
                await test('status UNSUPPORTED', async () => {
                        assert.equal(Ledger.status, 'UNSUPPORTED')
@@ -27,7 +28,7 @@ await Promise.all([
                })
        }),
 
-       suite('Ledger hardware wallet', { skip: isNode || navigator?.usb == null }, async () => {
+       suite('Ledger hardware wallet', { skip: isUnsupported }, async () => {
 
                const { LEDGER_NANOS, LEDGER_NANOSP } = CUSTOM_TEST_VECTORS
                const { OPEN_BLOCK, RECEIVE_BLOCK, SEND_BLOCK } = NANO_TEST_VECTORS
@@ -36,14 +37,14 @@ await Promise.all([
                        /** @type {Block} */ openBlock,
                        /** @type {Block} */ sendBlock,
                        /** @type {Block} */ receiveBlock,
-                       restored
+                       /** @type {Wallet} */ restored
                try {
                        wallet = await Wallet.create('Ledger')
                } catch {
                        return
                }
 
-               await test('request permissions', { skip: true }, async () => {
+               await test('request permissions', { skip: isUnsupported }, async () => {
                        let status = Ledger.status
 
                        Ledger.addEventListener('ledgerstatuschanged', (event) => {
@@ -152,7 +153,7 @@ await Promise.all([
                        assert.equal(status, 'CONNECTED')
                })
 
-               await test('switch between interfaces', { skip: false || isNode || navigator?.usb == null }, async () => {
+               await test('switch between interfaces', { skip: isUnsupported }, async () => {
                        await assert.resolves(click(
                                'Verify current interface is HID, switch to unlocked Bluetooth device, then click to continue',
                                async () => wallet.config({ connection: 'ble' })
@@ -177,29 +178,34 @@ await Promise.all([
 
                await test('verify mnemonic', async () => {
                        await click(
-                               'Open Nano app, then click to continue',
-                               async () => wallet.unlock()
+                               'Open Nano app, then click to verify mnemonic',
+                               async () => {
+                                       await wallet.config({ connection: 'hid' })
+                                       await wallet.unlock()
+                                       const isVerified = await wallet.verify(LEDGER_NANOS.MNEMONIC)
+                                       // const isVerified = await wallet.verify(LEDGER_NANOSP.MNEMONIC)
+                                       assert.exists(isVerified)
+                                       assert.equal(typeof isVerified, 'boolean')
+                                       assert.equal(isVerified, true)
+                               }
                        )
-                       const isVerified = await wallet.verify(LEDGER_NANOS.MNEMONIC)
-                       // const isVerified = await wallet.verify(LEDGER_NANOSP.MNEMONIC)
-
-                       assert.exists(isVerified)
-                       assert.equal(typeof isVerified, 'boolean')
-                       assert.equal(isVerified, true)
                })
 
                await test('verify seed', async () => {
-                       const isVerified = await wallet.verify(LEDGER_NANOS.SEED)
-                       // const isVerified = await wallet.verify(LEDGER_NANOSP.SEED)
-
-                       assert.exists(isVerified)
-                       assert.equal(typeof isVerified, 'boolean')
-                       assert.equal(isVerified, true)
+                       await click(
+                               'Click to verify seed',
+                               async () => {
+                                       const isVerified = await wallet.verify(LEDGER_NANOS.SEED)
+                                       // const isVerified = await wallet.verify(LEDGER_NANOSP.SEED)
+                                       assert.exists(isVerified)
+                                       assert.equal(typeof isVerified, 'boolean')
+                                       assert.equal(isVerified, true)
+                               }
+                       )
                })
 
                await test('get first account', async () => {
                        account = await wallet.account()
-
                        assert.exists(account)
                        assert.ok(account instanceof Account)
                        assert.exists(account.publicKey)
@@ -212,7 +218,6 @@ await Promise.all([
 
                await test('get second and third accounts', async () => {
                        const accounts = await wallet.accounts(1, 2)
-
                        assert.exists(accounts)
                        assert.equal(accounts.size, 2)
                        for (const account of accounts.values()) {
@@ -225,7 +230,6 @@ await Promise.all([
                // skip since accounts must already be opened to be refreshed
                await test('refresh first three accounts', { skip: true }, async () => {
                        const accounts = await wallet.refresh(rpc, 0, 2)
-
                        assert.exists(accounts)
                        for (const account of accounts.values()) {
                                assert.ok(account instanceof Account)
@@ -244,14 +248,23 @@ await Promise.all([
                        assert.nullish(openBlock.signature)
                        assert.equal(openBlock.account.publicKey, account.publicKey)
 
-                       await wallet.sign(0, openBlock)
+                       await click(
+                               'Click to sign open block from Ledger wallet',
+                               async () => wallet.sign(0, openBlock)
+                       )
+                       const { signature } = openBlock
 
-                       assert.ok(/^[A-F0-9]{128}$/i.test(openBlock.signature ?? ''))
+                       assert.ok(/^[A-F0-9]{128}$/i.test(signature ?? ''))
+                       openBlock.signature = undefined
 
-                       await openBlock.sign(wallet, 0)
+                       await click(
+                               'Click to sign open block from block using Ledger',
+                               async () => openBlock.sign(wallet, 0)
+                       )
 
                        assert.exists(openBlock.signature)
                        assert.ok(/^[A-F0-9]{128}$/i.test(openBlock.signature ?? ''))
+                       assert.equal(signature, openBlock.signature)
                })
 
                await test('sign send block from wallet which requires cache to be up-to-date', async () => {
@@ -262,7 +275,10 @@ await Promise.all([
                        assert.nullish(sendBlock.signature)
                        assert.equal(sendBlock.account.publicKey, account.publicKey)
 
-                       await wallet.sign(0, sendBlock, openBlock)
+                       await click(
+                               'Click to sign send block which requires up-to-date cache',
+                               async () => wallet.sign(0, sendBlock, openBlock)
+                       )
 
                        assert.ok(/^[A-F0-9]{128}$/i.test(sendBlock.signature ?? ''))
                })
@@ -275,7 +291,10 @@ await Promise.all([
                        assert.nullish(receiveBlock.signature)
                        assert.equal(receiveBlock.account.publicKey, account.publicKey)
 
-                       await receiveBlock.sign(wallet, 0, sendBlock)
+                       await click(
+                               'Click to sign receive block from block passing previous block for cache',
+                               async () => receiveBlock.sign(wallet, 0, sendBlock)
+                       )
 
                        assert.exists(receiveBlock.signature)
                        assert.ok(/^[A-F0-9]{128}$/i.test(receiveBlock.signature ?? ''))
@@ -300,7 +319,10 @@ await Promise.all([
                        assert.nullish(sendBlock.signature)
                        assert.equal(sendBlock.account.publicKey, account.publicKey)
 
-                       await wallet.sign(0, sendBlock, receiveBlock)
+                       await click(
+                               'Click to sign send block from Ledger including frontier block for cache',
+                               async () => wallet.sign(0, sendBlock, receiveBlock)
+                       )
 
                        assert.exists(sendBlock.signature)
                        assert.ok(/^[A-F0-9]{128}$/i.test(sendBlock.signature ?? ''))
@@ -309,18 +331,28 @@ await Promise.all([
                await test('sign a 16-byte nonce', async () => {
                        const nonce = 'hello nano world'
 
-                       const signature = await wallet.sign(0, nonce)
-
-                       assert.exists(signature)
-                       assert.ok(/^[A-F0-9]{128}$/i.test(signature))
+                       await click(
+                               'Click to sign send block from Ledger including frontier block for cache',
+                               async () => {
+                                       const signature = await wallet.sign(0, nonce)
+                                       assert.exists(signature)
+                                       assert.ok(/^[A-F0-9]{128}$/i.test(signature))
+                               }
+                       )
                })
 
                await test('fail to sign invalid length nonces', async () => {
                        const nonceShort = 'hello world'
                        const nonceLong = 'hello world foobar'
 
-                       await assert.rejects(wallet.sign(0, nonceShort))
-                       await assert.rejects(wallet.sign(0, nonceLong))
+                       await assert.rejects(click(
+                               'fail to sign short nonce',
+                               async () => wallet.sign(0, nonceShort)
+                       ))
+                       await assert.rejects(click(
+                               'fail to sign long nonce',
+                               async () => wallet.sign(0, nonceLong)
+                       ))
                })
 
                await test('fail when using new', async () => {
@@ -330,7 +362,10 @@ await Promise.all([
                await test('fail to sign a block without caching frontier', async () => {
                        sendBlock = new Block(account, receiveBlock.balance, receiveBlock.hash, SEND_BLOCK.representative)
                                .send(account.address, '0')
-                       await assert.rejects(sendBlock.sign(wallet, 0))
+                       await assert.rejects(click(
+                               'fail to sign without frontier cache',
+                               async () => sendBlock.sign(wallet, 0)
+                       ))
                })
 
                await test('restore from db then destroy', async () => {
@@ -338,7 +373,13 @@ await Promise.all([
 
                        assert.exists(restored)
                        await assert.resolves(restored.unlock())
-                       assert.equal(await restored.verify(LEDGER_NANOS.MNEMONIC), true)
+                       await assert.resolves(click(
+                               'Click to verify Ledger mnemonic',
+                               async () => {
+                                       const verification = await restored.verify(LEDGER_NANOS.MNEMONIC)
+                                       assert.equal(verification, true)
+                               }
+                       ))
                        // assert.equal(await restored.verify(LEDGER_NANOSP.MNEMONIC), true)
 
                        await click(