import { describe, it, expect, vi, beforeEach } from 'vitest' import { setActivePinia, createPinia } from 'pinia' import { useAppLauncherStore } from '../appLauncher' // Mock window.open for new-tab tests const mockWindowOpen = vi.fn() vi.stubGlobal('open', mockWindowOpen) describe('useAppLauncherStore', () => { beforeEach(() => { setActivePinia(createPinia()) vi.clearAllMocks() // Default to HTTP to avoid proxy rewriting Object.defineProperty(window, 'location', { value: { origin: 'http://192.168.1.228', protocol: 'http:', hostname: '192.168.1.228' }, writable: true, configurable: true, }) }) it('starts closed with empty state', () => { const store = useAppLauncherStore() expect(store.isOpen).toBe(false) expect(store.url).toBe('') expect(store.title).toBe('') }) it('opens an app in the iframe overlay', () => { const store = useAppLauncherStore() store.open({ url: 'http://192.168.1.228:8080', title: 'Mempool' }) expect(store.isOpen).toBe(true) expect(store.url).toBe('http://192.168.1.228:8080') expect(store.title).toBe('Mempool') expect(mockWindowOpen).not.toHaveBeenCalled() }) it('opens BTCPay (port 23000) in a new tab due to X-Frame-Options', () => { const store = useAppLauncherStore() store.open({ url: 'http://192.168.1.228:23000', title: 'BTCPay' }) expect(store.isOpen).toBe(false) expect(mockWindowOpen).toHaveBeenCalledWith( 'http://192.168.1.228:23000', '_blank', 'noopener,noreferrer', ) }) it('opens Home Assistant (port 8123) in a new tab', () => { const store = useAppLauncherStore() store.open({ url: 'http://192.168.1.228:8123', title: 'Home Assistant' }) expect(store.isOpen).toBe(false) expect(mockWindowOpen).toHaveBeenCalled() }) it('opens Grafana (port 3000) in a new tab', () => { const store = useAppLauncherStore() store.open({ url: 'http://192.168.1.228:3000', title: 'Grafana' }) expect(store.isOpen).toBe(false) expect(mockWindowOpen).toHaveBeenCalled() }) it('opens in new tab when openInNewTab flag is set', () => { const store = useAppLauncherStore() store.open({ url: 'http://192.168.1.228:8080', title: 'Mempool', openInNewTab: true }) expect(store.isOpen).toBe(false) expect(mockWindowOpen).toHaveBeenCalledWith( 'http://192.168.1.228:8080', '_blank', 'noopener,noreferrer', ) }) it('rewrites URL to proxy path on HTTPS for same-host apps', () => { Object.defineProperty(window, 'location', { value: { origin: 'https://192.168.1.228', protocol: 'https:', hostname: '192.168.1.228' }, writable: true, configurable: true, }) const store = useAppLauncherStore() store.open({ url: 'http://192.168.1.228:8083', title: 'FileBrowser' }) expect(store.isOpen).toBe(true) expect(store.url).toBe('https://192.168.1.228/app/filebrowser/') }) it('does not rewrite URL on HTTP (no mixed content)', () => { const store = useAppLauncherStore() store.open({ url: 'http://192.168.1.228:8083', title: 'FileBrowser' }) expect(store.url).toBe('http://192.168.1.228:8083') }) it('does not rewrite URL for different hosts', () => { Object.defineProperty(window, 'location', { value: { origin: 'https://192.168.1.228', protocol: 'https:', hostname: '192.168.1.228' }, writable: true, configurable: true, }) const store = useAppLauncherStore() store.open({ url: 'http://192.168.1.100:8083', title: 'Remote FileBrowser' }) // Different host — no proxy rewriting expect(store.url).toBe('http://192.168.1.100:8083') }) it('close resets state', () => { const store = useAppLauncherStore() store.open({ url: 'http://192.168.1.228:8080', title: 'Mempool' }) store.close() expect(store.isOpen).toBe(false) expect(store.url).toBe('') expect(store.title).toBe('') }) it('close restores focus to previous element', async () => { vi.useFakeTimers() const store = useAppLauncherStore() const mockButton = { focus: vi.fn() } as unknown as HTMLElement Object.defineProperty(document, 'activeElement', { value: mockButton, configurable: true }) store.open({ url: 'http://192.168.1.228:8080', title: 'Mempool' }) store.close() expect(store.isOpen).toBe(false) expect(store.url).toBe('') // requestAnimationFrame fires the focus restore callback vi.runAllTimers() vi.useRealTimers() }) })