/**
* Fizzy MCP Server Tests
*
* API Reference: https://github.com/basecamp/fizzy/blob/main/docs/API.md
*
* This test suite verifies the MCP server correctly registers all 47 tools
* that map to the Fizzy REST API endpoints.
*
* Endpoint Summary (RESTful - no .json extension):
*
* IDENTITY & ACCOUNTS (2 tools)
* GET /my/identity -> fizzy_get_identity
* (accounts from identity) -> fizzy_get_accounts
*
* BOARDS (5 tools)
* GET /:slug/boards -> fizzy_get_boards
* GET /:slug/boards/:id -> fizzy_get_board
* POST /:slug/boards -> fizzy_create_board
* PUT /:slug/boards/:id -> fizzy_update_board
* DELETE /:slug/boards/:id -> fizzy_delete_board
*
* CARDS (5 tools)
* GET /:slug/cards -> fizzy_get_cards
* GET /:slug/cards/:number -> fizzy_get_card
* POST /:slug/boards/:id/cards -> fizzy_create_card
* PUT /:slug/cards/:id -> fizzy_update_card
* DELETE /:slug/cards/:id -> fizzy_delete_card
*
* CARD ACTIONS (9 tools)
* POST /:slug/cards/:n/closure -> fizzy_close_card
* DELETE /:slug/cards/:n/closure -> fizzy_reopen_card
* POST /:slug/cards/:n/not_now -> fizzy_move_card_to_not_now
* POST /:slug/cards/:n/triage -> fizzy_move_card_to_column
* DELETE /:slug/cards/:n/triage -> fizzy_send_card_to_triage
* POST /:slug/cards/:n/taggings -> fizzy_toggle_card_tag
* POST /:slug/cards/:n/assignments -> fizzy_toggle_card_assignment
* POST /:slug/cards/:n/watch -> fizzy_watch_card
* DELETE /:slug/cards/:n/watch -> fizzy_unwatch_card
*
* COMMENTS (5 tools)
* GET /:slug/cards/:id/comments -> fizzy_get_card_comments
* GET /:slug/cards/:n/comments/:id -> fizzy_get_comment
* POST /:slug/cards/:id/comments -> fizzy_create_card_comment
* PUT /:slug/cards/:n/comments/:id -> fizzy_update_comment
* DELETE /:slug/cards/:n/comments/:id -> fizzy_delete_comment
*
* REACTIONS (3 tools)
* GET /:slug/cards/:n/comments/:id/reactions -> fizzy_get_reactions
* POST /:slug/cards/:n/comments/:id/reactions -> fizzy_add_reaction
* DELETE /:slug/cards/:n/comments/:id/reactions/:id -> fizzy_remove_reaction
*
* STEPS (4 tools)
* GET /:slug/cards/:n/steps/:id -> fizzy_get_step
* POST /:slug/cards/:n/steps -> fizzy_create_step
* PUT /:slug/cards/:n/steps/:id -> fizzy_update_step
* DELETE /:slug/cards/:n/steps/:id -> fizzy_delete_step
*
* COLUMNS (5 tools)
* GET /:slug/boards/:id/columns -> fizzy_get_columns
* GET /:slug/boards/:id/columns/:id -> fizzy_get_column
* POST /:slug/boards/:id/columns -> fizzy_create_column
* PUT /:slug/boards/:id/columns/:id -> fizzy_update_column
* DELETE /:slug/boards/:id/columns/:id -> fizzy_delete_column
*
* TAGS (1 tool)
* GET /:slug/tags -> fizzy_get_tags
* (POST/DELETE return 404 - not available via API)
*
* USERS (4 tools)
* GET /:slug/users -> fizzy_get_users
* GET /:slug/users/:id -> fizzy_get_user
* PUT /:slug/users/:id -> fizzy_update_user
* DELETE /:slug/users/:id -> fizzy_deactivate_user
*
* NOTIFICATIONS (4 tools)
* GET /:slug/notifications -> fizzy_get_notifications
* POST /:slug/notifications/:id/reading -> fizzy_mark_notification_read
* DELETE /:slug/notifications/:id/reading -> fizzy_mark_notification_unread
* POST /:slug/notifications/bulk_reading -> fizzy_mark_all_notifications_read
*/
import { describe, it, expect, vi, beforeEach } from "vitest";
import { createFizzyServer } from "../src/server.js";
import { FizzyClient } from "../src/client/fizzy-client.js";
// Mock the FizzyClient
vi.mock("../src/client/fizzy-client.js", () => {
return {
FizzyClient: vi.fn().mockImplementation(() => ({
getIdentity: vi.fn(),
getAccounts: vi.fn(),
getBoards: vi.fn(),
getBoard: vi.fn(),
createBoard: vi.fn(),
updateBoard: vi.fn(),
deleteBoard: vi.fn(),
getCards: vi.fn(),
getCard: vi.fn(),
createCard: vi.fn(),
updateCard: vi.fn(),
deleteCard: vi.fn(),
getCardComments: vi.fn(),
createCardComment: vi.fn(),
deleteComment: vi.fn(),
getColumns: vi.fn(),
getColumn: vi.fn(),
createColumn: vi.fn(),
updateColumn: vi.fn(),
deleteColumn: vi.fn(),
getTags: vi.fn(),
getUsers: vi.fn(),
getUser: vi.fn(),
updateUser: vi.fn(),
deactivateUser: vi.fn(),
getNotifications: vi.fn(),
markNotificationAsRead: vi.fn(),
markNotificationAsUnread: vi.fn(),
markAllNotificationsAsRead: vi.fn(),
})),
};
});
describe("FizzyServer", () => {
let mockClient: FizzyClient;
beforeEach(() => {
mockClient = new FizzyClient({ accessToken: "test-token" });
});
describe("createFizzyServer", () => {
it("should create an MCP server instance", () => {
const server = createFizzyServer(mockClient);
expect(server).toBeDefined();
});
it("should register all expected tools", () => {
const server = createFizzyServer(mockClient);
// The server should be an McpServer instance
expect(server).toHaveProperty("tool");
expect(server).toHaveProperty("connect");
});
});
describe("Tool count verification", () => {
it("should have all 47 tools registered", () => {
// List of all expected tool names
const expectedTools = [
// Identity & Accounts (2)
"fizzy_get_identity",
"fizzy_get_accounts",
// Boards (5)
"fizzy_get_boards",
"fizzy_get_board",
"fizzy_create_board",
"fizzy_update_board",
"fizzy_delete_board",
// Cards (5)
"fizzy_get_cards",
"fizzy_get_card",
"fizzy_create_card",
"fizzy_update_card",
"fizzy_delete_card",
// Card Actions (9)
"fizzy_close_card",
"fizzy_reopen_card",
"fizzy_move_card_to_not_now",
"fizzy_move_card_to_column",
"fizzy_send_card_to_triage",
"fizzy_toggle_card_tag",
"fizzy_toggle_card_assignment",
"fizzy_watch_card",
"fizzy_unwatch_card",
// Comments (5)
"fizzy_get_card_comments",
"fizzy_get_comment",
"fizzy_create_comment",
"fizzy_update_comment",
"fizzy_delete_comment",
// Reactions (3)
"fizzy_get_reactions",
"fizzy_add_reaction",
"fizzy_remove_reaction",
// Steps (4)
"fizzy_get_step",
"fizzy_create_step",
"fizzy_update_step",
"fizzy_delete_step",
// Columns (5)
"fizzy_get_columns",
"fizzy_get_column",
"fizzy_create_column",
"fizzy_update_column",
"fizzy_delete_column",
// Tags (1)
"fizzy_get_tags",
// Users (4)
"fizzy_get_users",
"fizzy_get_user",
"fizzy_update_user",
"fizzy_deactivate_user",
// Notifications (4)
"fizzy_get_notifications",
"fizzy_mark_notification_read",
"fizzy_mark_notification_unread",
"fizzy_mark_all_notifications_read",
];
expect(expectedTools).toHaveLength(47);
});
});
});
describe("API Coverage", () => {
it("should cover all Fizzy API endpoints", () => {
// This test documents the API coverage
const apiEndpoints = {
// Identity
"GET /my/identity": "fizzy_get_identity",
// Accounts (embedded in identity)
"GET accounts from identity": "fizzy_get_accounts",
// Boards
"GET /:account_slug/boards": "fizzy_get_boards",
"GET /:account_slug/boards/:board_id": "fizzy_get_board",
"POST /:account_slug/boards": "fizzy_create_board",
"PUT /:account_slug/boards/:board_id": "fizzy_update_board",
"DELETE /:account_slug/boards/:board_id": "fizzy_delete_board",
// Cards
"GET /:account_slug/cards": "fizzy_get_cards",
"GET /:account_slug/cards/:card_number": "fizzy_get_card",
"POST /:account_slug/boards/:board_id/cards": "fizzy_create_card",
"PUT /:account_slug/cards/:card_id": "fizzy_update_card",
"DELETE /:account_slug/cards/:card_id": "fizzy_delete_card",
// Card Actions
"POST /:account_slug/cards/:card_number/closure": "fizzy_close_card",
"DELETE /:account_slug/cards/:card_number/closure": "fizzy_reopen_card",
"POST /:account_slug/cards/:card_number/not_now": "fizzy_move_card_to_not_now",
"POST /:account_slug/cards/:card_number/triage": "fizzy_move_card_to_column",
"DELETE /:account_slug/cards/:card_number/triage": "fizzy_send_card_to_triage",
"POST /:account_slug/cards/:card_number/taggings": "fizzy_toggle_card_tag",
"POST /:account_slug/cards/:card_number/assignments": "fizzy_toggle_card_assignment",
"POST /:account_slug/cards/:card_number/watch": "fizzy_watch_card",
"DELETE /:account_slug/cards/:card_number/watch": "fizzy_unwatch_card",
// Comments
"GET /:account_slug/cards/:card_id/comments": "fizzy_get_card_comments",
"GET /:account_slug/cards/:card_number/comments/:comment_id": "fizzy_get_comment",
"POST /:account_slug/cards/:card_id/comments": "fizzy_create_comment",
"PUT /:account_slug/cards/:card_number/comments/:comment_id": "fizzy_update_comment",
"DELETE /:account_slug/cards/:card_number/comments/:comment_id": "fizzy_delete_comment",
// Reactions
"GET /:account_slug/cards/:card_number/comments/:comment_id/reactions": "fizzy_get_reactions",
"POST /:account_slug/cards/:card_number/comments/:comment_id/reactions": "fizzy_add_reaction",
"DELETE /:account_slug/cards/:card_number/comments/:comment_id/reactions/:reaction_id": "fizzy_remove_reaction",
// Steps
"GET /:account_slug/cards/:card_number/steps/:step_id": "fizzy_get_step",
"POST /:account_slug/cards/:card_number/steps": "fizzy_create_step",
"PUT /:account_slug/cards/:card_number/steps/:step_id": "fizzy_update_step",
"DELETE /:account_slug/cards/:card_number/steps/:step_id": "fizzy_delete_step",
// Columns
"GET /:account_slug/boards/:board_id/columns": "fizzy_get_columns",
"GET /:account_slug/boards/:board_id/columns/:column_id": "fizzy_get_column",
"POST /:account_slug/boards/:board_id/columns": "fizzy_create_column",
"PUT /:account_slug/boards/:board_id/columns/:column_id": "fizzy_update_column",
"DELETE /:account_slug/boards/:board_id/columns/:column_id": "fizzy_delete_column",
// Tags
"GET /:account_slug/tags": "fizzy_get_tags",
// Users
"GET /:account_slug/users": "fizzy_get_users",
"GET /:account_slug/users/:user_id": "fizzy_get_user",
"PUT /:account_slug/users/:user_id": "fizzy_update_user",
"DELETE /:account_slug/users/:user_id": "fizzy_deactivate_user",
// Notifications
"GET /:account_slug/notifications": "fizzy_get_notifications",
"POST /:account_slug/notifications/:notification_id/reading": "fizzy_mark_notification_read",
"DELETE /:account_slug/notifications/:notification_id/reading": "fizzy_mark_notification_unread",
"POST /:account_slug/notifications/bulk_reading": "fizzy_mark_all_notifications_read",
};
// Verify all endpoints are covered (47 tools)
expect(Object.keys(apiEndpoints)).toHaveLength(47);
});
});