diff --git a/public/hop-display.js b/public/hop-display.js index 543582e..86da802 100644 --- a/public/hop-display.js +++ b/public/hop-display.js @@ -81,9 +81,13 @@ window.HopDisplay = (function() { const regionalConflicts = conflicts.filter(c => c.regional); const badgeCount = regionalConflicts.length > 0 ? regionalConflicts.length : (globalFallback ? conflicts.length : 0); const conflictData = escapeHtml(JSON.stringify({ h, conflicts, globalFallback })); - const warnBadge = badgeCount > 1 + const conflictBadge = badgeCount > 1 ? ` ` : ''; + const unreliableBadge = unreliable + ? ' ' + : ''; + const warnBadge = conflictBadge + unreliableBadge; const cls = [ 'hop', diff --git a/public/style.css b/public/style.css index 70f6181..db9c5d7 100644 --- a/public/style.css +++ b/public/style.css @@ -1437,7 +1437,9 @@ button.ch-item.ch-item-encrypted .ch-badge { filter: grayscale(0.6); } .hop-conflict-name { font-weight: 600; flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .hop-conflict-dist { font-size: 11px; color: var(--text-muted); font-family: var(--mono); white-space: nowrap; } .hop-conflict-pk { font-size: 10px; color: var(--text-muted); font-family: var(--mono); } -.hop-unreliable { opacity: 0.5; text-decoration: line-through; } +.hop-unreliable { opacity: 0.85; } +.hop-unreliable-btn { background: none; border: none; color: var(--status-yellow, #f59e0b); font-size: 13px; + cursor: help; vertical-align: middle; margin-left: 2px; padding: 0 2px; line-height: 1; } .hop-global-fallback { border-bottom: 1px dashed var(--status-red); } .hop-current { font-weight: 700 !important; color: var(--accent) !important; } diff --git a/test-frontend-helpers.js b/test-frontend-helpers.js index 8327df5..3c06ba9 100644 --- a/test-frontend-helpers.js +++ b/test-frontend-helpers.js @@ -6198,6 +6198,62 @@ console.log('\n=== analytics.js: renderCollisionsFromServer collision table ===' }); } +// ===== #872 — hop-display unreliable badge ===== +{ + console.log('\n--- #872: hop-display unreliable warning badge ---'); + + function makeHopDisplaySandbox() { + const sb = { + window: { addEventListener: () => {}, dispatchEvent: () => {} }, + document: { + readyState: 'complete', + createElement: () => ({ id: '', textContent: '', innerHTML: '' }), + head: { appendChild: () => {} }, + getElementById: () => null, + addEventListener: () => {}, + querySelectorAll: () => [], + querySelector: () => null, + }, + console, + Date, Math, Array, Object, String, Number, JSON, RegExp, Map, Set, + encodeURIComponent, parseInt, parseFloat, isNaN, Infinity, NaN, undefined, + setTimeout: () => {}, setInterval: () => {}, clearTimeout: () => {}, clearInterval: () => {}, + }; + sb.window.document = sb.document; + sb.self = sb.window; + sb.globalThis = sb.window; + const ctx = vm.createContext(sb); + const hopSrc = fs.readFileSync(__dirname + '/public/hop-display.js', 'utf8'); + vm.runInContext(hopSrc, ctx); + return ctx; + } + + const hopCtx = makeHopDisplaySandbox(); + + test('#872: unreliable hop renders warning badge, not strikethrough', () => { + const html = hopCtx.window.HopDisplay.renderHop('AABB', { + name: 'TestNode', pubkey: 'pk123', unreliable: true, + ambiguous: false, conflicts: [], globalFallback: false, + }, {}); + // Must contain unreliable warning badge button + assert.ok(html.includes('hop-unreliable-btn'), 'should have unreliable badge button'); + assert.ok(html.includes('⚠️'), 'should have ⚠️ icon'); + assert.ok(html.includes('Unreliable name resolution'), 'should have tooltip text'); + // Must NOT contain line-through in inline style (CSS class no longer has it) + assert.ok(!html.includes('line-through'), 'should not contain line-through'); + // Should still have hop-unreliable class for subtle styling + assert.ok(html.includes('hop-unreliable'), 'should have hop-unreliable class'); + }); + + test('#872: reliable hop does NOT render unreliable badge', () => { + const html = hopCtx.window.HopDisplay.renderHop('CCDD', { + name: 'GoodNode', pubkey: 'pk456', unreliable: false, + ambiguous: false, conflicts: [], globalFallback: false, + }, {}); + assert.ok(!html.includes('hop-unreliable-btn'), 'should not have unreliable badge'); + }); +} + // ===== SUMMARY ===== Promise.allSettled(pendingTests).then(() => { console.log(`\n${'═'.repeat(40)}`);