@chargetrip/mcp
Version:
Chargetrip MCP server
415 lines (348 loc) • 14.4 kB
text/typescript
import { GraphQLError } from 'graphql';
import { FetchAndProcessUtil } from '../fetch-and-process';
import { GraphQLClient } from '../graphql-client';
jest.mock('../graphql-client');
describe('FetchAndProcessUtil', () => {
let mockGraphQLClient: jest.Mocked<GraphQLClient>;
beforeEach(() => {
mockGraphQLClient = {
query: jest.fn(),
mutate: jest.fn(),
subscription: jest.fn(),
} as any;
(GraphQLClient.getInstance as jest.Mock).mockReturnValue(mockGraphQLClient);
});
afterEach(() => {
jest.clearAllMocks();
});
describe('getList', () => {
const mockQuery = 'query { list { id name } }';
const mockVariables = { filter: 'test' };
const mockMapFunction = (item: { id: string; name: string }) => `${item.id}: ${item.name}`;
it('should return formatted list when data is successfully fetched', async () => {
const mockData = {
list: [
{ id: '1', name: 'Item 1' },
{ id: '2', name: 'Item 2' },
],
};
// @ts-ignore: Ignoring type errors for testing purposes
mockGraphQLClient.query.mockResolvedValue({ data: mockData, error: null });
const result = await FetchAndProcessUtil.getList({
query: mockQuery,
variables: mockVariables,
mapFunction: mockMapFunction,
});
expect(result.content).toHaveLength(4);
expect(result.content[0]).toEqual({
type: 'text',
text: 'Here is the response of the API for the list:',
});
expect(result.content[1]).toEqual({ type: 'text', text: '1: Item 1\n2: Item 2' });
expect(result.content[2]).toEqual({
type: 'text',
text: 'Here is the query that was used to fetch the list:',
});
expect(result.content[3]).toEqual({
type: 'text',
text: `Query: "${mockQuery}"\nVariables: "${JSON.stringify(mockVariables, null, 2)}"`,
});
});
it('should handle GraphQL error from response', async () => {
mockGraphQLClient.query.mockResolvedValue({
data: null,
// @ts-ignore: Ignoring type errors for testing purposes
error: { message: 'GraphQL error message' },
});
const result = await FetchAndProcessUtil.getList({
query: mockQuery,
variables: mockVariables,
mapFunction: mockMapFunction,
});
expect(result.content).toHaveLength(1);
expect(result.content[0]).toEqual({
type: 'text',
text: 'GraphQL error occurred while fetching the list: GraphQL error message',
});
});
it('should handle empty list', async () => {
// @ts-ignore: Ignoring type errors for testing purposes
mockGraphQLClient.query.mockResolvedValue({ data: { list: [] }, error: null });
const result = await FetchAndProcessUtil.getList({
query: mockQuery,
variables: mockVariables,
mapFunction: mockMapFunction,
});
expect(result.content).toHaveLength(1);
expect(result.content[0]).toEqual({
type: 'text',
text: 'Unexpected error occurred while fetching the list: No data found or an error occurred while fetching the list.',
});
});
it('should handle null data', async () => {
// @ts-ignore: Ignoring type errors for testing purposes
mockGraphQLClient.query.mockResolvedValue({ data: null, error: null });
const result = await FetchAndProcessUtil.getList({
query: mockQuery,
variables: mockVariables,
mapFunction: mockMapFunction,
});
expect(result.content).toHaveLength(1);
expect(result.content[0]).toEqual({
type: 'text',
text: 'Unexpected error occurred while fetching the list: No data found or an error occurred while fetching the list.',
});
});
it('should handle unexpected errors', async () => {
mockGraphQLClient.query.mockRejectedValue(new Error('Network error'));
const result = await FetchAndProcessUtil.getList({
query: mockQuery,
variables: mockVariables,
mapFunction: mockMapFunction,
});
expect(result.content).toHaveLength(1);
expect(result.content[0]).toEqual({
type: 'text',
text: 'Unexpected error occurred while fetching the list: Network error',
});
});
it('should handle non-Error exceptions', async () => {
mockGraphQLClient.query.mockRejectedValue('String error');
const result = await FetchAndProcessUtil.getList({
query: mockQuery,
variables: mockVariables,
mapFunction: mockMapFunction,
});
expect(result.content).toHaveLength(1);
expect(result.content[0]).toEqual({
type: 'text',
text: 'Unexpected error occurred while fetching the list: String error',
});
});
});
describe('getItem', () => {
const mockItemName = 'test-item';
const mockQuery = 'query { item { id name } }';
const mockVariables = { id: '1' };
const mockMapFunction = (item: { id: string; name: string }) => `${item.id}: ${item.name}`;
it('should return formatted item when query is successful', async () => {
const mockData = { item: { id: '1', name: 'Test Item' } };
// @ts-ignore: Ignoring type errors for testing purposes
mockGraphQLClient.query.mockResolvedValue({ data: mockData, error: null });
const result = await FetchAndProcessUtil.getItem({
itemName: mockItemName,
query: mockQuery,
variables: mockVariables,
mapFunction: mockMapFunction,
});
expect(result.content).toHaveLength(4);
expect(result.content[0]).toEqual({
type: 'text',
text: `Here is the response of the API for the ${mockItemName}:`,
});
expect(result.content[1]).toEqual({ type: 'text', text: '1: Test Item' });
expect(result.content[2]).toEqual({
type: 'text',
text: `Here is the query that was used to fetch the ${mockItemName}:`,
});
});
it('should use mutation when operationType is mutation', async () => {
const mockData = { item: { id: '1', name: 'Test Item' } };
// @ts-ignore: Ignoring type errors for testing purposes
mockGraphQLClient.mutate.mockResolvedValue({ data: mockData, error: null });
await FetchAndProcessUtil.getItem({
itemName: mockItemName,
query: mockQuery,
variables: mockVariables,
operationType: 'mutation',
mapFunction: mockMapFunction,
});
expect(mockGraphQLClient.mutate).toHaveBeenCalledWith(mockQuery, mockVariables);
expect(mockGraphQLClient.query).not.toHaveBeenCalled();
});
it('should use query when operationType is query', async () => {
const mockData = { item: { id: '1', name: 'Test Item' } };
// @ts-ignore: Ignoring type errors for testing purposes
mockGraphQLClient.query.mockResolvedValue({ data: mockData, error: null });
await FetchAndProcessUtil.getItem({
itemName: mockItemName,
query: mockQuery,
variables: mockVariables,
operationType: 'query',
mapFunction: mockMapFunction,
});
expect(mockGraphQLClient.query).toHaveBeenCalledWith(mockQuery, mockVariables);
expect(mockGraphQLClient.mutate).not.toHaveBeenCalled();
});
it('should handle GraphQL error from response', async () => {
mockGraphQLClient.query.mockResolvedValue({
data: null,
// @ts-ignore: Ignoring type errors for testing purposes
error: { message: 'Item not found' },
});
const result = await FetchAndProcessUtil.getItem({
itemName: mockItemName,
query: mockQuery,
variables: mockVariables,
mapFunction: mockMapFunction,
});
expect(result.content).toHaveLength(1);
expect(result.content[0]).toEqual({
type: 'text',
text: `GraphQL error occurred while fetching the ${mockItemName}: Item not found`,
});
});
it('should handle null item data', async () => {
// @ts-ignore: Ignoring type errors for testing purposes
mockGraphQLClient.query.mockResolvedValue({ data: { item: null }, error: null });
const result = await FetchAndProcessUtil.getItem({
itemName: mockItemName,
query: mockQuery,
variables: mockVariables,
mapFunction: mockMapFunction,
});
expect(result.content).toHaveLength(1);
expect(result.content[0]).toEqual({
type: 'text',
text: `Unexpected error occurred while fetching the ${mockItemName}: No data found or an error occurred while fetching the data.`,
});
});
it('should handle unexpected errors', async () => {
mockGraphQLClient.query.mockRejectedValue(new Error('Network error'));
const result = await FetchAndProcessUtil.getItem({
itemName: mockItemName,
query: mockQuery,
variables: mockVariables,
mapFunction: mockMapFunction,
});
expect(result.content).toHaveLength(1);
expect(result.content[0]).toEqual({
type: 'text',
text: `Unexpected error occurred while fetching the ${mockItemName}: Network error`,
});
});
it('should handle non-Error exceptions', async () => {
mockGraphQLClient.query.mockRejectedValue('String error');
const result = await FetchAndProcessUtil.getItem({
itemName: mockItemName,
query: mockQuery,
variables: mockVariables,
mapFunction: mockMapFunction,
});
expect(result.content).toHaveLength(1);
expect(result.content[0]).toEqual({
type: 'text',
text: `Unexpected error occurred while fetching the ${mockItemName}: String error`,
});
});
});
describe('getItemFromSubscription', () => {
const mockItemName = 'subscription-item';
const mockQuery = 'subscription { item { id status } }';
const mockVariables = { id: '1' };
const mockMapFunction = (item: { id: string; status: string }) => `${item.id}: ${item.status}`;
const mockSubscribeFunction = (item: { id: string; status: string }) =>
item.status === 'completed';
it('should return formatted item when subscription resolves', async () => {
const mockData = { id: '1', status: 'completed' };
const mockUnsubscribe = jest.fn();
const mockSubscribe = jest.fn(callback => {
setTimeout(() => callback({ data: mockData }), 0);
return { unsubscribe: mockUnsubscribe };
});
// @ts-ignore: Ignoring type errors for testing purposes
mockGraphQLClient.subscription.mockReturnValue({ subscribe: mockSubscribe });
const result = await FetchAndProcessUtil.getItemFromSubscription({
itemName: mockItemName,
query: mockQuery,
variables: mockVariables,
subscribeFunction: mockSubscribeFunction,
mapFunction: mockMapFunction,
});
expect(result.content).toHaveLength(4);
expect(result.content[0]).toEqual({
type: 'text',
text: `Here is the response of the API for the ${mockItemName}:`,
});
expect(result.content[1]).toEqual({ type: 'text', text: '1: completed' });
expect(mockUnsubscribe).toHaveBeenCalled();
});
it('should continue subscription until condition is met', async () => {
const mockUnsubscribe = jest.fn();
let callCount = 0;
const mockSubscribe = jest.fn(callback => {
const interval = setInterval(() => {
callCount++;
const status = callCount < 3 ? 'processing' : 'completed';
callback({ data: { id: '1', status } });
if (status === 'completed') {
clearInterval(interval);
}
}, 0);
return { unsubscribe: mockUnsubscribe };
});
// @ts-ignore: Ignoring type errors for testing purposes
mockGraphQLClient.subscription.mockReturnValue({ subscribe: mockSubscribe });
const result = await FetchAndProcessUtil.getItemFromSubscription({
itemName: mockItemName,
query: mockQuery,
variables: mockVariables,
subscribeFunction: mockSubscribeFunction,
mapFunction: mockMapFunction,
});
expect(result.content[1]).toEqual({ type: 'text', text: '1: completed' });
expect(mockUnsubscribe).toHaveBeenCalled();
});
it('should handle GraphQL errors in subscription', async () => {
mockGraphQLClient.subscription.mockImplementation(() => {
throw new GraphQLError('Subscription error');
});
const result = await FetchAndProcessUtil.getItemFromSubscription({
itemName: mockItemName,
query: mockQuery,
variables: mockVariables,
subscribeFunction: mockSubscribeFunction,
mapFunction: mockMapFunction,
});
expect(result.content).toHaveLength(1);
expect(result.content[0]).toEqual({
type: 'text',
text: 'GraphQL error occurred while waiting for the subscription-item: Subscription error',
});
});
it('should handle unexpected errors in subscription', async () => {
mockGraphQLClient.subscription.mockImplementation(() => {
throw new Error('Network error');
});
const result = await FetchAndProcessUtil.getItemFromSubscription({
itemName: mockItemName,
query: mockQuery,
variables: mockVariables,
subscribeFunction: mockSubscribeFunction,
mapFunction: mockMapFunction,
});
expect(result.content).toHaveLength(1);
expect(result.content[0]).toEqual({
type: 'text',
text: 'Unexpected error occurred while waiting for the subscription-item: Network error',
});
});
it('should handle non-Error exceptions in subscription', async () => {
mockGraphQLClient.subscription.mockImplementation(() => {
throw 'String subscription error';
});
const result = await FetchAndProcessUtil.getItemFromSubscription({
itemName: mockItemName,
query: mockQuery,
variables: mockVariables,
subscribeFunction: mockSubscribeFunction,
mapFunction: mockMapFunction,
});
expect(result.content).toHaveLength(1);
expect(result.content[0]).toEqual({
type: 'text',
text: 'Unexpected error occurred while waiting for the subscription-item: String subscription error',
});
});
});
});