cucumberstudio-mcp 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +36 -0
- package/.github/workflows/pr-checks.yml +41 -0
- package/.github/workflows/release.yml +194 -0
- package/.prettierignore +26 -0
- package/.prettierrc +14 -0
- package/CLAUDE.md +140 -0
- package/Dockerfile +50 -0
- package/Dockerfile.dev +31 -0
- package/LICENSE +21 -0
- package/README.md +395 -0
- package/build/api/client.d.ts +49 -0
- package/build/api/client.d.ts.map +1 -0
- package/build/api/client.js +204 -0
- package/build/api/client.js.map +1 -0
- package/build/api/types.d.ts +113 -0
- package/build/api/types.d.ts.map +1 -0
- package/build/api/types.js +2 -0
- package/build/api/types.js.map +1 -0
- package/build/config/settings.d.ts +123 -0
- package/build/config/settings.d.ts.map +1 -0
- package/build/config/settings.js +97 -0
- package/build/config/settings.js.map +1 -0
- package/build/constants.d.ts +16 -0
- package/build/constants.d.ts.map +1 -0
- package/build/constants.js +24 -0
- package/build/constants.js.map +1 -0
- package/build/generated/version.d.ts +3 -0
- package/build/generated/version.d.ts.map +1 -0
- package/build/generated/version.js +5 -0
- package/build/generated/version.js.map +1 -0
- package/build/index.d.ts +3 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +81 -0
- package/build/index.js.map +1 -0
- package/build/mcp-server.d.ts +6 -0
- package/build/mcp-server.d.ts.map +1 -0
- package/build/mcp-server.js +263 -0
- package/build/mcp-server.js.map +1 -0
- package/build/tools/action-words.d.ts +18 -0
- package/build/tools/action-words.d.ts.map +1 -0
- package/build/tools/action-words.js +191 -0
- package/build/tools/action-words.js.map +1 -0
- package/build/tools/projects.d.ts +19 -0
- package/build/tools/projects.d.ts.map +1 -0
- package/build/tools/projects.js +123 -0
- package/build/tools/projects.js.map +1 -0
- package/build/tools/scenarios.d.ts +18 -0
- package/build/tools/scenarios.d.ts.map +1 -0
- package/build/tools/scenarios.js +194 -0
- package/build/tools/scenarios.js.map +1 -0
- package/build/tools/test-runs.d.ts +21 -0
- package/build/tools/test-runs.d.ts.map +1 -0
- package/build/tools/test-runs.js +324 -0
- package/build/tools/test-runs.js.map +1 -0
- package/build/transports/http.d.ts +38 -0
- package/build/transports/http.d.ts.map +1 -0
- package/build/transports/http.js +381 -0
- package/build/transports/http.js.map +1 -0
- package/build/transports/index.d.ts +22 -0
- package/build/transports/index.d.ts.map +1 -0
- package/build/transports/index.js +10 -0
- package/build/transports/index.js.map +1 -0
- package/build/transports/stdio.d.ts +13 -0
- package/build/transports/stdio.d.ts.map +1 -0
- package/build/transports/stdio.js +24 -0
- package/build/transports/stdio.js.map +1 -0
- package/build/utils/errors.d.ts +10 -0
- package/build/utils/errors.d.ts.map +1 -0
- package/build/utils/errors.js +35 -0
- package/build/utils/errors.js.map +1 -0
- package/build/utils/logger-constants.d.ts +15 -0
- package/build/utils/logger-constants.d.ts.map +1 -0
- package/build/utils/logger-constants.js +16 -0
- package/build/utils/logger-constants.js.map +1 -0
- package/build/utils/logger.d.ts +55 -0
- package/build/utils/logger.d.ts.map +1 -0
- package/build/utils/logger.js +113 -0
- package/build/utils/logger.js.map +1 -0
- package/build/utils/validation.d.ts +89 -0
- package/build/utils/validation.d.ts.map +1 -0
- package/build/utils/validation.js +78 -0
- package/build/utils/validation.js.map +1 -0
- package/docker-compose.yml +20 -0
- package/eslint.config.js +97 -0
- package/package.json +92 -0
- package/scripts/generate-version.js +31 -0
- package/src/api/client.ts +286 -0
- package/src/api/types.ts +137 -0
- package/src/config/settings.ts +113 -0
- package/src/constants.ts +29 -0
- package/src/index.ts +99 -0
- package/src/mcp-server.ts +342 -0
- package/src/tools/action-words.ts +240 -0
- package/src/tools/projects.ts +144 -0
- package/src/tools/scenarios.ts +231 -0
- package/src/tools/test-runs.ts +400 -0
- package/src/transports/http.ts +467 -0
- package/src/transports/index.ts +26 -0
- package/src/transports/stdio.ts +28 -0
- package/src/utils/errors.ts +45 -0
- package/src/utils/logger-constants.ts +18 -0
- package/src/utils/logger.ts +150 -0
- package/src/utils/validation.ts +94 -0
- package/test/api/client-with-msw.test.ts +122 -0
- package/test/api/client.test.ts +326 -0
- package/test/api/types.test.ts +88 -0
- package/test/config/settings.test.ts +204 -0
- package/test/mocks/data/action-words.ts +40 -0
- package/test/mocks/data/index.ts +13 -0
- package/test/mocks/data/projects.ts +38 -0
- package/test/mocks/data/scenarios.ts +53 -0
- package/test/mocks/data/test-runs.ts +101 -0
- package/test/mocks/handlers/action-words.ts +52 -0
- package/test/mocks/handlers/index.ts +10 -0
- package/test/mocks/handlers/projects.ts +45 -0
- package/test/mocks/handlers/scenarios.ts +72 -0
- package/test/mocks/handlers/test-runs.ts +106 -0
- package/test/mocks/server.ts +26 -0
- package/test/setup/vitest.setup.ts +18 -0
- package/test/tools/coverage-boost.test.ts +252 -0
- package/test/tools/projects.test.ts +290 -0
- package/test/tools/tools-basic.test.ts +146 -0
- package/test/transports/http-basic.test.ts +87 -0
- package/test/transports/http-simple.test.ts +33 -0
- package/test/transports/stdio.test.ts +73 -0
- package/test/utils/errors.test.ts +117 -0
- package/test/utils/validation.test.ts +261 -0
- package/tsconfig.build.json +8 -0
- package/tsconfig.json +27 -0
- package/vitest.config.ts +43 -0
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { http, HttpResponse } from 'msw'
|
|
2
|
+
|
|
3
|
+
import { mockScenarios, mockScenario, mockFolders } from '../data/scenarios.js'
|
|
4
|
+
|
|
5
|
+
const BASE_URL = 'https://api.example.com'
|
|
6
|
+
|
|
7
|
+
export const scenarioHandlers = [
|
|
8
|
+
// List scenarios in a project
|
|
9
|
+
http.get(`${BASE_URL}/projects/:projectId/scenarios`, ({ params, request }) => {
|
|
10
|
+
const accessToken = request.headers.get('access-token')
|
|
11
|
+
|
|
12
|
+
if (!accessToken || accessToken !== 'token') {
|
|
13
|
+
return HttpResponse.json({ error: 'Unauthorized' }, { status: 401 })
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const projectId = Number(params.projectId)
|
|
17
|
+
const projectScenarios = mockScenarios.filter((s) => s.project_id === projectId)
|
|
18
|
+
|
|
19
|
+
// Handle query parameters for filtering
|
|
20
|
+
const url = new URL(request.url)
|
|
21
|
+
const tags = url.searchParams.get('tags')
|
|
22
|
+
const folderId = url.searchParams.get('folder_id')
|
|
23
|
+
|
|
24
|
+
let filteredScenarios = projectScenarios
|
|
25
|
+
|
|
26
|
+
if (tags) {
|
|
27
|
+
const tagList = tags.split(',')
|
|
28
|
+
filteredScenarios = filteredScenarios.filter((scenario) =>
|
|
29
|
+
tagList.some((tag) => scenario.tags.includes(tag.trim())),
|
|
30
|
+
)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (folderId) {
|
|
34
|
+
const folderIdNum = Number(folderId)
|
|
35
|
+
filteredScenarios = filteredScenarios.filter((scenario) => scenario.folder_id === folderIdNum)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return HttpResponse.json(filteredScenarios)
|
|
39
|
+
}),
|
|
40
|
+
|
|
41
|
+
// Get specific scenario
|
|
42
|
+
http.get(`${BASE_URL}/projects/:projectId/scenarios/:id`, ({ params, request }) => {
|
|
43
|
+
const accessToken = request.headers.get('access-token')
|
|
44
|
+
|
|
45
|
+
if (!accessToken || accessToken !== 'token') {
|
|
46
|
+
return HttpResponse.json({ error: 'Unauthorized' }, { status: 401 })
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const scenarioId = Number(params.id)
|
|
50
|
+
const scenario = mockScenarios.find((s) => s.id === scenarioId)
|
|
51
|
+
|
|
52
|
+
if (!scenario) {
|
|
53
|
+
return HttpResponse.json({ error: 'Scenario not found' }, { status: 404 })
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return HttpResponse.json(scenario)
|
|
57
|
+
}),
|
|
58
|
+
|
|
59
|
+
// List folders in a project
|
|
60
|
+
http.get(`${BASE_URL}/projects/:projectId/folders`, ({ params, request }) => {
|
|
61
|
+
const accessToken = request.headers.get('access-token')
|
|
62
|
+
|
|
63
|
+
if (!accessToken || accessToken !== 'token') {
|
|
64
|
+
return HttpResponse.json({ error: 'Unauthorized' }, { status: 401 })
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const projectId = Number(params.projectId)
|
|
68
|
+
const projectFolders = mockFolders.filter((f) => f.project_id === projectId)
|
|
69
|
+
|
|
70
|
+
return HttpResponse.json(projectFolders)
|
|
71
|
+
}),
|
|
72
|
+
]
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { http, HttpResponse } from 'msw'
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
mockTestRuns,
|
|
5
|
+
mockTestRun,
|
|
6
|
+
mockTestExecutions,
|
|
7
|
+
mockBuilds,
|
|
8
|
+
mockBuild,
|
|
9
|
+
mockExecutionEnvironments,
|
|
10
|
+
} from '../data/test-runs.js'
|
|
11
|
+
|
|
12
|
+
const BASE_URL = 'https://api.example.com'
|
|
13
|
+
|
|
14
|
+
export const testRunHandlers = [
|
|
15
|
+
// List test runs in a project
|
|
16
|
+
http.get(`${BASE_URL}/projects/:projectId/test_runs`, ({ params, request }) => {
|
|
17
|
+
const accessToken = request.headers.get('access-token')
|
|
18
|
+
|
|
19
|
+
if (!accessToken || accessToken !== 'token') {
|
|
20
|
+
return HttpResponse.json({ error: 'Unauthorized' }, { status: 401 })
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const projectId = Number(params.projectId)
|
|
24
|
+
const projectTestRuns = mockTestRuns.filter((t) => t.project_id === projectId)
|
|
25
|
+
|
|
26
|
+
return HttpResponse.json(projectTestRuns)
|
|
27
|
+
}),
|
|
28
|
+
|
|
29
|
+
// Get specific test run
|
|
30
|
+
http.get(`${BASE_URL}/projects/:projectId/test_runs/:id`, ({ params, request }) => {
|
|
31
|
+
const accessToken = request.headers.get('access-token')
|
|
32
|
+
|
|
33
|
+
if (!accessToken || accessToken !== 'token') {
|
|
34
|
+
return HttpResponse.json({ error: 'Unauthorized' }, { status: 401 })
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const testRunId = Number(params.id)
|
|
38
|
+
const testRun = mockTestRuns.find((t) => t.id === testRunId)
|
|
39
|
+
|
|
40
|
+
if (!testRun) {
|
|
41
|
+
return HttpResponse.json({ error: 'Test run not found' }, { status: 404 })
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return HttpResponse.json(testRun)
|
|
45
|
+
}),
|
|
46
|
+
|
|
47
|
+
// Get test executions for a test run
|
|
48
|
+
http.get(`${BASE_URL}/projects/:projectId/test_runs/:testRunId/test_snapshots`, ({ params, request }) => {
|
|
49
|
+
const accessToken = request.headers.get('access-token')
|
|
50
|
+
|
|
51
|
+
if (!accessToken || accessToken !== 'token') {
|
|
52
|
+
return HttpResponse.json({ error: 'Unauthorized' }, { status: 401 })
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const testRunId = Number(params.testRunId)
|
|
56
|
+
const executions = mockTestExecutions.filter((e) => e.test_run_id === testRunId)
|
|
57
|
+
|
|
58
|
+
return HttpResponse.json(executions)
|
|
59
|
+
}),
|
|
60
|
+
|
|
61
|
+
// List builds in a project
|
|
62
|
+
http.get(`${BASE_URL}/projects/:projectId/builds`, ({ params, request }) => {
|
|
63
|
+
const accessToken = request.headers.get('access-token')
|
|
64
|
+
|
|
65
|
+
if (!accessToken || accessToken !== 'token') {
|
|
66
|
+
return HttpResponse.json({ error: 'Unauthorized' }, { status: 401 })
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const projectId = Number(params.projectId)
|
|
70
|
+
const projectBuilds = mockBuilds.filter((b) => b.project_id === projectId)
|
|
71
|
+
|
|
72
|
+
return HttpResponse.json(projectBuilds)
|
|
73
|
+
}),
|
|
74
|
+
|
|
75
|
+
// Get specific build
|
|
76
|
+
http.get(`${BASE_URL}/projects/:projectId/builds/:id`, ({ params, request }) => {
|
|
77
|
+
const accessToken = request.headers.get('access-token')
|
|
78
|
+
|
|
79
|
+
if (!accessToken || accessToken !== 'token') {
|
|
80
|
+
return HttpResponse.json({ error: 'Unauthorized' }, { status: 401 })
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const buildId = Number(params.id)
|
|
84
|
+
const build = mockBuilds.find((b) => b.id === buildId)
|
|
85
|
+
|
|
86
|
+
if (!build) {
|
|
87
|
+
return HttpResponse.json({ error: 'Build not found' }, { status: 404 })
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return HttpResponse.json(build)
|
|
91
|
+
}),
|
|
92
|
+
|
|
93
|
+
// List execution environments
|
|
94
|
+
http.get(`${BASE_URL}/projects/:projectId/execution_environments`, ({ params, request }) => {
|
|
95
|
+
const accessToken = request.headers.get('access-token')
|
|
96
|
+
|
|
97
|
+
if (!accessToken || accessToken !== 'token') {
|
|
98
|
+
return HttpResponse.json({ error: 'Unauthorized' }, { status: 401 })
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const projectId = Number(params.projectId)
|
|
102
|
+
const environments = mockExecutionEnvironments.filter((e) => e.project_id === projectId)
|
|
103
|
+
|
|
104
|
+
return HttpResponse.json(environments)
|
|
105
|
+
}),
|
|
106
|
+
]
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { setupServer } from 'msw/node'
|
|
2
|
+
|
|
3
|
+
import { handlers } from './handlers/index.js'
|
|
4
|
+
|
|
5
|
+
// Create and export the mock server
|
|
6
|
+
export const mockServer = setupServer(...handlers)
|
|
7
|
+
|
|
8
|
+
// Helper functions for test setup
|
|
9
|
+
export const startMockServer = () => {
|
|
10
|
+
mockServer.listen({
|
|
11
|
+
onUnhandledRequest: 'warn', // Warn about unhandled requests
|
|
12
|
+
})
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const stopMockServer = () => {
|
|
16
|
+
mockServer.close()
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export const resetMockServer = () => {
|
|
20
|
+
mockServer.resetHandlers()
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Export handlers for selective testing
|
|
24
|
+
export { handlers } from './handlers/index.js'
|
|
25
|
+
export * from './handlers/index.js'
|
|
26
|
+
export * from './data/index.js'
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { beforeAll, afterEach, afterAll } from 'vitest'
|
|
2
|
+
|
|
3
|
+
import { startMockServer, stopMockServer, resetMockServer } from '../mocks/server.js'
|
|
4
|
+
|
|
5
|
+
// Start the mock server before all tests
|
|
6
|
+
beforeAll(() => {
|
|
7
|
+
startMockServer()
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
// Reset handlers after each test to ensure test isolation
|
|
11
|
+
afterEach(() => {
|
|
12
|
+
resetMockServer()
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
// Stop the mock server after all tests
|
|
16
|
+
afterAll(() => {
|
|
17
|
+
stopMockServer()
|
|
18
|
+
})
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
import { CallToolRequest } from '@modelcontextprotocol/sdk/types.js'
|
|
2
|
+
import { describe, it, expect, beforeEach, vi } from 'vitest'
|
|
3
|
+
|
|
4
|
+
import { CucumberStudioApiClient } from '@/api/client.js'
|
|
5
|
+
import { ActionWordTools } from '@/tools/action-words.js'
|
|
6
|
+
import { ScenarioTools } from '@/tools/scenarios.js'
|
|
7
|
+
import { TestRunTools } from '@/tools/test-runs.js'
|
|
8
|
+
|
|
9
|
+
// Mock the API client
|
|
10
|
+
vi.mock('@/api/client.js')
|
|
11
|
+
|
|
12
|
+
describe('Tools Coverage Boost', () => {
|
|
13
|
+
let mockApiClient: any
|
|
14
|
+
|
|
15
|
+
beforeEach(() => {
|
|
16
|
+
mockApiClient = {
|
|
17
|
+
getScenarios: vi.fn().mockResolvedValue({ data: [] }),
|
|
18
|
+
getScenario: vi.fn().mockResolvedValue({ data: { id: 1, attributes: { name: 'Test' } } }),
|
|
19
|
+
findScenariosByTag: vi.fn().mockResolvedValue({ data: [] }),
|
|
20
|
+
getActionWords: vi.fn().mockResolvedValue({ data: [] }),
|
|
21
|
+
getActionWord: vi.fn().mockResolvedValue({ data: { id: 1, attributes: { name: 'Test' } } }),
|
|
22
|
+
findActionWordsByTag: vi.fn().mockResolvedValue({ data: [] }),
|
|
23
|
+
getTestRuns: vi.fn().mockResolvedValue({ data: [] }),
|
|
24
|
+
getTestRun: vi.fn().mockResolvedValue({ data: { id: 1, attributes: { name: 'Test' } } }),
|
|
25
|
+
getTestExecutions: vi.fn().mockResolvedValue({ data: [] }),
|
|
26
|
+
getBuilds: vi.fn().mockResolvedValue({ data: [] }),
|
|
27
|
+
getBuild: vi.fn().mockResolvedValue({ data: { id: 1, attributes: { name: 'Test' } } }),
|
|
28
|
+
getExecutionEnvironments: vi.fn().mockResolvedValue({ data: [] }),
|
|
29
|
+
}
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
describe('ScenarioTools handleToolCall', () => {
|
|
33
|
+
let scenarioTools: ScenarioTools
|
|
34
|
+
|
|
35
|
+
beforeEach(() => {
|
|
36
|
+
scenarioTools = new ScenarioTools(mockApiClient)
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
it('should handle cucumberstudio_list_scenarios', async () => {
|
|
40
|
+
const request: CallToolRequest = {
|
|
41
|
+
method: 'tools/call',
|
|
42
|
+
params: {
|
|
43
|
+
name: 'cucumberstudio_list_scenarios',
|
|
44
|
+
arguments: { projectId: '1' },
|
|
45
|
+
},
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const result = await scenarioTools.handleToolCall(request)
|
|
49
|
+
expect(result.content).toBeDefined()
|
|
50
|
+
expect(result.content[0].type).toBe('text')
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
it('should handle cucumberstudio_get_scenario', async () => {
|
|
54
|
+
const request: CallToolRequest = {
|
|
55
|
+
method: 'tools/call',
|
|
56
|
+
params: {
|
|
57
|
+
name: 'cucumberstudio_get_scenario',
|
|
58
|
+
arguments: { projectId: '1', scenarioId: '1' },
|
|
59
|
+
},
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const result = await scenarioTools.handleToolCall(request)
|
|
63
|
+
expect(result.content).toBeDefined()
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
it('should handle cucumberstudio_find_scenarios_by_tags', async () => {
|
|
67
|
+
const request: CallToolRequest = {
|
|
68
|
+
method: 'tools/call',
|
|
69
|
+
params: {
|
|
70
|
+
name: 'cucumberstudio_find_scenarios_by_tags',
|
|
71
|
+
arguments: { projectId: '1', tags: 'test' },
|
|
72
|
+
},
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const result = await scenarioTools.handleToolCall(request)
|
|
76
|
+
expect(result.content).toBeDefined()
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
// Note: cucumberstudio_list_folders is not implemented in ScenarioTools
|
|
80
|
+
|
|
81
|
+
it('should throw for unknown scenario tool', async () => {
|
|
82
|
+
const request: CallToolRequest = {
|
|
83
|
+
method: 'tools/call',
|
|
84
|
+
params: {
|
|
85
|
+
name: 'unknown_scenario_tool',
|
|
86
|
+
arguments: {},
|
|
87
|
+
},
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
await expect(scenarioTools.handleToolCall(request)).rejects.toThrow()
|
|
91
|
+
})
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
describe('ActionWordTools handleToolCall', () => {
|
|
95
|
+
let actionWordTools: ActionWordTools
|
|
96
|
+
|
|
97
|
+
beforeEach(() => {
|
|
98
|
+
actionWordTools = new ActionWordTools(mockApiClient)
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
it('should handle cucumberstudio_list_action_words', async () => {
|
|
102
|
+
const request: CallToolRequest = {
|
|
103
|
+
method: 'tools/call',
|
|
104
|
+
params: {
|
|
105
|
+
name: 'cucumberstudio_list_action_words',
|
|
106
|
+
arguments: { projectId: '1' },
|
|
107
|
+
},
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const result = await actionWordTools.handleToolCall(request)
|
|
111
|
+
expect(result.content).toBeDefined()
|
|
112
|
+
expect(result.content[0].type).toBe('text')
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
it('should handle cucumberstudio_get_action_word', async () => {
|
|
116
|
+
const request: CallToolRequest = {
|
|
117
|
+
method: 'tools/call',
|
|
118
|
+
params: {
|
|
119
|
+
name: 'cucumberstudio_get_action_word',
|
|
120
|
+
arguments: { projectId: '1', actionWordId: '1' },
|
|
121
|
+
},
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const result = await actionWordTools.handleToolCall(request)
|
|
125
|
+
expect(result.content).toBeDefined()
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
it('should handle cucumberstudio_find_action_words_by_tags', async () => {
|
|
129
|
+
const request: CallToolRequest = {
|
|
130
|
+
method: 'tools/call',
|
|
131
|
+
params: {
|
|
132
|
+
name: 'cucumberstudio_find_action_words_by_tags',
|
|
133
|
+
arguments: { projectId: '1', tags: 'test' },
|
|
134
|
+
},
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const result = await actionWordTools.handleToolCall(request)
|
|
138
|
+
expect(result.content).toBeDefined()
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
it('should throw for unknown action word tool', async () => {
|
|
142
|
+
const request: CallToolRequest = {
|
|
143
|
+
method: 'tools/call',
|
|
144
|
+
params: {
|
|
145
|
+
name: 'unknown_action_word_tool',
|
|
146
|
+
arguments: {},
|
|
147
|
+
},
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
await expect(actionWordTools.handleToolCall(request)).rejects.toThrow()
|
|
151
|
+
})
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
describe('TestRunTools handleToolCall', () => {
|
|
155
|
+
let testRunTools: TestRunTools
|
|
156
|
+
|
|
157
|
+
beforeEach(() => {
|
|
158
|
+
testRunTools = new TestRunTools(mockApiClient)
|
|
159
|
+
})
|
|
160
|
+
|
|
161
|
+
it('should handle cucumberstudio_list_test_runs', async () => {
|
|
162
|
+
const request: CallToolRequest = {
|
|
163
|
+
method: 'tools/call',
|
|
164
|
+
params: {
|
|
165
|
+
name: 'cucumberstudio_list_test_runs',
|
|
166
|
+
arguments: { projectId: '1' },
|
|
167
|
+
},
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const result = await testRunTools.handleToolCall(request)
|
|
171
|
+
expect(result.content).toBeDefined()
|
|
172
|
+
expect(result.content[0].type).toBe('text')
|
|
173
|
+
})
|
|
174
|
+
|
|
175
|
+
it('should handle cucumberstudio_get_test_run', async () => {
|
|
176
|
+
const request: CallToolRequest = {
|
|
177
|
+
method: 'tools/call',
|
|
178
|
+
params: {
|
|
179
|
+
name: 'cucumberstudio_get_test_run',
|
|
180
|
+
arguments: { projectId: '1', testRunId: '1' },
|
|
181
|
+
},
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const result = await testRunTools.handleToolCall(request)
|
|
185
|
+
expect(result.content).toBeDefined()
|
|
186
|
+
})
|
|
187
|
+
|
|
188
|
+
it('should handle cucumberstudio_get_test_executions', async () => {
|
|
189
|
+
const request: CallToolRequest = {
|
|
190
|
+
method: 'tools/call',
|
|
191
|
+
params: {
|
|
192
|
+
name: 'cucumberstudio_get_test_executions',
|
|
193
|
+
arguments: { projectId: '1', testRunId: '1' },
|
|
194
|
+
},
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const result = await testRunTools.handleToolCall(request)
|
|
198
|
+
expect(result.content).toBeDefined()
|
|
199
|
+
})
|
|
200
|
+
|
|
201
|
+
it('should handle cucumberstudio_list_builds', async () => {
|
|
202
|
+
const request: CallToolRequest = {
|
|
203
|
+
method: 'tools/call',
|
|
204
|
+
params: {
|
|
205
|
+
name: 'cucumberstudio_list_builds',
|
|
206
|
+
arguments: { projectId: '1' },
|
|
207
|
+
},
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
const result = await testRunTools.handleToolCall(request)
|
|
211
|
+
expect(result.content).toBeDefined()
|
|
212
|
+
})
|
|
213
|
+
|
|
214
|
+
it('should handle cucumberstudio_get_build', async () => {
|
|
215
|
+
const request: CallToolRequest = {
|
|
216
|
+
method: 'tools/call',
|
|
217
|
+
params: {
|
|
218
|
+
name: 'cucumberstudio_get_build',
|
|
219
|
+
arguments: { projectId: '1', buildId: '1' },
|
|
220
|
+
},
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
const result = await testRunTools.handleToolCall(request)
|
|
224
|
+
expect(result.content).toBeDefined()
|
|
225
|
+
})
|
|
226
|
+
|
|
227
|
+
it('should handle cucumberstudio_list_execution_environments', async () => {
|
|
228
|
+
const request: CallToolRequest = {
|
|
229
|
+
method: 'tools/call',
|
|
230
|
+
params: {
|
|
231
|
+
name: 'cucumberstudio_list_execution_environments',
|
|
232
|
+
arguments: { projectId: '1' },
|
|
233
|
+
},
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
const result = await testRunTools.handleToolCall(request)
|
|
237
|
+
expect(result.content).toBeDefined()
|
|
238
|
+
})
|
|
239
|
+
|
|
240
|
+
it('should throw for unknown test run tool', async () => {
|
|
241
|
+
const request: CallToolRequest = {
|
|
242
|
+
method: 'tools/call',
|
|
243
|
+
params: {
|
|
244
|
+
name: 'unknown_test_run_tool',
|
|
245
|
+
arguments: {},
|
|
246
|
+
},
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
await expect(testRunTools.handleToolCall(request)).rejects.toThrow()
|
|
250
|
+
})
|
|
251
|
+
})
|
|
252
|
+
})
|