Skip to main content
Glama
setup.ts10.6 kB
import { HttpResponse, http } from "msw"; import { setupServer } from "msw/node"; import { afterEach, beforeEach, expect, vi } from "vitest"; import type { Channel, Chat, ChatMessage, ConversationMember, GraphApiResponse, Team, User, } from "../types/graph.js"; // Mock data fixtures export const mockUser: User = { id: "test-user-id", displayName: "Test User", userPrincipalName: "test.user@example.com", mail: "test.user@example.com", jobTitle: "Test Engineer", department: "Engineering", officeLocation: "Remote", }; export const mockTeam: Team = { id: "test-team-id", displayName: "Test Team", description: "A test team for unit tests", isArchived: false, }; export const mockChannel: Channel = { id: "test-channel-id", displayName: "General", description: "General discussion channel", membershipType: "standard", }; export const mockChat: Chat = { id: "test-chat-id", topic: "Test Chat", chatType: "group", }; export const mockChatMessage: ChatMessage = { id: "test-message-id", createdDateTime: "2024-01-01T12:00:00Z", body: { content: "Test message content", contentType: "text", }, from: { user: { id: "test-user-id", displayName: "Test User", }, }, importance: "normal", }; export const mockConversationMember: ConversationMember = { id: "test-member-id", displayName: "Test Member", roles: ["owner"], }; // Microsoft Graph API mock handlers export const graphApiHandlers = [ // User endpoints http.get("https://graph.microsoft.com/v1.0/me", () => { return HttpResponse.json(mockUser); }), http.get("https://graph.microsoft.com/v1.0/users", ({ request }) => { const url = new URL(request.url); const filter = url.searchParams.get("$filter"); // Simulate search functionality const response: GraphApiResponse<User> = { value: filter?.includes("test") ? [mockUser] : [], }; return HttpResponse.json(response); }), http.get("https://graph.microsoft.com/v1.0/users/:userId", ({ params }) => { if (params.userId === "test-user-id" || params.userId === "test.user@example.com") { return HttpResponse.json(mockUser); } return new HttpResponse(null, { status: 404 }); }), // Teams endpoints http.get("https://graph.microsoft.com/v1.0/me/joinedTeams", () => { const response: GraphApiResponse<Team> = { value: [mockTeam], }; return HttpResponse.json(response); }), http.get("https://graph.microsoft.com/v1.0/teams/:teamId/channels", ({ params }) => { if (params.teamId === "test-team-id") { const response: GraphApiResponse<Channel> = { value: [mockChannel], }; return HttpResponse.json(response); } return new HttpResponse(null, { status: 404 }); }), http.get("https://graph.microsoft.com/v1.0/teams/:teamId/members", ({ params }) => { if (params.teamId === "test-team-id") { const response: GraphApiResponse<ConversationMember> = { value: [mockConversationMember], }; return HttpResponse.json(response); } return new HttpResponse(null, { status: 404 }); }), // Channel messages http.get( "https://graph.microsoft.com/v1.0/teams/:teamId/channels/:channelId/messages", ({ params }) => { if (params.teamId === "test-team-id" && params.channelId === "test-channel-id") { const response: GraphApiResponse<ChatMessage> = { value: [mockChatMessage], }; return HttpResponse.json(response); } return new HttpResponse(null, { status: 404 }); } ), http.post( "https://graph.microsoft.com/v1.0/teams/:teamId/channels/:channelId/messages", async ({ params, request }) => { if (params.teamId === "test-team-id" && params.channelId === "test-channel-id") { const body = (await request.json()) as any; const response = { ...mockChatMessage, id: "new-message-id", body: body.body, createdDateTime: new Date().toISOString(), }; return HttpResponse.json(response); } return new HttpResponse(null, { status: 404 }); } ), // Chats endpoints http.get("https://graph.microsoft.com/v1.0/me/chats", () => { const response: GraphApiResponse<Chat> = { value: [mockChat], }; return HttpResponse.json(response); }), http.get("https://graph.microsoft.com/v1.0/me/chats/:chatId/messages", ({ params, request }) => { if (params.chatId === "test-chat-id") { const url = new URL(request.url); const fromUser = url.searchParams.get("$filter")?.includes("from/user/id"); const response: GraphApiResponse<ChatMessage> = { value: fromUser ? [] : [mockChatMessage], }; return HttpResponse.json(response); } return new HttpResponse(null, { status: 404 }); }), http.post( "https://graph.microsoft.com/v1.0/me/chats/:chatId/messages", async ({ params, request }) => { if (params.chatId === "test-chat-id") { const body = (await request.json()) as any; const response = { ...mockChatMessage, id: "new-chat-message-id", body: body.body, createdDateTime: new Date().toISOString(), }; return HttpResponse.json(response); } return new HttpResponse(null, { status: 404 }); } ), http.post("https://graph.microsoft.com/v1.0/me/chats", async ({ request }) => { const body = (await request.json()) as any; const response = { ...mockChat, id: "new-chat-id", topic: body.topic, chatType: body.chatType, }; return HttpResponse.json(response); }), // Search endpoints http.post("https://graph.microsoft.com/v1.0/search/query", async ({ request }) => { const body = (await request.json()) as any; const searchRequest = body.requests[0]; const response = { value: [ { searchTerms: [searchRequest.query.queryString], hitsContainers: [ { hits: [ { hitId: "search-hit-1", rank: 1, summary: "Test message found in search", resource: { "@odata.type": "#microsoft.graph.chatMessage", id: "search-message-id", createdDateTime: "2024-01-01T12:00:00Z", from: { user: { displayName: "Test User", id: "test-user-id", }, }, body: { content: "Test search result message", contentType: "text", }, chatId: "test-chat-id", }, }, ], total: 1, moreResultsAvailable: false, }, ], }, ], }; return HttpResponse.json(response); }), // Error scenarios for testing http.get("https://graph.microsoft.com/v1.0/error/401", () => { return HttpResponse.json( { error: { code: "InvalidAuthenticationToken", message: "Access token is empty.", }, }, { status: 401 } ); }), http.get("https://graph.microsoft.com/v1.0/error/403", () => { return HttpResponse.json( { error: { code: "Forbidden", message: "Insufficient privileges to complete the operation.", }, }, { status: 403 } ); }), http.get("https://graph.microsoft.com/v1.0/error/429", () => { return HttpResponse.json( { error: { code: "TooManyRequests", message: "Too many requests", }, }, { status: 429, headers: { "Retry-After": "30" } } ); }), ]; // Setup MSW server export const server = setupServer(...graphApiHandlers); // Global test setup beforeEach(() => { // Reset all mocks before each test vi.clearAllMocks(); // Mock file system operations for token storage vi.mock("node:fs", async () => { const actual = (await vi.importActual("node:fs")) as any; return { ...actual, promises: { ...(actual.promises || {}), readFile: vi.fn(), writeFile: vi.fn(), unlink: vi.fn(), access: vi.fn(), }, }; }); // Mock Azure identity vi.mock("@azure/identity", () => ({ DeviceCodeCredential: vi.fn(), })); }); afterEach(() => { // Clean up after each test vi.resetAllMocks(); }); // Helper function to create mock authenticated GraphService export function createMockGraphService() { const GraphService = vi.fn().mockImplementation(() => ({ getInstance: vi.fn().mockReturnThis(), getAuthStatus: vi.fn().mockResolvedValue({ isAuthenticated: true, userPrincipalName: mockUser.userPrincipalName, displayName: mockUser.displayName, expiresAt: new Date(Date.now() + 3600000).toISOString(), }), getClient: vi.fn().mockResolvedValue({ api: vi.fn().mockReturnValue({ get: vi.fn(), post: vi.fn(), filter: vi.fn().mockReturnThis(), }), }), isAuthenticated: vi.fn().mockReturnValue(true), })); return new GraphService(); } // Helper function to create mock unauthenticated GraphService export function createMockUnauthenticatedGraphService() { const GraphService = vi.fn().mockImplementation(() => ({ getInstance: vi.fn().mockReturnThis(), getAuthStatus: vi.fn().mockResolvedValue({ isAuthenticated: false, }), getClient: vi.fn().mockRejectedValue(new Error("Not authenticated")), isAuthenticated: vi.fn().mockReturnValue(false), })); return new GraphService(); } // Helper function to create mock MCP server export function createMockMcpServer() { const tools = new Map(); return { tool: vi.fn().mockImplementation((name, description, schema, handler) => { tools.set(name, { description, schema, handler }); }), connect: vi.fn(), getTool: (name: string) => tools.get(name), getAllTools: () => Array.from(tools.keys()), }; } // Helper function to test MCP tool execution export async function testMcpTool( toolName: string, parameters: any, mockServer: any, expectedResult?: any ) { const tool = mockServer.getTool(toolName); if (!tool) { throw new Error(`Tool ${toolName} not found`); } const result = await tool.handler(parameters); if (expectedResult) { expect(result).toEqual(expectedResult); } return result; }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/floriscornel/teams-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server