We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/starlink-awaken/mcp-openclaw'
If you have feedback or need assistance with the MCP directory API, please join our Discord server
/**
* Unit tests for OpenClaw Client
*/
import { OpenClawClient, OpenClawApiError } from '../src/openclaw-client.js';
import type {
SendMessageParams,
ExecuteCommandParams,
CreateCalendarEventParams,
SendEmailParams,
GetTaskStatusParams,
} from '../src/types.js';
// Mock axios to avoid actual HTTP calls
jest.mock('axios', () => {
const mockAxios = {
create: jest.fn(() => mockAxios),
request: jest.fn(),
interceptors: {
response: {
use: jest.fn(),
},
},
};
return mockAxios;
});
import axios from 'axios';
const mockedAxios = axios as jest.Mocked<typeof axios>;
describe('OpenClawClient', () => {
let client: OpenClawClient;
beforeEach(() => {
// Reset mocks
jest.clearAllMocks();
// Create client instance
client = new OpenClawClient({
apiUrl: 'https://api.test.com',
apiKey: 'test-api-key',
timeout: 10000,
});
// Mock the axios instance returned by create
const mockInstance = {
request: jest.fn(),
interceptors: {
response: {
use: jest.fn(),
},
},
};
(mockedAxios.create as jest.Mock).mockReturnValue(mockInstance as any);
(mockedAxios.request as jest.Mock) = mockInstance.request;
});
describe('Initialization', () => {
it('should create client with correct config', () => {
expect(client).toBeInstanceOf(OpenClawClient);
});
it('should use default timeout when not provided', () => {
const defaultClient = new OpenClawClient({
apiUrl: 'https://api.test.com',
apiKey: 'test-key',
});
expect(defaultClient).toBeInstanceOf(OpenClawClient);
});
});
describe('sendMessage', () => {
it('should send message successfully', async () => {
const mockResponse = { success: true, messageId: 'msg-123' };
(mockedAxios.request as jest.Mock).mockResolvedValue({ data: mockResponse });
const params: SendMessageParams = {
platform: 'telegram',
recipient: '@testuser',
message: 'Hello',
};
const result = await client.sendMessage(params);
expect(result).toEqual(mockResponse);
});
it('should handle API errors', async () => {
(mockedAxios.request as jest.Mock).mockRejectedValue({
response: {
status: 400,
data: { code: 'INVALID_INPUT', message: 'Invalid recipient' },
},
});
const params: SendMessageParams = {
platform: 'telegram',
recipient: 'invalid',
message: 'Test',
};
const result = await client.sendMessage(params);
expect(result.success).toBe(false);
expect(result.error).toBeDefined();
});
it('should handle network errors', async () => {
(mockedAxios.request as jest.Mock).mockRejectedValue({
request: {},
});
const params: SendMessageParams = {
platform: 'telegram',
recipient: '@test',
message: 'Test',
};
const result = await client.sendMessage(params);
expect(result.success).toBe(false);
expect(result.error).toContain('No response');
});
});
describe('executeCommand', () => {
it('should execute command successfully', async () => {
const mockResponse = {
success: true,
output: 'Hello, World!',
exitCode: 0,
};
(mockedAxios.request as jest.Mock).mockResolvedValue({ data: mockResponse });
const params: ExecuteCommandParams = {
command: 'echo "Hello, World!"',
timeout: 30,
};
const result = await client.executeCommand(params);
expect(result).toEqual(mockResponse);
});
it('should execute async command and return task ID', async () => {
const mockResponse = {
success: true,
taskId: 'task-abc123',
};
(mockedAxios.request as jest.Mock).mockResolvedValue({ data: mockResponse });
const params: ExecuteCommandParams = {
command: 'npm install',
async: true,
};
const result = await client.executeCommand(params);
expect(result.success).toBe(true);
expect(result.taskId).toBe('task-abc123');
});
});
describe('createCalendarEvent', () => {
it('should create calendar event successfully', async () => {
const mockResponse = {
success: true,
eventId: 'event-456',
};
(mockedAxios.request as jest.Mock).mockResolvedValue({ data: mockResponse });
const params: CreateCalendarEventParams = {
title: 'Test Event',
startTime: '2024-12-15T10:00:00Z',
endTime: '2024-12-15T11:00:00Z',
};
const result = await client.createCalendarEvent(params);
expect(result).toEqual(mockResponse);
});
it('should handle event creation failure', async () => {
(mockedAxios.request as jest.Mock).mockRejectedValue({
response: {
status: 409,
data: { code: 'CONFLICT', message: 'Event conflicts with existing event' },
},
});
const params: CreateCalendarEventParams = {
title: 'Conflict Event',
startTime: '2024-12-15T10:00:00Z',
};
const result = await client.createCalendarEvent(params);
expect(result.success).toBe(false);
expect(result.error).toContain('conflicts');
});
});
describe('sendEmail', () => {
it('should send email successfully', async () => {
const mockResponse = {
success: true,
messageId: 'email-789',
};
(mockedAxios.request as jest.Mock).mockResolvedValue({ data: mockResponse });
const params: SendEmailParams = {
to: 'test@example.com',
subject: 'Test Email',
body: 'Test body',
};
const result = await client.sendEmail(params);
expect(result).toEqual(mockResponse);
});
it('should handle multiple recipients', async () => {
const mockResponse = {
success: true,
messageId: 'email-multiple',
};
(mockedAxios.request as jest.Mock).mockResolvedValue({ data: mockResponse });
const params: SendEmailParams = {
to: ['user1@example.com', 'user2@example.com'],
subject: 'Group Email',
body: 'Hello everyone',
};
const result = await client.sendEmail(params);
expect(result.success).toBe(true);
});
it('should handle invalid email format', async () => {
const mockResponse = {
success: false,
error: 'Invalid email format',
};
(mockedAxios.request as jest.Mock).mockResolvedValue({ data: mockResponse });
const params: SendEmailParams = {
to: 'invalid-email',
subject: 'Test',
body: 'Test',
};
const result = await client.sendEmail(params);
expect(result.success).toBe(false);
});
});
describe('getTaskStatus', () => {
it('should return task status', async () => {
const mockResponse = {
success: true,
taskId: 'task-abc',
status: 'completed' as const,
output: 'Done',
exitCode: 0,
};
(mockedAxios.request as jest.Mock).mockResolvedValue({ data: mockResponse });
const params: GetTaskStatusParams = {
taskId: 'task-abc',
};
const result = await client.getTaskStatus(params);
expect(result.status).toBe('completed');
expect(result.output).toBe('Done');
});
it('should handle task not found', async () => {
(mockedAxios.request as jest.Mock).mockRejectedValue({
response: {
status: 404,
data: { code: 'NOT_FOUND', message: 'Task not found' },
},
});
const params: GetTaskStatusParams = {
taskId: 'nonexistent',
};
const result = await client.getTaskStatus(params);
expect(result.success).toBe(false);
expect(result.error).toContain('not found');
});
});
describe('healthCheck', () => {
it('should return healthy status', async () => {
const mockResponse = {
healthy: true,
version: '1.0.0',
};
(mockedAxios.request as jest.Mock).mockResolvedValue({ data: mockResponse });
const result = await client.healthCheck();
expect(result.healthy).toBe(true);
expect(result.version).toBe('1.0.0');
});
it('should return unhealthy on error', async () => {
(mockedAxios.request as jest.Mock).mockRejectedValue(new Error('Connection failed'));
const result = await client.healthCheck();
expect(result.healthy).toBe(false);
});
});
});
describe('createClientFromEnv', () => {
const originalEnv = process.env;
afterEach(() => {
process.env = originalEnv;
});
it('should create client from environment variables', () => {
process.env.OPENCLAW_API_URL = 'https://api.from-env.com';
process.env.OPENCLAW_API_KEY = 'env-api-key';
// Dynamic import to avoid loading module at top level
const { createClientFromEnv } = require('../src/openclaw-client');
const client = createClientFromEnv();
expect(client).toBeInstanceOf(OpenClawClient);
});
it('should throw error when API URL is missing', () => {
delete process.env.OPENCLAW_API_URL;
process.env.OPENCLAW_API_KEY = 'key';
const { createClientFromEnv } = require('../src/openclaw-client');
expect(() => createClientFromEnv()).toThrow('OPENCLAW_API_URL environment variable is required');
});
it('should throw error when API key is missing', () => {
process.env.OPENCLAW_API_URL = 'https://api.test.com';
delete process.env.OPENCLAW_API_KEY;
const { createClientFromEnv } = require('../src/openclaw-client');
expect(() => createClientFromEnv()).toThrow('OPENCLAW_API_KEY environment variable is required');
});
});