Skip to main content
Glama

Scrapbox Cosense MCP Server

by worldnine
create-page.test.ts6.43 kB
import { handleCreatePage } from '@/routes/handlers/create-page.js'; import * as cosense from '@/cosense.js'; // モックの設定 jest.mock('@/cosense.js'); jest.mock('@/utils/markdown-converter.js', () => ({ convertMarkdownToScrapbox: jest.fn((text) => text) // そのまま返す })); // @cosense/stdライブラリ全体をモック jest.mock('@cosense/std/websocket', () => ({ patch: jest.fn() })); const mockedCosense = cosense as jest.Mocked<typeof cosense>; // patchのモックを動的に取得 let mockedPatch: jest.MockedFunction<typeof import('@cosense/std/websocket').patch>; beforeAll(async () => { const websocketModule = await import('@cosense/std/websocket'); mockedPatch = websocketModule.patch as jest.MockedFunction<typeof import('@cosense/std/websocket').patch>; }); describe('handleCreatePage', () => { const mockProjectName = 'test-project'; const mockCosenseSid = 'test-sid'; beforeEach(() => { jest.clearAllMocks(); // createPageUrlのデフォルトモック mockedCosense.createPageUrl.mockReturnValue( 'https://scrapbox.io/test-project/New%20Page' ); }); describe('正常ケース', () => { test('タイトルのみでページを作成できること(WebSocket API)', async () => { mockedPatch.mockResolvedValue(undefined); const params = { title: 'New Page' }; const result = await handleCreatePage(mockProjectName, mockCosenseSid, params); expect(result.content).toHaveLength(1); expect(result.content[0]?.type).toBe('text'); expect(result.content[0]?.text).toContain('Successfully created page'); expect(result.content[0]?.text).toContain('Title: New Page'); expect(result.content[0]?.text).toContain('Lines: 1'); expect(mockedPatch).toHaveBeenCalledWith( mockProjectName, 'New Page', expect.any(Function), { sid: mockCosenseSid } ); }); test('createActually=falseでURL生成のみ行うこと', async () => { const params = { title: 'New Page', createActually: false }; const result = await handleCreatePage(mockProjectName, mockCosenseSid, params); expect(result.content).toHaveLength(1); expect(result.content[0]?.type).toBe('text'); expect(result.content[0]?.text).toContain('Created page: New Page'); expect(result.content[0]?.text).toContain('URL: https://scrapbox.io/test-project/New%20Page'); expect(mockedPatch).not.toHaveBeenCalled(); expect(mockedCosense.createPageUrl).toHaveBeenCalledWith( mockProjectName, 'New Page', undefined ); }); test('本文付きでページを作成できること(WebSocket API)', async () => { mockedPatch.mockResolvedValue(undefined); const params = { title: 'New Page', body: '# Header\nContent' }; const result = await handleCreatePage(mockProjectName, mockCosenseSid, params); expect(result.content[0]?.text).toContain('Successfully created page'); expect(result.content[0]?.text).toContain('Lines: 3'); // title + 2 lines expect(mockedPatch).toHaveBeenCalled(); }); }); describe('エラーケース', () => { test('COSENSE_SID無しでcreateActually=trueの場合にエラーを返すこと', async () => { const params = { title: 'New Page', createActually: true }; const result = await handleCreatePage(mockProjectName, undefined, params); expect(result.isError).toBe(true); expect(result.content[0]?.text).toContain('Error: Authentication required'); expect(result.content[0]?.text).toContain('COSENSE_SID environment variable is required'); expect(mockedPatch).not.toHaveBeenCalled(); }); test('WebSocket APIでエラーが発生した場合にエラーレスポンスを返すこと', async () => { const errorMessage = 'WebSocket error'; mockedPatch.mockRejectedValue(new Error(errorMessage)); const params = { title: 'New Page' }; const result = await handleCreatePage(mockProjectName, mockCosenseSid, params); expect(result.isError).toBe(true); expect(result.content[0]?.text).toContain('Error details:'); expect(result.content[0]?.text).toContain(errorMessage); }); test('createPageUrlでエラーが発生した場合にエラーレスポンスを返すこと(createActually=false)', async () => { const errorMessage = 'URL creation failed'; mockedCosense.createPageUrl.mockImplementation(() => { throw new Error(errorMessage); }); const params = { title: 'New Page', createActually: false }; const result = await handleCreatePage(mockProjectName, mockCosenseSid, params); expect(result.isError).toBe(true); expect(result.content[0]?.text).toContain('Error details:'); expect(result.content[0]?.text).toContain(errorMessage); }); }); describe('出力フォーマット', () => { test('WebSocket API成功レスポンスのフォーマットが正しいこと', async () => { mockedPatch.mockResolvedValue(undefined); const params = { title: 'New Page' }; const result = await handleCreatePage(mockProjectName, mockCosenseSid, params); expect(result.content).toHaveLength(1); expect(result.content[0]?.type).toBe('text'); const outputText = result.content[0]?.text || ''; expect(outputText).toContain('Successfully created page'); expect(outputText).toContain('Operation: create_page'); expect(outputText).toContain('Project: test-project'); expect(outputText).toContain('Title: New Page'); expect(outputText).toContain('Lines: 1'); expect(outputText).toContain('URL: https://scrapbox.io/test-project/New%20Page'); expect(outputText).toContain('Timestamp:'); }); test('URL生成のみのレスポンスフォーマットが正しいこと', async () => { const params = { title: 'New Page', createActually: false }; const result = await handleCreatePage(mockProjectName, mockCosenseSid, params); expect(result.content).toHaveLength(1); expect(result.content[0]?.type).toBe('text'); const outputLines = result.content[0]?.text.split('\n') || []; expect(outputLines).toEqual([ 'Created page: New Page', 'URL: https://scrapbox.io/test-project/New%20Page' ]); }); }); });

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/worldnine/scrapbox-cosense-mcp'

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