Files
makelore/tests/unit/project-plugins-page.test.tsx

96 lines
5.8 KiB
TypeScript

import { fireEvent, render, screen } from '@testing-library/react';
import { MemoryRouter } from 'react-router-dom';
import { describe, expect, it, vi } from 'vitest';
import { ProjectPluginsView } from '@/pages/ProjectPlugins';
import type { CodingPluginProject } from '@/lib/coding-plugins';
function projection(): CodingPluginProject {
return {
schemaVersion: 1,
project: { localProjectId: 'local-only-id', durableProjectId: '11111111-1111-4111-8111-111111111111' },
policyStatus: 'current',
unknownPluginIds: [],
items: [{
id: 'makelore.data-service', version: '1.0.0', displayName: '开发数据服务', description: '为当前项目提供 JSON 数据。',
contractVersion: 1, requiresBackend: true,
enabled: false, state: 'disabled', backend: { status: 'unconfigured' },
skills: [{ id: 'data-service', assignedAgentIds: ['agent-1'] }],
capabilities: [
{ id: 'data-service.control', operations: [{
id: 'inspect',
billing: { mode: 'included', availability: 'available', notice: 'Fixed quotas apply' },
tool: {
name: 'data_service_inspect', label: 'Inspect', description: 'Inspect data',
mutation: 'read', permissions: ['project.data.read'],
},
}] },
{ id: 'data-service.documents', operations: [{
id: 'put_document',
billing: { mode: 'external_account', availability: 'available', notice: 'Provider billed' },
tool: {
name: 'data_service_put_document', label: 'Put', description: 'Put data',
mutation: 'write', permissions: ['project.data.write'],
},
}] },
{ id: 'data-service.preview', operations: [{
id: 'get',
billing: { mode: 'platform_metered', availability: 'unavailable', notice: 'Pricing unavailable' },
tool: null,
}] },
],
settingsSurface: 'data-service',
}],
};
}
describe('Project Plugin Center', () => {
it('uses available/enabled language, text states, exact included copy, and never renders project IDs', () => {
const onSetEnabled = vi.fn();
render(<MemoryRouter><ProjectPluginsView projectName="Demo" projection={projection()} dataService={null} pending={{}} agentNames={{ 'agent-1': '小明' }} onRefresh={vi.fn()} onSetEnabled={onSetEnabled} onConfigure={vi.fn()} onReset={vi.fn()} onRemoveCollection={vi.fn()} onRemoveProject={vi.fn()} /></MemoryRouter>);
expect(screen.getByRole('heading', { name: '项目插件' })).toHaveClass('text-balance');
expect(screen.getAllByText('未启用').length).toBeGreaterThan(0);
expect(screen.getByText('当前包含,不按单次调用扣点')).toBeVisible();
expect(screen.getByText('小明')).toBeVisible();
expect(screen.getByText('data-service.control')).toBeVisible();
expect(screen.getByText('data-service.documents')).toBeVisible();
expect(screen.getByText('data-service.preview')).toBeVisible();
expect(screen.getByText('data_service_inspect')).toBeVisible();
expect(screen.getByText('SDK')).toBeVisible();
expect(screen.getByText('由外部服务商计费,不计入 Token Point。')).toBeVisible();
expect(screen.getByText('计费策略暂不可用,相关调用已停用。')).toBeVisible();
expect(screen.queryByText('local-only-id')).not.toBeInTheDocument();
expect(screen.queryByText('11111111-1111-4111-8111-111111111111')).not.toBeInTheDocument();
fireEvent.click(screen.getByRole('button', { name: '启用到项目开发数据服务' }));
expect(onSetEnabled).toHaveBeenCalledWith('makelore.data-service', true);
});
it('keeps the last project structure visible when refresh is degraded', () => {
render(<MemoryRouter><ProjectPluginsView projectName="Demo" projection={projection()} dataService={null} pending={{}} agentNames={{}} refreshError="network unavailable" onRefresh={vi.fn()} onSetEnabled={vi.fn()} onConfigure={vi.fn()} onReset={vi.fn()} onRemoveCollection={vi.fn()} onRemoveProject={vi.fn()} /></MemoryRouter>);
expect(screen.getByRole('status')).toHaveTextContent('刷新失败');
expect(screen.getByRole('article')).toBeVisible();
});
it('explains unknown billing and keeps invocation unavailable', () => {
const value = projection();
value.items[0].state = 'unavailable';
value.items[0].capabilities = [value.items[0].capabilities[0]];
value.items[0].capabilities[0].operations[0].billing = { mode: 'platform_metered', availability: 'unavailable', notice: 'pricing unavailable' };
render(<MemoryRouter><ProjectPluginsView projectName="Demo" projection={value} dataService={null} pending={{}} agentNames={{}} onRefresh={vi.fn()} onSetEnabled={vi.fn()} onConfigure={vi.fn()} onReset={vi.fn()} onRemoveCollection={vi.fn()} onRemoveProject={vi.fn()} /></MemoryRouter>);
expect(screen.getByText('计费策略暂不可用,相关调用已停用。')).toBeVisible();
expect(screen.getByRole('button', { name: '启用到项目开发数据服务' })).toBeDisabled();
});
it('shows retained unknown IDs without invented metadata and allows only explicit disable', () => {
const value = projection();
value.unknownPluginIds = ['makelore.removed'];
const onSetEnabled = vi.fn();
render(<MemoryRouter><ProjectPluginsView projectName="Demo" projection={value} dataService={null} pending={{}} agentNames={{}} onRefresh={vi.fn()} onSetEnabled={onSetEnabled} onConfigure={vi.fn()} onReset={vi.fn()} onRemoveCollection={vi.fn()} onRemoveProject={vi.fn()} /></MemoryRouter>);
expect(screen.getByText('配置保留、当前不可用')).toBeVisible();
expect(screen.getByText('makelore.removed')).toBeVisible();
expect(screen.queryByText(/makelore.removed.*v\d/u)).not.toBeInTheDocument();
fireEvent.click(screen.getByRole('button', { name: '从项目禁用保留插件 makelore.removed' }));
expect(onSetEnabled).toHaveBeenCalledWith('makelore.removed', false);
});
});