import { describe, it, expect, vi, beforeEach } from 'vitest'; import { render, screen, fireEvent, act, within } from '@testing-library/react'; const createAPIKey = vi.fn(async () => ({ id: 'k1', userId: 'u', name: 'HA', keyPrefix: 'mindsift_sec_ab', scopes: 'webhook:triage,webhook:list', createdAt: '' })); const updateAPIKey = vi.fn(async () => ({})); vi.mock('../../../lib/api', () => ({ api: { getAPIKeys: vi.fn(async () => [ { id: 'k0', userId: 'u', name: 'Rauchmelder', keyPrefix: 'mindsift_sec_xy', scopes: 'webhook:triage,webhook:task', createdAt: '' }, ]), getAllLists: vi.fn(async () => []), getTaskLists: vi.fn(async () => []), createAPIKey: (...args: unknown[]) => createAPIKey(...(args as [])), deleteAPIKey: vi.fn(), updateAPIKey: (...args: unknown[]) => updateAPIKey(...(args as [])), testWebhookIngest: vi.fn(), }, triggerHaptic: vi.fn(), })); import { ApiKeysPanel } from '../ApiKeysPanel'; describe('ApiKeysPanel', () => { beforeEach(() => createAPIKey.mockClear()); it('shows the rights of existing keys as badges', async () => { render(); expect(await screen.findByText('Rauchmelder')).toBeTruthy(); expect(screen.getByText('Aufgaben anlegen')).toBeTruthy(); expect(screen.getByText('Inbox')).toBeTruthy(); }); it('creates a key with the chosen scopes and never without one', async () => { render(); const triage = screen.getByRole('switch', { name: 'Inbox' }); fireEvent.click(triage); // last remaining scope cannot be switched off expect(triage.getAttribute('aria-checked')).toBe('true'); fireEvent.click(screen.getByRole('switch', { name: 'Listeneinträge hinzufügen' })); await act(async () => { fireEvent.click(screen.getByRole('button', { name: /API-Key erzeugen/ })); }); expect(createAPIKey).toHaveBeenCalledWith('Home Assistant', ['webhook:triage', 'webhook:list']); }); it('shows curl for scripts and, in the second tab, how to connect an MCP client', async () => { render(); fireEvent.click(screen.getByRole('switch', { name: 'Aufgaben ändern' })); expect(screen.getByRole('switch', { name: 'Aufgaben ändern' }).getAttribute('aria-checked')).toBe('true'); expect(screen.getAllByText(/tasks\?due=today&status=open/).length).toBeGreaterThan(0); expect(screen.queryByText(/claude mcp add/)).toBeNull(); fireEvent.click(screen.getByRole('tab', { name: /KI-Agenten/ })); expect(screen.getByText(/claude mcp add --transport http mindsift/)).toBeTruthy(); fireEvent.click(screen.getByRole('radio', { name: 'OpenAI Codex' })); expect(screen.getByText(/\[mcp_servers\.mindsift\]/)).toBeTruthy(); }); it('renames a key and changes its rights', async () => { render(); fireEvent.click(await screen.findByRole('button', { name: 'API-Key Rauchmelder bearbeiten' })); fireEvent.change(screen.getByLabelText('Name des Schlüssels'), { target: { value: 'Rauchmelder Flur' } }); const group = screen.getByRole('group', { name: 'Berechtigungen von Rauchmelder' }); fireEvent.click(within(group).getByRole('switch', { name: 'Aufgaben lesen' })); await act(async () => { fireEvent.click(screen.getByRole('button', { name: 'Speichern' })); }); expect(updateAPIKey).toHaveBeenCalledWith('k0', { name: 'Rauchmelder Flur', scopes: ['webhook:triage', 'webhook:task', 'tasks:read'], }); }); });