feat: add GitHub skill installation support
- Implemented functionality to install skills from GitHub URLs. - Updated API to handle new installation requests from GitHub. - Enhanced UI to allow users to input GitHub skill URLs for installation. - Added translations for new GitHub installation features in English, Thai, and Chinese. - Created tests for the new skill installation service and API routes to ensure proper functionality.
This commit is contained in:
152
tests/skills-routes.test.ts
Normal file
152
tests/skills-routes.test.ts
Normal file
@@ -0,0 +1,152 @@
|
||||
// @vitest-environment node
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
const mocks = vi.hoisted(() => ({
|
||||
install: vi.fn(),
|
||||
getAllSkillConfigs: vi.fn(),
|
||||
updateSkillConfig: vi.fn(),
|
||||
openPath: vi.fn(),
|
||||
MockSkillInstallServiceError: class MockSkillInstallServiceError extends Error {
|
||||
status: number;
|
||||
code: string;
|
||||
|
||||
constructor(message: string, status: number, code: string) {
|
||||
super(message);
|
||||
this.status = status;
|
||||
this.code = code;
|
||||
}
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock('@service/skill-install-service', () => ({
|
||||
SkillInstallService: class {
|
||||
install = mocks.install;
|
||||
},
|
||||
SkillInstallServiceError: mocks.MockSkillInstallServiceError,
|
||||
}));
|
||||
|
||||
vi.mock('../electron/utils/skill-config', () => ({
|
||||
getAllSkillConfigs: mocks.getAllSkillConfigs,
|
||||
updateSkillConfig: mocks.updateSkillConfig,
|
||||
}));
|
||||
|
||||
vi.mock('../electron/utils/paths', () => ({
|
||||
getOpenClawConfigDir: () => 'C:/Users/Administrator/.openclaw',
|
||||
}));
|
||||
|
||||
vi.mock('electron', () => ({
|
||||
shell: {
|
||||
openPath: mocks.openPath,
|
||||
},
|
||||
}));
|
||||
|
||||
import { normalizeRequest } from '../electron/api/route-utils';
|
||||
import { handleSkillRoutes } from '../electron/api/routes/skills';
|
||||
|
||||
const ctx = {
|
||||
gatewayManager: null,
|
||||
providerApiService: null,
|
||||
mainWindow: null,
|
||||
clawHubService: {
|
||||
getMarketplaceCapability: vi.fn(),
|
||||
search: vi.fn(),
|
||||
install: vi.fn(),
|
||||
uninstall: vi.fn(),
|
||||
listInstalled: vi.fn(),
|
||||
openSkillReadme: vi.fn(),
|
||||
openSkillPath: vi.fn(),
|
||||
},
|
||||
} as any;
|
||||
|
||||
describe('skill install routes', () => {
|
||||
beforeEach(() => {
|
||||
mocks.install.mockReset();
|
||||
mocks.getAllSkillConfigs.mockReset();
|
||||
mocks.updateSkillConfig.mockReset();
|
||||
mocks.openPath.mockReset();
|
||||
});
|
||||
|
||||
it('keeps /api/clawhub/install compatible with the marketplace payload', async () => {
|
||||
mocks.install.mockResolvedValue({
|
||||
success: true,
|
||||
slug: 'demo-skill',
|
||||
baseDir: 'C:/Users/Administrator/.openclaw/skills/demo-skill',
|
||||
source: 'marketplace',
|
||||
enabled: true,
|
||||
});
|
||||
|
||||
const response = await handleSkillRoutes(normalizeRequest({
|
||||
path: '/api/clawhub/install',
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
slug: 'demo-skill',
|
||||
version: '1.2.3',
|
||||
force: true,
|
||||
}),
|
||||
}), ctx);
|
||||
|
||||
expect(mocks.install).toHaveBeenCalledWith({
|
||||
kind: 'marketplace',
|
||||
slug: 'demo-skill',
|
||||
version: '1.2.3',
|
||||
force: true,
|
||||
});
|
||||
expect(response?.ok).toBe(true);
|
||||
expect(response?.json).toMatchObject({
|
||||
success: true,
|
||||
slug: 'demo-skill',
|
||||
source: 'marketplace',
|
||||
});
|
||||
});
|
||||
|
||||
it('handles /api/skills/install for github-url payloads', async () => {
|
||||
mocks.install.mockResolvedValue({
|
||||
success: true,
|
||||
slug: 'minimax-xlsx',
|
||||
baseDir: 'C:/Users/Administrator/.openclaw/skills/minimax-xlsx',
|
||||
source: 'github-url',
|
||||
enabled: true,
|
||||
});
|
||||
|
||||
const response = await handleSkillRoutes(normalizeRequest({
|
||||
path: '/api/skills/install',
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
kind: 'github-url',
|
||||
url: 'https://github.com/MiniMax-AI/skills/blob/main/skills/minimax-xlsx/SKILL.md',
|
||||
}),
|
||||
}), ctx);
|
||||
|
||||
expect(mocks.install).toHaveBeenCalledWith({
|
||||
kind: 'github-url',
|
||||
url: 'https://github.com/MiniMax-AI/skills/blob/main/skills/minimax-xlsx/SKILL.md',
|
||||
});
|
||||
expect(response?.ok).toBe(true);
|
||||
expect(response?.json).toMatchObject({
|
||||
success: true,
|
||||
slug: 'minimax-xlsx',
|
||||
source: 'github-url',
|
||||
});
|
||||
});
|
||||
|
||||
it('returns the service status code when install validation fails', async () => {
|
||||
mocks.install.mockRejectedValue(new mocks.MockSkillInstallServiceError(
|
||||
'GitHub skill URL is invalid.',
|
||||
400,
|
||||
'invalid_github_url',
|
||||
));
|
||||
|
||||
const response = await handleSkillRoutes(normalizeRequest({
|
||||
path: '/api/skills/install',
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
kind: 'github-url',
|
||||
url: 'https://example.com/not-supported',
|
||||
}),
|
||||
}), ctx);
|
||||
|
||||
expect(response?.ok).toBe(false);
|
||||
expect(response?.status).toBe(400);
|
||||
expect(response?.error).toBe('GitHub skill URL is invalid.');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user