import { beforeEach, afterEach, describe, expect, it, vi } from 'vitest'; import { fireEvent, render, screen, waitFor } from '../../../setup/test-utils'; import { ControlPanelEmbed } from '@/components/cliproxy/control-panel-embed'; function createJsonResponse(body: Record, status = 200): Response { return new Response(JSON.stringify(body), { status, headers: { 'Content-Type': 'application/json' }, }); } function getRequestUrl(input: RequestInfo | URL): string { if (input instanceof Request) { return input.url; } return String(input); } function createDeferred() { let resolve!: (value: T) => void; let reject!: (reason?: unknown) => void; const promise = new Promise((res, rej) => { resolve = res; reject = rej; }); return { promise, resolve, reject }; } describe('ControlPanelEmbed', () => { beforeEach(() => { vi.clearAllMocks(); }); afterEach(() => { vi.unstubAllGlobals(); vi.restoreAllMocks(); }); it('waits for the real local management secret before rendering the iframe', async () => { const tokenRequest = createDeferred(); const fetchMock = vi.fn((input: RequestInfo | URL) => { const url = getRequestUrl(input); if (url.endsWith('/api/cliproxy-server')) { return Promise.resolve( createJsonResponse({ remote: { enabled: false, host: '', protocol: 'http', auth_token: '', }, fallback: { enabled: true, auto_start: false, }, local: { port: 8317, auto_start: true, }, }) ); } if (url.endsWith('/api/settings/auth/tokens/raw')) { return tokenRequest.promise; } if (url.endsWith('/api/cliproxy-local/')) { return Promise.resolve(new Response('ok', { status: 200 })); } throw new Error(`Unexpected fetch: ${url}`); }); vi.stubGlobal('fetch', fetchMock); const { unmount } = render(); await waitFor(() => { expect(fetchMock).toHaveBeenCalledWith('/api/settings/auth/tokens/raw'); }); expect(screen.queryByTitle('CLIProxy Management Panel')).toBeNull(); tokenRequest.resolve( createJsonResponse({ apiKey: { value: 'ccs-internal-managed', isCustom: false }, managementSecret: { value: 'custom-secret', isCustom: true }, }) ); const iframe = await screen.findByTitle('CLIProxy Management Panel'); expect(iframe).toHaveAttribute('src', '/api/cliproxy-local/management.html'); await waitFor(() => { expect(window.localStorage.removeItem).toHaveBeenCalledWith('cli-proxy-auth'); expect(window.localStorage.setItem).toHaveBeenCalledWith( 'apiBase', 'http://localhost:3000/api/cliproxy-local' ); expect(window.localStorage.setItem).toHaveBeenCalledWith( 'apiUrl', 'http://localhost:3000/api/cliproxy-local' ); expect(window.localStorage.setItem).toHaveBeenCalledWith('managementKey', 'custom-secret'); expect(window.localStorage.setItem).toHaveBeenCalledWith('isLoggedIn', 'true'); }); vi.clearAllMocks(); unmount(); expect(window.localStorage.removeItem).toHaveBeenCalledWith('cli-proxy-auth'); expect(window.localStorage.removeItem).toHaveBeenCalledWith('apiBase'); expect(window.localStorage.removeItem).toHaveBeenCalledWith('apiUrl'); expect(window.localStorage.removeItem).toHaveBeenCalledWith('managementKey'); expect(window.localStorage.removeItem).toHaveBeenCalledWith('isLoggedIn'); }); it('clears stale local control-panel session keys when token bootstrap fails', async () => { const fetchMock = vi.fn((input: RequestInfo | URL) => { const url = getRequestUrl(input); if (url.endsWith('/api/cliproxy-server')) { return Promise.resolve( createJsonResponse({ remote: { enabled: false, host: '', protocol: 'http', auth_token: '', }, fallback: { enabled: true, auto_start: false, }, local: { port: 8317, auto_start: true, }, }) ); } if (url.endsWith('/api/settings/auth/tokens/raw')) { return Promise.reject(new Error('token bootstrap failed')); } if (url.endsWith('/api/cliproxy-local/')) { return Promise.resolve(new Response('ok', { status: 200 })); } throw new Error(`Unexpected fetch: ${url}`); }); vi.stubGlobal('fetch', fetchMock); render(); await screen.findByTitle('CLIProxy Management Panel'); await waitFor(() => { expect(window.localStorage.removeItem).toHaveBeenCalledWith('cli-proxy-auth'); expect(window.localStorage.removeItem).toHaveBeenCalledWith('apiBase'); expect(window.localStorage.removeItem).toHaveBeenCalledWith('apiUrl'); expect(window.localStorage.removeItem).toHaveBeenCalledWith('managementKey'); expect(window.localStorage.removeItem).toHaveBeenCalledWith('isLoggedIn'); }); }); it('preserves remote postMessage bootstrap for remote iframes', async () => { const fetchMock = vi.fn((input: RequestInfo | URL) => { const url = getRequestUrl(input); if (url.endsWith('/api/cliproxy-server')) { return Promise.resolve( createJsonResponse({ remote: { enabled: true, host: 'remote.example.com', protocol: 'https', auth_token: 'remote-secret', port: 443, }, fallback: { enabled: true, auto_start: false, }, local: { port: 8317, auto_start: true, }, }) ); } if (url.endsWith('/api/cliproxy-server/test')) { return Promise.resolve(createJsonResponse({ reachable: true })); } throw new Error(`Unexpected fetch: ${url}`); }); vi.stubGlobal('fetch', fetchMock); render(); const iframe = await screen.findByTitle('CLIProxy Management Panel'); expect(iframe).toHaveAttribute('src', 'https://remote.example.com/management.html'); const postMessage = vi.fn(); Object.defineProperty(iframe, 'contentWindow', { configurable: true, value: { postMessage }, }); fireEvent.load(iframe); expect(postMessage).toHaveBeenCalledWith( { type: 'ccs-auto-login', apiBase: 'https://remote.example.com', managementKey: 'remote-secret', }, 'https://remote.example.com' ); expect(fetchMock).not.toHaveBeenCalledWith('/api/settings/auth/tokens/raw'); }); });