Files
open-design/apps/web/tests/components/AgentDiagnosticRow.test.tsx
T
dbc74a397c feat(agents): CLI detection self-rescue with actionable diagnostics (#3560)
* feat(agents): surface actionable CLI diagnostics

Detect unavailable CLI agents with structured diagnostics, stream agent discovery results to the settings UI, and render actionable fix controls for common setup failures.

Also harden the streamed agents client so server error events and dropped streams surface as failures instead of replacing state with a truncated agent list.

* fix(agents): gate streamed rescan loading

Generated-By: looper 0.9.2 (runner=fixer, agent=codex)

* fix(agents): distinguish non-executable CLI diagnostics

Generated-By: looper 0.9.2 (runner=fixer, agent=codex)

* fix(agents): defer OAuth diagnostics without producer

Generated-By: looper 0.9.2 (runner=fixer, agent=codex)

---------

Co-authored-by: chaoxiaoche <chaoxiaoche@chaoxiaochedeMacBook-Pro.local>
Co-authored-by: Looper <looper@noreply.github.com>
Co-authored-by: Looper Fixer <looper-fixer@noreply.github.com>
Co-authored-by: looper-fixer <looper-fixer@users.noreply.github.com>
2026-06-04 03:18:37 +00:00

53 lines
1.9 KiB
TypeScript

// @vitest-environment jsdom
import { cleanup, fireEvent, render, screen } from '@testing-library/react';
import { afterEach, describe, expect, it, vi } from 'vitest';
import { AgentDiagnosticRow } from '../../src/components/AgentDiagnosticRow';
import type { AgentDiagnostic } from '../../src/types';
import { en } from '../../src/i18n/locales/en';
afterEach(() => {
cleanup();
vi.clearAllMocks();
});
const notOnPath: AgentDiagnostic = {
reason: 'not-on-path',
severity: 'error',
message: 'Gemini (`gemini`) was not found on your PATH.',
searchedDirs: ['/usr/bin', '/opt/homebrew/bin'],
fixActions: [{ kind: 'openInstall' }, { kind: 'rescan' }],
};
describe('AgentDiagnosticRow', () => {
it('renders the daemon message and tags the reason', () => {
render(<AgentDiagnosticRow diagnostic={notOnPath} />);
const group = screen.getByRole('group');
expect(group.getAttribute('data-reason')).toBe('not-on-path');
expect(screen.getByText(notOnPath.message)).toBeTruthy();
});
it('exposes searched dirs via the message tooltip', () => {
render(<AgentDiagnosticRow diagnostic={notOnPath} />);
const title = screen.getByText(notOnPath.message).getAttribute('title') ?? '';
expect(title).toContain('/usr/bin');
expect(title).toContain('/opt/homebrew/bin');
});
it('only renders buttons for intents that have a wired handler', () => {
const onRescan = vi.fn();
// openInstall is in the diagnostic but no onOpenInstall handler is given,
// so only Rescan should render. Actions are icon-only buttons whose
// accessible name comes from the (tooltip) aria-label.
render(<AgentDiagnosticRow diagnostic={notOnPath} handlers={{ onRescan }} />);
expect(
screen.queryByRole('button', { name: en['settings.agentInstall.install'] }),
).toBeNull();
const rescan = screen.getByRole('button', { name: en['settings.rescan'] });
fireEvent.click(rescan);
expect(onRescan).toHaveBeenCalledTimes(1);
});
});