generated from CubeCraft-Creations/Tracehound
CUB-196: CameraCard component with live SSE status display #3
@@ -131,4 +131,33 @@ describe('CameraCard', () => {
|
|||||||
)
|
)
|
||||||
expect(screen.getByText('unknown')).toBeInTheDocument()
|
expect(screen.getByText('unknown')).toBeInTheDocument()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('shows "unknown" when last_seen is in the future', () => {
|
||||||
|
const future = new Date(Date.now() + 86400000).toISOString() // +1 day
|
||||||
|
render(<CameraCard camera={makeCamera({ last_seen: future })} />)
|
||||||
|
expect(screen.getByText('unknown')).toBeInTheDocument()
|
||||||
|
})
|
||||||
|
|
||||||
|
// ── Edge cases ──────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
it('clamps negative battery_pct to 0%', () => {
|
||||||
|
render(<CameraCard camera={makeCamera({ battery_pct: -5 })} />)
|
||||||
|
expect(screen.getByText('0%')).toBeInTheDocument()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('shows exact boundary: 15% battery → yellow bar', () => {
|
||||||
|
const { container } = render(
|
||||||
|
<CameraCard camera={makeCamera({ battery_pct: 15 })} />,
|
||||||
|
)
|
||||||
|
const bar = container.querySelector('[role="progressbar"] div')
|
||||||
|
expect(bar?.className).toContain('bg-rig-warning')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('shows exact boundary: 50% battery → green bar', () => {
|
||||||
|
const { container } = render(
|
||||||
|
<CameraCard camera={makeCamera({ battery_pct: 50 })} />,
|
||||||
|
)
|
||||||
|
const bar = container.querySelector('[role="progressbar"] div')
|
||||||
|
expect(bar?.className).toContain('bg-rig-success')
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ function formatRelativeTime(iso: string): string {
|
|||||||
if (isNaN(then)) return 'unknown'
|
if (isNaN(then)) return 'unknown'
|
||||||
|
|
||||||
const diffSec = Math.floor((Date.now() - then) / 1000)
|
const diffSec = Math.floor((Date.now() - then) / 1000)
|
||||||
|
if (diffSec < 0) return 'unknown'
|
||||||
|
|
||||||
if (diffSec < 10) return 'just now'
|
if (diffSec < 10) return 'just now'
|
||||||
if (diffSec < 60) return `${diffSec}s ago`
|
if (diffSec < 60) return `${diffSec}s ago`
|
||||||
@@ -32,7 +33,7 @@ function batteryColor(pct: number | null): { bar: string; text: string } {
|
|||||||
function formatTimeLeft(sec: number): string {
|
function formatTimeLeft(sec: number): string {
|
||||||
if (sec <= 0 || !isFinite(sec)) return '--'
|
if (sec <= 0 || !isFinite(sec)) return '--'
|
||||||
const m = Math.floor(sec / 60)
|
const m = Math.floor(sec / 60)
|
||||||
const s = sec % 60
|
const s = Math.floor(sec % 60)
|
||||||
return `${m}m ${s}s left`
|
return `${m}m ${s}s left`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,7 +139,7 @@ export default function CameraCard({ camera }: CameraCardProps) {
|
|||||||
Battery
|
Battery
|
||||||
</span>
|
</span>
|
||||||
<span className={`font-mono text-xs ${batt.text}`}>
|
<span className={`font-mono text-xs ${batt.text}`}>
|
||||||
{battery_pct !== null ? `${battery_pct}%` : 'N/A'}
|
{battery_pct !== null ? `${Math.max(0, battery_pct)}%` : 'N/A'}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
|
|||||||
Reference in New Issue
Block a user