OverviewFilesCommitsIssuesDocsReleasesPeers

hyper-wallet / tests / integration / test-address-sync.js.moved

103 lines · moved ref:
import { TmuxOrchestrator } from '../../../hyper-lab/lib/tmux-orchestrator.js'

export default async function testAddressSync(agentConfigs, options = {}) {
  const test = new TmuxOrchestrator('address-sync', agentConfigs)

  try {
    // Connect to all agents
    await test.connect()

    // Create tmux session (both human and AI can see)
    await test.createSession()

    await test.log('📱 Starting address sync test...', 'blue')

    const device1 = agentConfigs[0].name
    const device2 = agentConfigs[1].name

    // Initialize wallets
    await test.log('🔐 Initializing wallets...', 'blue')
    await test.run(device1, 'init')
    await test.run(device2, 'init')

    // Bootstrap device1
    await test.log('🖥️  Bootstrapping device1...', 'blue')
    await test.run(device1, 'device', ['bootstrap', 'Device1'])

    // Create invite
    await test.log('🔗 Creating device pairing invite...', 'blue')
    await test.run(device1, 'device', ['add'])

    // Wait for invite to appear, then capture it
    await test.sleep(2000)
    const device1Output = await test.capturePane(test.paneMap.get(device1), 100)
    const invite = extractInvite(device1Output)

    if (!invite) {
      throw new Error('Could not extract invite from device1 output')
    }

    await test.log(`📋 Invite extracted: ${invite.substring(0, 20)}...`, 'blue')

    // Device2 joins (this will wait for approval)
    await test.log('📱 Device2 joining...', 'blue')
    await test.run(device2, 'device', ['join', invite, 'Device2'])

    // Wait for join success message
    await test.log('⏳ Waiting for pairing to complete...', 'yellow')
    await test.waitForOutput(device2, '✅ Joined wallet successfully', 30000)

    // Generate address on device1
    await test.log('🔑 Generating Bitcoin address on device1...', 'blue')
    await test.run(device1, 'address', ['new', 'bitcoin'])

    // Wait for sync (Autobase replication)
    await test.log('⏳ Waiting for Autobase sync (8 seconds)...', 'yellow')
    await test.sleep(8000)

    // Check device2 has the address
    await test.log('🔍 Checking sync on device2...', 'blue')
    await test.run(device2, 'address', ['list', 'bitcoin'])

    // Wait a moment for list output
    await test.sleep(1000)

    // Verify by reading device2's pane output
    const device2Output = await test.capturePane(test.paneMap.get(device2), 50)

    test.assert(
      device2Output.includes('Total: 1 address'),
      'Device2 should have 1 synced address'
    )
    test.assert(
      device2Output.includes('tb1q'),
      'Address should be Bitcoin testnet (tb1q...)'
    )

    await test.log('🎉 Test passed!', 'green')

    // Return session name for --attach option
    return test.sessionName

  } catch (err) {
    await test.log(`💥 Test failed: ${err.message}`, 'red')
    throw err
  } finally {
    await test.cleanup()
  }
}

function extractInvite(output) {
  const lines = output.split('\n')
  for (let i = 0; i < lines.length; i++) {
    if (lines[i].includes('━━━━')) {
      // Invite is on the next line
      const invite = lines[i + 1].trim()
      if (invite && invite.length > 20) {
        return invite
      }
    }
  }
  return null
}