import { describe, it, expect, beforeEach, afterEach } from 'vitest' import { render, screen } from '@testing-library/react' import { BrowserPanel } from '../components/BrowserPanel' describe('BrowserPanel', () => { const originalLocation = window.location beforeEach(() => { // Reset location before each test Object.defineProperty(window, 'location', { configurable: true, writable: true, value: { hostname: 'localhost' }, }) }) afterEach(() => { Object.defineProperty(window, 'location', { configurable: true, writable: true, value: originalLocation, }) }) describe('placeholder (no sessionId)', () => { it('renders placeholder text when sessionId is null', () => { render() expect(screen.getByText('Select a session to view the browser')).toBeTruthy() }) it('does not render an iframe when sessionId is null', () => { const { container } = render() expect(container.querySelector('iframe')).toBeNull() }) it('placeholder div has padding 2rem', () => { const { container } = render() const div = container.firstElementChild as HTMLElement expect(div.style.padding).toBe('2rem') }) it('placeholder div text has color #6a6a8a', () => { const { container } = render() const div = container.firstElementChild as HTMLElement // jsdom normalizes hex colors to rgb() — #6a6a8a = rgb(106, 106, 138) expect(div.style.color).toBe('rgb(106, 106, 138)') }) it('placeholder div text is centered', () => { const { container } = render() const div = container.firstElementChild as HTMLElement expect(div.style.textAlign).toBe('center') }) }) describe('iframe (with sessionId)', () => { it('renders an iframe when sessionId is provided', () => { const { container } = render() expect(container.querySelector('iframe')).toBeTruthy() }) it('does not render placeholder text when sessionId is provided', () => { render() expect(screen.queryByText('Select a session to view the browser')).toBeNull() }) it('iframe has title "Browser - noVNC"', () => { const { container } = render() const iframe = container.querySelector('iframe') as HTMLIFrameElement expect(iframe.title).toBe('Browser - noVNC') }) it('iframe has width 100%', () => { const { container } = render() const iframe = container.querySelector('iframe') as HTMLIFrameElement expect(iframe.style.width).toBe('100%') }) it('iframe has height 100%', () => { const { container } = render() const iframe = container.querySelector('iframe') as HTMLIFrameElement expect(iframe.style.height).toBe('100%') }) it('iframe has no border', () => { const { container } = render() const iframe = container.querySelector('iframe') as HTMLIFrameElement // jsdom expands border shorthand — check borderStyle which carries the 'none' value expect(iframe.style.borderStyle).toBe('none') }) it('iframe has dark background color #0a0a1a', () => { const { container } = render() const iframe = container.querySelector('iframe') as HTMLIFrameElement // jsdom normalizes hex colors to rgb() — #0a0a1a = rgb(10, 10, 26) expect(iframe.style.background).toBe('rgb(10, 10, 26)') }) it('iframe has clipboard allow attribute', () => { const { container } = render() const iframe = container.querySelector('iframe') as HTMLIFrameElement expect(iframe.getAttribute('allow')).toBe('clipboard-read; clipboard-write') }) }) describe('getVncUrl() — URL detection', () => { it('returns cloudflared HTTPS URL when hostname is research.ampbox.io', () => { Object.defineProperty(window, 'location', { configurable: true, writable: true, value: { hostname: 'research.ampbox.io' }, }) const { container } = render() const iframe = container.querySelector('iframe') as HTMLIFrameElement expect(iframe.src).toBe( 'https://vnc.ampbox.io/vnc.html?autoconnect=true&resize=remote&quality=6&compression=2' ) }) it('returns localhost http URL with port 6080 when hostname is localhost', () => { Object.defineProperty(window, 'location', { configurable: true, writable: true, value: { hostname: 'localhost' }, }) const { container } = render() const iframe = container.querySelector('iframe') as HTMLIFrameElement expect(iframe.src).toBe( 'http://localhost:6080/vnc.html?autoconnect=true&resize=remote&quality=6&compression=2' ) }) it('returns http URL with other hostname when not research.ampbox.io', () => { Object.defineProperty(window, 'location', { configurable: true, writable: true, value: { hostname: '192.168.1.100' }, }) const { container } = render() const iframe = container.querySelector('iframe') as HTMLIFrameElement expect(iframe.src).toBe( 'http://192.168.1.100:6080/vnc.html?autoconnect=true&resize=remote&quality=6&compression=2' ) }) it('URL includes autoconnect=true query param', () => { const { container } = render() const iframe = container.querySelector('iframe') as HTMLIFrameElement expect(iframe.src).toContain('autoconnect=true') }) it('URL includes resize=remote query param', () => { const { container } = render() const iframe = container.querySelector('iframe') as HTMLIFrameElement expect(iframe.src).toContain('resize=remote') }) it('URL includes quality=6 query param', () => { const { container } = render() const iframe = container.querySelector('iframe') as HTMLIFrameElement expect(iframe.src).toContain('quality=6') }) it('URL includes compression=2 query param', () => { const { container } = render() const iframe = container.querySelector('iframe') as HTMLIFrameElement expect(iframe.src).toContain('compression=2') }) }) })