import { act } from 'react'; import { createRoot, type Root } from 'react-dom/client'; import { afterAll, afterEach, beforeAll, describe, expect, it, vi } from 'vitest'; import { CommandsPanel } from './commands-panel'; beforeAll(() => { Object.defineProperty(globalThis, 'IS_REACT_ACT_ENVIRONMENT', { configurable: true, value: true, }); }); afterAll(() => { Reflect.deleteProperty(globalThis, 'IS_REACT_ACT_ENVIRONMENT'); }); let root: Root | null; let container: HTMLElement | null; async function render(node: Parameters[0]): Promise { container = document.createElement('div'); document.body.append(container); root = createRoot(container); await act(async () => { root?.render(node); }); } afterEach(async () => { await act(async () => { root?.unmount(); }); document.body.replaceChildren(); root = null; container = null; }); describe('CommandsPanel', () => { it('shows the frozen local pendingApproval args in the confirmation area, regardless of misleading server message text', async () => { await render( , ); // The exact frozen combined action is visible... expect(container?.textContent).toContain('/deploy'); expect(container?.textContent).toContain('prod'); // ...and the misleading server free-text is never shown next to it. expect(container?.textContent).not.toContain('staging environment'); }); it('does not throw when a manifest commands entry is null', async () => { const manifest = { commands: [ null, { name: 'model', aliases: [], description: 'Change the active model', scope: 'core', execution: 'socket', available: true, }, ], skills: [null], version: 1, } as unknown as Parameters[0]['manifest']; await expect( render( , ), ).resolves.not.toThrow(); expect(container?.textContent).toContain('model'); }); it('shows an explicit no-args fallback when the frozen pendingApproval has no args', async () => { await render( , ); expect(container?.textContent?.toLowerCase()).toContain('no args'); }); it('renders skills from a skills-only manifest', async () => { await render( , ); expect(container?.textContent).toContain('brave-search'); expect(container?.textContent).toContain('Search the web'); }); it('does not show the Run affordance when approval.success/approvalId are objects, even though command matches pendingApproval', async () => { const approval = { conversationId: 'c1', command: 'deploy', success: { truthy: 'object' }, approvalId: { also: 'object' }, } as unknown as Parameters[0]['approval']; await render( , ); expect( [...(container?.querySelectorAll('button') ?? [])].some((button) => button.textContent?.includes('Run approved command'), ), ).toBe(false); }); it('shows the guarded server-provided denial reason for a denied approval', async () => { await render( , ); expect(container?.textContent).toContain('Not authorized'); }); it('falls back to a stable "Denied." copy when a denial has no usable message', async () => { await render( , ); expect(container?.textContent).toContain('Denied.'); }); it('shows the guarded contract-provided reason for a failed command result, falling back to a stable copy only when absent', async () => { await render( , ); expect(container?.textContent).toContain('Unknown model'); expect(container?.textContent).toContain('Command failed.'); }); it('bounds an oversized command result message at the render site as defense-in-depth', async () => { const hostileMessage = 'y'.repeat(50_000); await render( , ); const text = container?.textContent ?? ''; expect(text.length).toBeLessThan(hostileMessage.length); }); it('does not throw when the manifest fields are malformed (non-array commands/skills)', async () => { const manifest = { commands: 'not-an-array', skills: null, version: 1, } as unknown as Parameters[0]['manifest']; await expect( render( , ), ).resolves.not.toThrow(); }); });