Files
tkmind_go/ui/desktop/src/components/ExtensionInstallModal.test.tsx
T
2025-09-22 15:35:28 -04:00

179 lines
6.0 KiB
TypeScript

/* eslint-disable @typescript-eslint/no-explicit-any */
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
import { render, screen, act } from '@testing-library/react';
import { ExtensionInstallModal } from './ExtensionInstallModal';
import { addExtensionFromDeepLink } from './settings/extensions/deeplink';
vi.mock('./settings/extensions/deeplink', () => ({
addExtensionFromDeepLink: vi.fn(),
}));
const mockElectron = {
getConfig: vi.fn(),
getAllowedExtensions: vi.fn(),
logInfo: vi.fn(),
on: vi.fn(),
off: vi.fn(),
};
(window as any).electron = mockElectron;
describe('ExtensionInstallModal', () => {
const mockAddExtension = vi.fn();
const getAddExtensionEventHandler = () => {
const addExtensionCall = mockElectron.on.mock.calls.find((call) => call[0] === 'add-extension');
expect(addExtensionCall).toBeDefined();
return addExtensionCall![1];
};
beforeEach(() => {
vi.clearAllMocks();
mockElectron.getConfig.mockReturnValue({
GOOSE_ALLOWLIST_WARNING: false,
});
});
afterEach(() => {
vi.clearAllMocks();
});
describe('Extension Request Handling', () => {
it('should handle trusted extension (default behaviour, no allowlist)', async () => {
mockElectron.getAllowedExtensions.mockResolvedValue([]);
render(<ExtensionInstallModal addExtension={mockAddExtension} />);
const eventHandler = getAddExtensionEventHandler();
await act(async () => {
await eventHandler({}, 'goose://extension?cmd=npx&arg=test-extension&name=TestExt');
});
expect(screen.getByRole('dialog')).toBeInTheDocument();
expect(screen.getByText('Confirm Extension Installation')).toBeInTheDocument();
expect(screen.getByText(/TestExt extension/)).toBeInTheDocument();
expect(screen.getAllByRole('button')).toHaveLength(3);
});
it('should handle trusted extension (from allowlist)', async () => {
mockElectron.getAllowedExtensions.mockResolvedValue(['npx test-extension']);
render(<ExtensionInstallModal addExtension={mockAddExtension} />);
const eventHandler = getAddExtensionEventHandler();
await act(async () => {
await eventHandler({}, 'goose://extension?cmd=npx&arg=test-extension&name=AllowedExt');
});
expect(screen.getByText('Confirm Extension Installation')).toBeInTheDocument();
expect(screen.getAllByRole('button')).toHaveLength(3);
});
it('should handle warning mode', async () => {
mockElectron.getConfig.mockReturnValue({
GOOSE_ALLOWLIST_WARNING: true,
});
mockElectron.getAllowedExtensions.mockResolvedValue(['uvx allowed-package']);
render(<ExtensionInstallModal addExtension={mockAddExtension} />);
const eventHandler = getAddExtensionEventHandler();
await act(async () => {
await eventHandler(
{},
'goose://extension?cmd=npx&arg=untrusted-extension&name=UntrustedExt'
);
});
expect(screen.getByText('Install Untrusted Extension?')).toBeInTheDocument();
expect(screen.getByRole('button', { name: 'Install Anyway' })).toBeInTheDocument();
expect(screen.getAllByRole('button')).toHaveLength(3);
});
it("should handle i-ching-mcp-server as allowed command", async () => {
mockElectron.getAllowedExtensions.mockResolvedValue([]);
render(<ExtensionInstallModal addExtension={mockAddExtension} />);
const eventHandler = getAddExtensionEventHandler();
await act(async () => {
await eventHandler({}, "goose://extension?cmd=i-ching-mcp-server&id=i-ching&name=I%20Ching&description=I%20Ching%20divination");
});
expect(screen.getByRole("dialog")).toBeInTheDocument();
expect(screen.getByText("Confirm Extension Installation")).toBeInTheDocument();
expect(screen.getByText(/I Ching extension/)).toBeInTheDocument();
expect(screen.getAllByRole("button")).toHaveLength(3);
});
it('should handle blocked extension', async () => {
mockElectron.getAllowedExtensions.mockResolvedValue(['uvx allowed-package']);
render(<ExtensionInstallModal addExtension={mockAddExtension} />);
const eventHandler = getAddExtensionEventHandler();
await act(async () => {
await eventHandler({}, 'goose://extension?cmd=npx&arg=blocked-extension&name=BlockedExt');
});
expect(screen.getByText('Extension Installation Blocked')).toBeInTheDocument();
expect(screen.getByRole('button', { name: 'OK' })).toBeInTheDocument();
expect(screen.getAllByRole('button')).toHaveLength(2);
expect(screen.getByText(/Contact your administrator/)).toBeInTheDocument();
});
});
describe('Modal Actions', () => {
it('should dismiss modal correctly', async () => {
mockElectron.getAllowedExtensions.mockResolvedValue([]);
render(<ExtensionInstallModal addExtension={mockAddExtension} />);
const eventHandler = getAddExtensionEventHandler();
await act(async () => {
await eventHandler({}, 'goose://extension?cmd=npx&arg=test&name=Test');
});
expect(screen.getByRole('dialog')).toBeInTheDocument();
await act(async () => {
screen.getByRole('button', { name: 'No' }).click();
});
expect(screen.queryByRole('dialog')).not.toBeInTheDocument();
});
it('should handle successful extension installation', async () => {
vi.mocked(addExtensionFromDeepLink).mockResolvedValue(undefined);
mockElectron.getAllowedExtensions.mockResolvedValue([]);
render(<ExtensionInstallModal addExtension={mockAddExtension} />);
const eventHandler = getAddExtensionEventHandler();
await act(async () => {
await eventHandler({}, 'goose://extension?cmd=npx&arg=test&name=Test');
});
await act(async () => {
screen.getByRole('button', { name: 'Yes' }).click();
});
expect(addExtensionFromDeepLink).toHaveBeenCalledWith(
'goose://extension?cmd=npx&arg=test&name=Test',
mockAddExtension,
expect.any(Function)
);
expect(screen.queryByRole('dialog')).not.toBeInTheDocument();
});
});
});