|
| 1 | +import { test, expect } from '@playwright/test'; |
| 2 | + |
| 3 | +test.describe('BTC Monitoring Page', () => { |
| 4 | + test.beforeEach(async ({ page }) => { |
| 5 | + await page.goto('/monitoring/btc'); |
| 6 | + }); |
| 7 | + |
| 8 | + test('page loads with correct title', async ({ page }) => { |
| 9 | + await expect(page).toHaveTitle('lightning.space - BTC Monitoring'); |
| 10 | + }); |
| 11 | + |
| 12 | + test('displays header and navigation', async ({ page }) => { |
| 13 | + await expect(page.locator('h1')).toHaveText('lightning.space - BTC Monitoring'); |
| 14 | + await expect(page.locator('.nav')).toContainText('Overview'); |
| 15 | + await expect(page.locator('.nav')).toContainText('USD Monitoring'); |
| 16 | + await expect(page.locator('.nav a[href="/monitoring"]')).toBeVisible(); |
| 17 | + await expect(page.locator('.nav a[href="/monitoring/usd"]')).toBeVisible(); |
| 18 | + }); |
| 19 | + |
| 20 | + test('displays BTC Holdings Breakdown table', async ({ page }) => { |
| 21 | + await expect(page.locator('h2').filter({ hasText: 'BTC Holdings Breakdown' })).toBeVisible(); |
| 22 | + |
| 23 | + const table = page.locator('table').first(); |
| 24 | + await expect(table).toBeVisible(); |
| 25 | + |
| 26 | + // Check header columns |
| 27 | + await expect(table.locator('th').nth(0)).toHaveText('Source'); |
| 28 | + await expect(table.locator('th').nth(1)).toHaveText('Location'); |
| 29 | + await expect(table.locator('th').nth(2)).toHaveText('BTC'); |
| 30 | + |
| 31 | + // Check all 6 source rows exist |
| 32 | + const rows = table.locator('tr').filter({ hasNot: page.locator('th') }); |
| 33 | + await expect(rows).toHaveCount(7); // 6 sources + 1 total row |
| 34 | + |
| 35 | + // Verify source names |
| 36 | + await expect(table).toContainText('Onchain BTC'); |
| 37 | + await expect(table).toContainText('LND Onchain'); |
| 38 | + await expect(table).toContainText('Lightning'); |
| 39 | + await expect(table).toContainText('cBTC'); |
| 40 | + await expect(table).toContainText('WBTC'); |
| 41 | + await expect(table).toContainText('WBTCe'); |
| 42 | + |
| 43 | + // Verify locations |
| 44 | + await expect(table).toContainText('Bitcoin'); |
| 45 | + await expect(table).toContainText('LND Wallet'); |
| 46 | + await expect(table).toContainText('LN Channels'); |
| 47 | + await expect(table).toContainText('Citrea'); |
| 48 | + await expect(table).toContainText('Ethereum'); |
| 49 | + }); |
| 50 | + |
| 51 | + test('correctly converts sats to BTC', async ({ page }) => { |
| 52 | + const table = page.locator('table').first(); |
| 53 | + |
| 54 | + // Onchain BTC: 35390000 sats = 0.35390000 BTC |
| 55 | + const onchainRow = table.locator('tr').filter({ hasText: 'Onchain BTC' }); |
| 56 | + await expect(onchainRow.locator('td.number')).toHaveText('0.35390000'); |
| 57 | + |
| 58 | + // LND Onchain: 35300000 sats = 0.35300000 BTC |
| 59 | + const lndRow = table.locator('tr').filter({ hasText: 'LND Onchain' }); |
| 60 | + await expect(lndRow.locator('td.number')).toHaveText('0.35300000'); |
| 61 | + |
| 62 | + // Lightning: 128180000 sats = 1.28180000 BTC |
| 63 | + const lnRow = table.locator('tr').filter({ hasText: 'Lightning' }); |
| 64 | + await expect(lnRow.locator('td.number')).toHaveText('1.28180000'); |
| 65 | + |
| 66 | + // cBTC: 60010000 sats = 0.60010000 BTC |
| 67 | + const cbtcRow = table.locator('tr').filter({ hasText: /^cBTC/ }); |
| 68 | + await expect(cbtcRow.locator('td.number')).toHaveText('0.60010000'); |
| 69 | + }); |
| 70 | + |
| 71 | + test('correctly shows EVM token balances in BTC', async ({ page }) => { |
| 72 | + const table = page.locator('table').first(); |
| 73 | + |
| 74 | + // WBTC: 0.0037 BTC (already in BTC) - use td:first-child to match exactly |
| 75 | + const wbtcRow = table.locator('tr').filter({ has: page.locator('td:first-child', { hasText: /^WBTC$/ }) }); |
| 76 | + await expect(wbtcRow.locator('td.number')).toHaveText('0.00370000'); |
| 77 | + |
| 78 | + // WBTCe: 0.0012 BTC |
| 79 | + const wbtceRow = table.locator('tr').filter({ has: page.locator('td:first-child', { hasText: /^WBTCe$/ }) }); |
| 80 | + await expect(wbtceRow.locator('td.number')).toHaveText('0.00120000'); |
| 81 | + }); |
| 82 | + |
| 83 | + test('displays correct total holdings', async ({ page }) => { |
| 84 | + const table = page.locator('table').first(); |
| 85 | + const totalRow = table.locator('tr.total-row'); |
| 86 | + await expect(totalRow).toContainText('Total'); |
| 87 | + |
| 88 | + // Total = 0.3539 + 0.353 + 1.2818 + 0.6001 + 0.0037 + 0.0012 = 2.5937 |
| 89 | + await expect(totalRow.locator('td.number')).toHaveText('2.59370000'); |
| 90 | + }); |
| 91 | + |
| 92 | + test('displays BTC Balance Sheet', async ({ page }) => { |
| 93 | + await expect(page.locator('h2').filter({ hasText: 'BTC Balance Sheet' })).toBeVisible(); |
| 94 | + |
| 95 | + const balanceTable = page.locator('table').nth(1); |
| 96 | + await expect(balanceTable).toBeVisible(); |
| 97 | + |
| 98 | + await expect(balanceTable).toContainText('Total Holdings'); |
| 99 | + await expect(balanceTable).toContainText('Customer Balance'); |
| 100 | + await expect(balanceTable).toContainText('LDS Net Position'); |
| 101 | + }); |
| 102 | + |
| 103 | + test('shows correct customer balance as negative', async ({ page }) => { |
| 104 | + const balanceTable = page.locator('table').nth(1); |
| 105 | + const customerRow = balanceTable.locator('tr').filter({ hasText: 'Customer Balance' }); |
| 106 | + // Customer: 161260000 sats = 1.6126 BTC, shown as -1.61260000 |
| 107 | + await expect(customerRow.locator('td.number')).toHaveText('-1.61260000'); |
| 108 | + await expect(customerRow.locator('td.number')).toHaveClass(/negative/); |
| 109 | + }); |
| 110 | + |
| 111 | + test('shows correct net position with color', async ({ page }) => { |
| 112 | + const balanceTable = page.locator('table').nth(1); |
| 113 | + const netRow = balanceTable.locator('tr.total-row'); |
| 114 | + // Net = 2.5937 - 1.6126 = 0.9811 |
| 115 | + await expect(netRow.locator('td.number')).toHaveText('0.98110000'); |
| 116 | + await expect(netRow.locator('td.number')).toHaveClass(/positive/); |
| 117 | + }); |
| 118 | + |
| 119 | + test('shows timestamp after data loads', async ({ page }) => { |
| 120 | + const timestamp = page.locator('#timestamp'); |
| 121 | + await expect(timestamp).not.toHaveText('Loading...'); |
| 122 | + await expect(timestamp).toContainText('Last updated:'); |
| 123 | + }); |
| 124 | +}); |
0 commit comments