@hubspot/cli 7.9.0-experimental.0 → 7.9.1-experimental.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/bin/cli.js +5 -4
- package/commands/__tests__/getStarted.test.js +10 -0
- package/commands/account/__tests__/rename.test.js +42 -0
- package/commands/account/auth.js +10 -14
- package/commands/account/clean.js +11 -19
- package/commands/account/createOverride.js +15 -11
- package/commands/account/info.js +8 -5
- package/commands/account/list.js +13 -18
- package/commands/account/remove.js +23 -22
- package/commands/account/removeOverride.js +6 -6
- package/commands/account/rename.d.ts +1 -1
- package/commands/account/rename.js +6 -3
- package/commands/account/use.js +19 -8
- package/commands/app/__tests__/migrate.test.js +8 -4
- package/commands/app/migrate.js +2 -2
- package/commands/auth.js +18 -14
- package/commands/config/migrate.js +5 -5
- package/commands/config/set.js +1 -2
- package/commands/customObject/createSchema.js +2 -3
- package/commands/customObject/updateSchema.js +2 -3
- package/commands/getStarted.js +10 -5
- package/commands/hubdb/__tests__/list.test.js +1 -0
- package/commands/hubdb/list.js +2 -2
- package/commands/hubdb.d.ts +1 -1
- package/commands/init.js +36 -32
- package/commands/project/__tests__/deploy.test.js +10 -5
- package/commands/project/__tests__/devUnifiedFlow.test.js +6 -4
- package/commands/project/__tests__/logs.test.js +4 -0
- package/commands/project/__tests__/validate.test.js +2 -2
- package/commands/project/cloneApp.js +2 -2
- package/commands/project/deploy.js +2 -2
- package/commands/project/dev/deprecatedFlow.js +4 -5
- package/commands/project/dev/index.js +14 -4
- package/commands/project/dev/unifiedFlow.js +4 -5
- package/commands/project/listBuilds.js +7 -1
- package/commands/project/logs.js +2 -3
- package/commands/project/profile/add.js +6 -7
- package/commands/project/profile/delete.js +2 -2
- package/commands/project/upload.js +9 -3
- package/commands/project/validate.js +9 -3
- package/commands/project/watch.js +7 -2
- package/commands/sandbox/__tests__/create.test.js +14 -5
- package/commands/sandbox/create.js +4 -5
- package/commands/sandbox/delete.js +23 -20
- package/commands/testAccount/__tests__/create.test.js +68 -0
- package/commands/testAccount/create.d.ts +8 -0
- package/commands/testAccount/create.js +134 -44
- package/commands/testAccount/delete.js +9 -8
- package/commands/testAccount/importData.d.ts +1 -1
- package/lang/en.d.ts +3204 -3205
- package/lang/en.js +33 -9
- package/lib/__tests__/buildAccount.test.js +22 -30
- package/lib/__tests__/commonOpts.test.js +9 -13
- package/lib/__tests__/developerTestAccounts.test.js +29 -17
- package/lib/__tests__/importData.test.js +20 -10
- package/lib/__tests__/oauth.test.js +19 -8
- package/lib/__tests__/sandboxSync.test.js +33 -11
- package/lib/__tests__/sandboxes.test.js +30 -19
- package/lib/__tests__/usageTracking.test.js +10 -10
- package/lib/__tests__/validation.test.js +32 -32
- package/lib/accountTypes.d.ts +9 -9
- package/lib/accountTypes.js +2 -4
- package/lib/app/__tests__/migrate.test.js +15 -0
- package/lib/app/__tests__/migrate_legacy.test.js +9 -0
- package/lib/app/migrate_legacy.d.ts +2 -2
- package/lib/buildAccount.d.ts +4 -4
- package/lib/buildAccount.js +7 -14
- package/lib/commonOpts.js +3 -3
- package/lib/configMigrate.d.ts +2 -2
- package/lib/configMigrate.js +42 -18
- package/lib/configOptions.js +3 -2
- package/lib/constants.d.ts +1 -0
- package/lib/constants.js +6 -0
- package/lib/developerTestAccounts.d.ts +3 -3
- package/lib/developerTestAccounts.js +4 -7
- package/lib/doctor/DiagnosticInfoBuilder.d.ts +1 -1
- package/lib/doctor/DiagnosticInfoBuilder.js +9 -6
- package/lib/doctor/Doctor.js +4 -3
- package/lib/doctor/__tests__/Diagnosis.test.js +4 -3
- package/lib/doctor/__tests__/DiagnosticInfoBuilder.test.js +17 -9
- package/lib/doctor/__tests__/Doctor.test.js +14 -0
- package/lib/importData.js +8 -7
- package/lib/links.js +5 -5
- package/lib/mcp/__tests__/setup.test.js +127 -0
- package/lib/mcp/setup.d.ts +4 -12
- package/lib/mcp/setup.js +34 -1
- package/lib/middleware/__test__/commandTargetingUtils.test.js +3 -3
- package/lib/middleware/__test__/configMiddleware.test.js +23 -22
- package/lib/middleware/__test__/gitMiddleware.test.js +9 -7
- package/lib/middleware/autoUpdateMiddleware.d.ts +3 -1
- package/lib/middleware/autoUpdateMiddleware.js +10 -2
- package/lib/middleware/commandTargetingUtils.js +2 -2
- package/lib/middleware/configMiddleware.d.ts +6 -1
- package/lib/middleware/configMiddleware.js +36 -15
- package/lib/middleware/gitMiddleware.js +8 -4
- package/lib/oauth.d.ts +2 -2
- package/lib/oauth.js +8 -10
- package/lib/projects/__tests__/AppDevModeInterface.test.js +17 -6
- package/lib/projects/__tests__/DevServerManager.test.js +1 -0
- package/lib/projects/__tests__/LocalDevProcess.test.js +1 -0
- package/lib/projects/__tests__/components.test.js +148 -24
- package/lib/projects/__tests__/deploy.test.js +1 -0
- package/lib/projects/__tests__/projects.test.js +13 -42
- package/lib/projects/components.js +76 -20
- package/lib/projects/config.js +5 -9
- package/lib/projects/create/__tests__/v2.test.js +11 -0
- package/lib/projects/localDev/AppDevModeInterface.js +2 -2
- package/lib/projects/localDev/DevServerManager_DEPRECATED.js +2 -2
- package/lib/projects/localDev/LocalDevLogger.js +4 -4
- package/lib/projects/localDev/LocalDevManager_DEPRECATED.js +3 -3
- package/lib/projects/localDev/helpers/account.d.ts +10 -10
- package/lib/projects/localDev/helpers/account.js +6 -11
- package/lib/projects/urls.js +5 -6
- package/lib/prompts/__tests__/createDeveloperTestAccountConfigPrompt.test.d.ts +1 -0
- package/lib/prompts/__tests__/createDeveloperTestAccountConfigPrompt.test.js +153 -0
- package/lib/prompts/__tests__/downloadProjectPrompt.test.js +7 -5
- package/lib/prompts/accountNamePrompt.js +3 -3
- package/lib/prompts/accountsPrompt.d.ts +1 -1
- package/lib/prompts/accountsPrompt.js +6 -7
- package/lib/prompts/confirmImportDataPrompt.js +2 -2
- package/lib/prompts/createDeveloperTestAccountConfigPrompt.d.ts +5 -0
- package/lib/prompts/createDeveloperTestAccountConfigPrompt.js +76 -66
- package/lib/prompts/downloadProjectPrompt.d.ts +1 -0
- package/lib/prompts/downloadProjectPrompt.js +5 -2
- package/lib/prompts/importDataTestAccountSelectPrompt.js +4 -5
- package/lib/prompts/personalAccessKeyPrompt.js +2 -2
- package/lib/prompts/projectDevTargetAccountPrompt.d.ts +3 -3
- package/lib/prompts/projectDevTargetAccountPrompt.js +5 -7
- package/lib/prompts/sandboxesPrompt.js +7 -8
- package/lib/prompts/setAsDefaultAccountPrompt.js +7 -6
- package/lib/sandboxSync.d.ts +2 -2
- package/lib/sandboxSync.js +3 -9
- package/lib/sandboxes.d.ts +4 -4
- package/lib/sandboxes.js +6 -11
- package/lib/serverlessLogs.js +2 -2
- package/lib/theme/__tests__/migrate.test.js +15 -0
- package/lib/ui/index.js +6 -3
- package/lib/usageTracking.js +15 -8
- package/lib/validation.js +13 -11
- package/mcp-server/tools/cms/HsCreateFunctionTool.js +8 -2
- package/mcp-server/tools/cms/HsCreateModuleTool.d.ts +4 -4
- package/mcp-server/tools/cms/HsCreateModuleTool.js +8 -2
- package/mcp-server/tools/cms/HsCreateTemplateTool.js +8 -2
- package/mcp-server/tools/cms/HsFunctionLogsTool.d.ts +4 -4
- package/mcp-server/tools/cms/HsFunctionLogsTool.js +6 -2
- package/mcp-server/tools/cms/HsListFunctionsTool.js +5 -1
- package/mcp-server/tools/cms/HsListTool.js +5 -1
- package/mcp-server/tools/cms/__tests__/HsCreateFunctionTool.test.js +1 -0
- package/mcp-server/tools/index.js +4 -0
- package/mcp-server/tools/project/AddFeatureToProjectTool.d.ts +1 -1
- package/mcp-server/tools/project/AddFeatureToProjectTool.js +9 -3
- package/mcp-server/tools/project/CreateProjectTool.js +8 -2
- package/mcp-server/tools/project/CreateTestAccountTool.d.ts +41 -0
- package/mcp-server/tools/project/CreateTestAccountTool.js +150 -0
- package/mcp-server/tools/project/DeployProjectTool.d.ts +1 -1
- package/mcp-server/tools/project/DeployProjectTool.js +8 -2
- package/mcp-server/tools/project/DocFetchTool.d.ts +1 -1
- package/mcp-server/tools/project/DocFetchTool.js +9 -5
- package/mcp-server/tools/project/DocsSearchTool.d.ts +1 -1
- package/mcp-server/tools/project/DocsSearchTool.js +12 -8
- package/mcp-server/tools/project/GetApiUsagePatternsByAppIdTool.d.ts +1 -1
- package/mcp-server/tools/project/GetApiUsagePatternsByAppIdTool.js +11 -7
- package/mcp-server/tools/project/GetApplicationInfoTool.d.ts +1 -1
- package/mcp-server/tools/project/GetApplicationInfoTool.js +11 -7
- package/mcp-server/tools/project/GetBuildStatusTool.d.ts +26 -0
- package/mcp-server/tools/project/GetBuildStatusTool.js +164 -0
- package/mcp-server/tools/project/GetConfigValuesTool.d.ts +1 -1
- package/mcp-server/tools/project/GetConfigValuesTool.js +11 -7
- package/mcp-server/tools/project/GuidedWalkthroughTool.d.ts +1 -1
- package/mcp-server/tools/project/GuidedWalkthroughTool.js +7 -3
- package/mcp-server/tools/project/UploadProjectTools.d.ts +9 -3
- package/mcp-server/tools/project/UploadProjectTools.js +51 -5
- package/mcp-server/tools/project/ValidateProjectTool.d.ts +1 -1
- package/mcp-server/tools/project/ValidateProjectTool.js +7 -3
- package/mcp-server/tools/project/__tests__/CreateTestAccountTool.test.d.ts +1 -0
- package/mcp-server/tools/project/__tests__/CreateTestAccountTool.test.js +454 -0
- package/mcp-server/tools/project/__tests__/DocFetchTool.test.js +5 -1
- package/mcp-server/tools/project/__tests__/DocsSearchTool.test.js +25 -13
- package/mcp-server/tools/project/__tests__/GetApiUsagePatternsByAppIdTool.test.js +7 -5
- package/mcp-server/tools/project/__tests__/GetApplicationInfoTool.test.js +7 -5
- package/mcp-server/tools/project/__tests__/GetBuildStatusTool.test.d.ts +1 -0
- package/mcp-server/tools/project/__tests__/GetBuildStatusTool.test.js +240 -0
- package/mcp-server/tools/project/__tests__/GetConfigValuesTool.test.js +8 -6
- package/mcp-server/tools/project/__tests__/UploadProjectTools.test.js +56 -4
- package/mcp-server/utils/__tests__/content.test.js +21 -20
- package/mcp-server/utils/__tests__/feedbackTracking.test.js +33 -28
- package/mcp-server/utils/content.d.ts +1 -1
- package/mcp-server/utils/content.js +2 -2
- package/mcp-server/utils/feedbackTracking.d.ts +1 -1
- package/mcp-server/utils/feedbackTracking.js +3 -3
- package/mcp-server/utils/toolUsageTracking.js +4 -3
- package/package.json +8 -7
- package/mcp-server/utils/__tests__/cliConfig.test.js +0 -110
- package/mcp-server/utils/cliConfig.d.ts +0 -1
- package/mcp-server/utils/cliConfig.js +0 -12
- /package/{mcp-server/utils/__tests__/cliConfig.test.d.ts → lib/mcp/__tests__/setup.test.d.ts} +0 -0
|
@@ -14,7 +14,7 @@ declare const inputSchemaZodObject: z.ZodObject<{
|
|
|
14
14
|
export type CreateProjectInputSchema = z.infer<typeof inputSchemaZodObject>;
|
|
15
15
|
export declare class ValidateProjectTool extends Tool<CreateProjectInputSchema> {
|
|
16
16
|
constructor(mcpServer: McpServer);
|
|
17
|
-
handler({ absoluteProjectPath,
|
|
17
|
+
handler({ absoluteProjectPath, }: CreateProjectInputSchema): Promise<TextContentResponse>;
|
|
18
18
|
register(): RegisteredTool;
|
|
19
19
|
}
|
|
20
20
|
export {};
|
|
@@ -15,14 +15,14 @@ export class ValidateProjectTool extends Tool {
|
|
|
15
15
|
constructor(mcpServer) {
|
|
16
16
|
super(mcpServer);
|
|
17
17
|
}
|
|
18
|
-
async handler({ absoluteProjectPath,
|
|
18
|
+
async handler({ absoluteProjectPath, }) {
|
|
19
19
|
await trackToolUsage(toolName);
|
|
20
20
|
try {
|
|
21
21
|
const { stdout, stderr } = await runCommandInDir(absoluteProjectPath, 'hs project validate');
|
|
22
|
-
return formatTextContents(
|
|
22
|
+
return formatTextContents(stdout, stderr);
|
|
23
23
|
}
|
|
24
24
|
catch (error) {
|
|
25
|
-
return formatTextContents(
|
|
25
|
+
return formatTextContents(error instanceof Error ? error.message : `${error}`);
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
28
|
register() {
|
|
@@ -30,6 +30,10 @@ export class ValidateProjectTool extends Tool {
|
|
|
30
30
|
title: 'Validate HubSpot Project',
|
|
31
31
|
description: 'Validates the HubSpot project and its configuration files. This tool does not need to be ran before uploading the project',
|
|
32
32
|
inputSchema,
|
|
33
|
+
annotations: {
|
|
34
|
+
readOnlyHint: true,
|
|
35
|
+
openWorldHint: false,
|
|
36
|
+
},
|
|
33
37
|
}, this.handler);
|
|
34
38
|
}
|
|
35
39
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,454 @@
|
|
|
1
|
+
import { CreateTestAccountTool, } from '../CreateTestAccountTool.js';
|
|
2
|
+
import { runCommandInDir } from '../../../utils/project.js';
|
|
3
|
+
import { addFlag } from '../../../utils/command.js';
|
|
4
|
+
import { mcpFeedbackRequest } from '../../../utils/feedbackTracking.js';
|
|
5
|
+
import fs from 'fs';
|
|
6
|
+
import * as config from '@hubspot/local-dev-lib/config';
|
|
7
|
+
vi.mock('@modelcontextprotocol/sdk/server/mcp.js');
|
|
8
|
+
vi.mock('../../../utils/project');
|
|
9
|
+
vi.mock('../../../utils/command');
|
|
10
|
+
vi.mock('../../../utils/toolUsageTracking');
|
|
11
|
+
vi.mock('../../../utils/feedbackTracking');
|
|
12
|
+
vi.mock('fs');
|
|
13
|
+
vi.mock('@hubspot/local-dev-lib/config');
|
|
14
|
+
const mockMcpFeedbackRequest = mcpFeedbackRequest;
|
|
15
|
+
const mockRunCommandInDir = runCommandInDir;
|
|
16
|
+
const mockAddFlag = addFlag;
|
|
17
|
+
const mockReadFileSync = fs.readFileSync;
|
|
18
|
+
const mockGetConfigAccountByName = vi.spyOn(config, 'getConfigAccountByName');
|
|
19
|
+
describe('mcp-server/tools/project/CreateTestAccountTool', () => {
|
|
20
|
+
let mockMcpServer;
|
|
21
|
+
let tool;
|
|
22
|
+
let mockRegisteredTool;
|
|
23
|
+
beforeEach(() => {
|
|
24
|
+
vi.clearAllMocks();
|
|
25
|
+
// @ts-expect-error Not mocking the whole server
|
|
26
|
+
mockMcpServer = {
|
|
27
|
+
registerTool: vi.fn(),
|
|
28
|
+
};
|
|
29
|
+
mockRegisteredTool = {};
|
|
30
|
+
mockMcpServer.registerTool.mockReturnValue(mockRegisteredTool);
|
|
31
|
+
mockMcpFeedbackRequest.mockResolvedValue('');
|
|
32
|
+
tool = new CreateTestAccountTool(mockMcpServer);
|
|
33
|
+
// Mock addFlag to simulate command building
|
|
34
|
+
mockAddFlag.mockImplementation((command, flag, value) => `${command} --${flag} "${value}"`);
|
|
35
|
+
// Mock fs.readFileSync for config file tests
|
|
36
|
+
mockReadFileSync.mockReturnValue(JSON.stringify({
|
|
37
|
+
accountName: 'TestAccountFromConfig',
|
|
38
|
+
description: 'Test description',
|
|
39
|
+
marketingLevel: 'PROFESSIONAL',
|
|
40
|
+
}));
|
|
41
|
+
// @ts-expect-error breaking things
|
|
42
|
+
mockGetConfigAccountByName.mockReturnValue(undefined);
|
|
43
|
+
});
|
|
44
|
+
describe('register', () => {
|
|
45
|
+
it('should register tool with correct parameters', () => {
|
|
46
|
+
const result = tool.register();
|
|
47
|
+
expect(mockMcpServer.registerTool).toHaveBeenCalledWith('create-test-account', expect.objectContaining({
|
|
48
|
+
title: 'Create HubSpot Test Account',
|
|
49
|
+
description: expect.stringContaining('Creates a HubSpot developer test account'),
|
|
50
|
+
inputSchema: expect.any(Object),
|
|
51
|
+
}), expect.any(Function));
|
|
52
|
+
expect(result).toBe(mockRegisteredTool);
|
|
53
|
+
});
|
|
54
|
+
it('should include all key information in description', () => {
|
|
55
|
+
tool.register();
|
|
56
|
+
const registerCall = mockMcpServer.registerTool.mock.calls[0];
|
|
57
|
+
const config = registerCall[1];
|
|
58
|
+
expect(config.description).toContain('test account');
|
|
59
|
+
expect(config.description).toContain('WORKFLOW');
|
|
60
|
+
expect(config.description).toContain('config file');
|
|
61
|
+
expect(config.description).toContain('ALL account details');
|
|
62
|
+
expect(config.description).toContain('non-interactive execution');
|
|
63
|
+
expect(config.description).toContain('FREE, STARTER, PROFESSIONAL, ENTERPRISE');
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
describe('handler', () => {
|
|
67
|
+
describe('config file approach', () => {
|
|
68
|
+
const baseInput = {
|
|
69
|
+
absoluteCurrentWorkingDirectory: '/test/workspace',
|
|
70
|
+
configPath: './test-account.json',
|
|
71
|
+
description: 'Test account',
|
|
72
|
+
marketingLevel: 'ENTERPRISE',
|
|
73
|
+
opsLevel: 'ENTERPRISE',
|
|
74
|
+
serviceLevel: 'ENTERPRISE',
|
|
75
|
+
salesLevel: 'ENTERPRISE',
|
|
76
|
+
contentLevel: 'ENTERPRISE',
|
|
77
|
+
};
|
|
78
|
+
it('should create test account with config path', async () => {
|
|
79
|
+
mockRunCommandInDir.mockResolvedValue({
|
|
80
|
+
stdout: 'Test account created successfully\nAccount ID: 12345678',
|
|
81
|
+
stderr: '',
|
|
82
|
+
});
|
|
83
|
+
const result = await tool.handler(baseInput);
|
|
84
|
+
expect(mockAddFlag).toHaveBeenCalledWith('hs test-account create', 'config-path', './test-account.json');
|
|
85
|
+
expect(mockRunCommandInDir).toHaveBeenCalledWith('/test/workspace', 'hs test-account create --config-path "./test-account.json"');
|
|
86
|
+
expect(result).toEqual({
|
|
87
|
+
content: [
|
|
88
|
+
{ type: 'text', text: '/test/workspace' },
|
|
89
|
+
{
|
|
90
|
+
type: 'text',
|
|
91
|
+
text: 'Test account created successfully\nAccount ID: 12345678',
|
|
92
|
+
},
|
|
93
|
+
{ type: 'text', text: '' },
|
|
94
|
+
],
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
it('should handle absolute config path', async () => {
|
|
98
|
+
mockRunCommandInDir.mockResolvedValue({
|
|
99
|
+
stdout: 'Account created',
|
|
100
|
+
stderr: '',
|
|
101
|
+
});
|
|
102
|
+
const input = {
|
|
103
|
+
absoluteCurrentWorkingDirectory: '/test/workspace',
|
|
104
|
+
configPath: '/absolute/path/to/config.json',
|
|
105
|
+
description: 'Test account',
|
|
106
|
+
marketingLevel: 'ENTERPRISE',
|
|
107
|
+
opsLevel: 'ENTERPRISE',
|
|
108
|
+
serviceLevel: 'ENTERPRISE',
|
|
109
|
+
salesLevel: 'ENTERPRISE',
|
|
110
|
+
contentLevel: 'ENTERPRISE',
|
|
111
|
+
};
|
|
112
|
+
await tool.handler(input);
|
|
113
|
+
expect(mockAddFlag).toHaveBeenCalledWith('hs test-account create', 'config-path', '/absolute/path/to/config.json');
|
|
114
|
+
expect(mockRunCommandInDir).toHaveBeenCalledWith('/test/workspace', 'hs test-account create --config-path "/absolute/path/to/config.json"');
|
|
115
|
+
});
|
|
116
|
+
it('should prioritize config path over flags', async () => {
|
|
117
|
+
mockRunCommandInDir.mockResolvedValue({
|
|
118
|
+
stdout: 'Account created',
|
|
119
|
+
stderr: '',
|
|
120
|
+
});
|
|
121
|
+
const input = {
|
|
122
|
+
absoluteCurrentWorkingDirectory: '/test/workspace',
|
|
123
|
+
configPath: './test-account.json',
|
|
124
|
+
name: 'FlagAccount',
|
|
125
|
+
description: 'This should be ignored',
|
|
126
|
+
marketingLevel: 'ENTERPRISE',
|
|
127
|
+
opsLevel: 'ENTERPRISE',
|
|
128
|
+
serviceLevel: 'ENTERPRISE',
|
|
129
|
+
salesLevel: 'ENTERPRISE',
|
|
130
|
+
contentLevel: 'ENTERPRISE',
|
|
131
|
+
};
|
|
132
|
+
await tool.handler(input);
|
|
133
|
+
expect(mockAddFlag).toHaveBeenCalledWith('hs test-account create', 'config-path', './test-account.json');
|
|
134
|
+
// Should not call addFlag for name or description
|
|
135
|
+
expect(mockAddFlag).not.toHaveBeenCalledWith(expect.anything(), 'name', expect.anything());
|
|
136
|
+
});
|
|
137
|
+
it('should return helpful error when config file does not exist', async () => {
|
|
138
|
+
mockReadFileSync.mockImplementation(() => {
|
|
139
|
+
throw new Error("ENOENT: no such file or directory, open './missing-config.json'");
|
|
140
|
+
});
|
|
141
|
+
const input = {
|
|
142
|
+
absoluteCurrentWorkingDirectory: '/test/workspace',
|
|
143
|
+
configPath: './missing-config.json',
|
|
144
|
+
};
|
|
145
|
+
const result = await tool.handler(input);
|
|
146
|
+
expect(mockRunCommandInDir).not.toHaveBeenCalled();
|
|
147
|
+
expect(result).toEqual({
|
|
148
|
+
content: [
|
|
149
|
+
{
|
|
150
|
+
type: 'text',
|
|
151
|
+
text: expect.stringContaining('Failed to read or parse config file at "./missing-config.json"'),
|
|
152
|
+
},
|
|
153
|
+
],
|
|
154
|
+
});
|
|
155
|
+
expect(result.content[0]).toHaveProperty('text', expect.stringContaining('Please ensure the file exists and contains valid JSON'));
|
|
156
|
+
});
|
|
157
|
+
it('should return helpful error when config file contains invalid JSON', async () => {
|
|
158
|
+
mockReadFileSync.mockReturnValue('{ invalid json }');
|
|
159
|
+
const input = {
|
|
160
|
+
absoluteCurrentWorkingDirectory: '/test/workspace',
|
|
161
|
+
configPath: './invalid-config.json',
|
|
162
|
+
};
|
|
163
|
+
const result = await tool.handler(input);
|
|
164
|
+
expect(mockRunCommandInDir).not.toHaveBeenCalled();
|
|
165
|
+
expect(result).toEqual({
|
|
166
|
+
content: [
|
|
167
|
+
{
|
|
168
|
+
type: 'text',
|
|
169
|
+
text: expect.stringContaining('Failed to read or parse config file at "./invalid-config.json"'),
|
|
170
|
+
},
|
|
171
|
+
],
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
describe('flag-based approach', () => {
|
|
176
|
+
it('should create test account with name and all defaults', async () => {
|
|
177
|
+
mockRunCommandInDir.mockResolvedValue({
|
|
178
|
+
stdout: 'Test account created successfully',
|
|
179
|
+
stderr: '',
|
|
180
|
+
});
|
|
181
|
+
const input = {
|
|
182
|
+
absoluteCurrentWorkingDirectory: '/test/workspace',
|
|
183
|
+
name: 'MyTestAccount',
|
|
184
|
+
description: '',
|
|
185
|
+
marketingLevel: 'ENTERPRISE',
|
|
186
|
+
opsLevel: 'ENTERPRISE',
|
|
187
|
+
serviceLevel: 'ENTERPRISE',
|
|
188
|
+
salesLevel: 'ENTERPRISE',
|
|
189
|
+
contentLevel: 'ENTERPRISE',
|
|
190
|
+
};
|
|
191
|
+
await tool.handler(input);
|
|
192
|
+
expect(mockAddFlag).toHaveBeenCalledWith('hs test-account create', 'name', 'MyTestAccount');
|
|
193
|
+
});
|
|
194
|
+
it('should add all flags with defaults when only name is provided', async () => {
|
|
195
|
+
mockRunCommandInDir.mockResolvedValue({
|
|
196
|
+
stdout: 'Test account created successfully',
|
|
197
|
+
stderr: '',
|
|
198
|
+
});
|
|
199
|
+
const input = {
|
|
200
|
+
absoluteCurrentWorkingDirectory: '/test/workspace',
|
|
201
|
+
name: 'MyTestAccount',
|
|
202
|
+
};
|
|
203
|
+
await tool.handler(input);
|
|
204
|
+
expect(mockAddFlag).toHaveBeenCalledWith('hs test-account create', 'name', 'MyTestAccount');
|
|
205
|
+
// Implementation uses name as fallback for description, and adds all hub levels with ENTERPRISE defaults
|
|
206
|
+
expect(mockAddFlag).toHaveBeenCalledTimes(7);
|
|
207
|
+
expect(mockRunCommandInDir).toHaveBeenCalled();
|
|
208
|
+
});
|
|
209
|
+
it('should create test account with account name and description', async () => {
|
|
210
|
+
mockRunCommandInDir.mockResolvedValue({
|
|
211
|
+
stdout: 'Test account created',
|
|
212
|
+
stderr: '',
|
|
213
|
+
});
|
|
214
|
+
const input = {
|
|
215
|
+
absoluteCurrentWorkingDirectory: '/test/workspace',
|
|
216
|
+
name: 'MyTestAccount',
|
|
217
|
+
description: 'Test account for development',
|
|
218
|
+
marketingLevel: 'ENTERPRISE',
|
|
219
|
+
opsLevel: 'ENTERPRISE',
|
|
220
|
+
serviceLevel: 'ENTERPRISE',
|
|
221
|
+
salesLevel: 'ENTERPRISE',
|
|
222
|
+
contentLevel: 'ENTERPRISE',
|
|
223
|
+
};
|
|
224
|
+
await tool.handler(input);
|
|
225
|
+
expect(mockAddFlag).toHaveBeenCalledWith('hs test-account create', 'name', 'MyTestAccount');
|
|
226
|
+
expect(mockAddFlag).toHaveBeenCalledWith(expect.stringContaining('name'), 'description', 'Test account for development');
|
|
227
|
+
});
|
|
228
|
+
it('should create test account with specific hub levels', async () => {
|
|
229
|
+
mockRunCommandInDir.mockResolvedValue({
|
|
230
|
+
stdout: 'Test account created',
|
|
231
|
+
stderr: '',
|
|
232
|
+
});
|
|
233
|
+
const input = {
|
|
234
|
+
absoluteCurrentWorkingDirectory: '/test/workspace',
|
|
235
|
+
name: 'MixedTierAccount',
|
|
236
|
+
description: 'Test account',
|
|
237
|
+
marketingLevel: 'PROFESSIONAL',
|
|
238
|
+
salesLevel: 'STARTER',
|
|
239
|
+
contentLevel: 'FREE',
|
|
240
|
+
serviceLevel: 'ENTERPRISE',
|
|
241
|
+
opsLevel: 'ENTERPRISE',
|
|
242
|
+
};
|
|
243
|
+
await tool.handler(input);
|
|
244
|
+
expect(mockAddFlag).toHaveBeenCalledWith('hs test-account create', 'name', 'MixedTierAccount');
|
|
245
|
+
expect(mockAddFlag).toHaveBeenCalledWith(expect.stringContaining('name'), 'marketing-level', 'PROFESSIONAL');
|
|
246
|
+
expect(mockAddFlag).toHaveBeenCalledWith(expect.stringContaining('marketing-level'), 'sales-level', 'STARTER');
|
|
247
|
+
expect(mockAddFlag).toHaveBeenCalledWith(expect.stringContaining('sales-level'), 'content-level', 'FREE');
|
|
248
|
+
});
|
|
249
|
+
it('should create test account with all hub levels specified', async () => {
|
|
250
|
+
mockRunCommandInDir.mockResolvedValue({
|
|
251
|
+
stdout: 'Test account created',
|
|
252
|
+
stderr: '',
|
|
253
|
+
});
|
|
254
|
+
const input = {
|
|
255
|
+
absoluteCurrentWorkingDirectory: '/test/workspace',
|
|
256
|
+
name: 'AllHubsAccount',
|
|
257
|
+
description: 'Full configuration',
|
|
258
|
+
marketingLevel: 'ENTERPRISE',
|
|
259
|
+
opsLevel: 'PROFESSIONAL',
|
|
260
|
+
serviceLevel: 'STARTER',
|
|
261
|
+
salesLevel: 'ENTERPRISE',
|
|
262
|
+
contentLevel: 'PROFESSIONAL',
|
|
263
|
+
};
|
|
264
|
+
await tool.handler(input);
|
|
265
|
+
expect(mockAddFlag).toHaveBeenCalledWith('hs test-account create', 'name', 'AllHubsAccount');
|
|
266
|
+
expect(mockAddFlag).toHaveBeenCalledWith(expect.any(String), 'description', 'Full configuration');
|
|
267
|
+
expect(mockAddFlag).toHaveBeenCalledWith(expect.any(String), 'marketing-level', 'ENTERPRISE');
|
|
268
|
+
expect(mockAddFlag).toHaveBeenCalledWith(expect.any(String), 'ops-level', 'PROFESSIONAL');
|
|
269
|
+
expect(mockAddFlag).toHaveBeenCalledWith(expect.any(String), 'service-level', 'STARTER');
|
|
270
|
+
expect(mockAddFlag).toHaveBeenCalledWith(expect.any(String), 'sales-level', 'ENTERPRISE');
|
|
271
|
+
expect(mockAddFlag).toHaveBeenCalledWith(expect.any(String), 'content-level', 'PROFESSIONAL');
|
|
272
|
+
});
|
|
273
|
+
});
|
|
274
|
+
describe('handler defaults', () => {
|
|
275
|
+
it('should use ENTERPRISE defaults for all hub levels when not specified', async () => {
|
|
276
|
+
mockRunCommandInDir.mockResolvedValue({
|
|
277
|
+
stdout: 'Test account created',
|
|
278
|
+
stderr: '',
|
|
279
|
+
});
|
|
280
|
+
const input = {
|
|
281
|
+
absoluteCurrentWorkingDirectory: '/test/workspace',
|
|
282
|
+
name: 'DefaultLevelsAccount',
|
|
283
|
+
description: '',
|
|
284
|
+
marketingLevel: 'ENTERPRISE',
|
|
285
|
+
opsLevel: 'ENTERPRISE',
|
|
286
|
+
serviceLevel: 'ENTERPRISE',
|
|
287
|
+
salesLevel: 'ENTERPRISE',
|
|
288
|
+
contentLevel: 'ENTERPRISE',
|
|
289
|
+
};
|
|
290
|
+
await tool.handler(input);
|
|
291
|
+
expect(mockAddFlag).toHaveBeenCalledWith('hs test-account create', 'name', 'DefaultLevelsAccount');
|
|
292
|
+
expect(mockAddFlag).toHaveBeenCalledWith(expect.any(String), 'marketing-level', 'ENTERPRISE');
|
|
293
|
+
expect(mockAddFlag).toHaveBeenCalledWith(expect.any(String), 'ops-level', 'ENTERPRISE');
|
|
294
|
+
expect(mockAddFlag).toHaveBeenCalledWith(expect.any(String), 'service-level', 'ENTERPRISE');
|
|
295
|
+
expect(mockAddFlag).toHaveBeenCalledWith(expect.any(String), 'sales-level', 'ENTERPRISE');
|
|
296
|
+
expect(mockAddFlag).toHaveBeenCalledWith(expect.any(String), 'content-level', 'ENTERPRISE');
|
|
297
|
+
});
|
|
298
|
+
it('should use name as fallback for description when description is empty', async () => {
|
|
299
|
+
mockRunCommandInDir.mockResolvedValue({
|
|
300
|
+
stdout: 'Test account created',
|
|
301
|
+
stderr: '',
|
|
302
|
+
});
|
|
303
|
+
const input = {
|
|
304
|
+
absoluteCurrentWorkingDirectory: '/test/workspace',
|
|
305
|
+
name: 'NoDescriptionAccount',
|
|
306
|
+
description: '',
|
|
307
|
+
marketingLevel: 'ENTERPRISE',
|
|
308
|
+
opsLevel: 'ENTERPRISE',
|
|
309
|
+
serviceLevel: 'ENTERPRISE',
|
|
310
|
+
salesLevel: 'ENTERPRISE',
|
|
311
|
+
contentLevel: 'ENTERPRISE',
|
|
312
|
+
};
|
|
313
|
+
await tool.handler(input);
|
|
314
|
+
expect(mockAddFlag).toHaveBeenCalledWith('hs test-account create', 'name', 'NoDescriptionAccount');
|
|
315
|
+
// Implementation uses name as fallback for description
|
|
316
|
+
expect(mockAddFlag).toHaveBeenCalledWith(expect.any(String), 'description', 'NoDescriptionAccount');
|
|
317
|
+
});
|
|
318
|
+
it('should use defaults for some hub levels while respecting explicit values', async () => {
|
|
319
|
+
mockRunCommandInDir.mockResolvedValue({
|
|
320
|
+
stdout: 'Test account created',
|
|
321
|
+
stderr: '',
|
|
322
|
+
});
|
|
323
|
+
const input = {
|
|
324
|
+
absoluteCurrentWorkingDirectory: '/test/workspace',
|
|
325
|
+
name: 'PartialLevelsAccount',
|
|
326
|
+
description: '',
|
|
327
|
+
marketingLevel: 'FREE',
|
|
328
|
+
salesLevel: 'STARTER',
|
|
329
|
+
opsLevel: 'ENTERPRISE',
|
|
330
|
+
serviceLevel: 'ENTERPRISE',
|
|
331
|
+
contentLevel: 'ENTERPRISE',
|
|
332
|
+
};
|
|
333
|
+
await tool.handler(input);
|
|
334
|
+
expect(mockAddFlag).toHaveBeenCalledWith('hs test-account create', 'name', 'PartialLevelsAccount');
|
|
335
|
+
expect(mockAddFlag).toHaveBeenCalledWith(expect.any(String), 'marketing-level', 'FREE');
|
|
336
|
+
expect(mockAddFlag).toHaveBeenCalledWith(expect.any(String), 'sales-level', 'STARTER');
|
|
337
|
+
expect(mockAddFlag).toHaveBeenCalledWith(expect.any(String), 'ops-level', 'ENTERPRISE');
|
|
338
|
+
expect(mockAddFlag).toHaveBeenCalledWith(expect.any(String), 'service-level', 'ENTERPRISE');
|
|
339
|
+
expect(mockAddFlag).toHaveBeenCalledWith(expect.any(String), 'content-level', 'ENTERPRISE');
|
|
340
|
+
});
|
|
341
|
+
it('should add all hub level flags when defaults are applied', async () => {
|
|
342
|
+
mockRunCommandInDir.mockResolvedValue({
|
|
343
|
+
stdout: 'Test account created with defaults',
|
|
344
|
+
stderr: '',
|
|
345
|
+
});
|
|
346
|
+
const input = {
|
|
347
|
+
absoluteCurrentWorkingDirectory: '/test/workspace',
|
|
348
|
+
name: 'MinimalAccount',
|
|
349
|
+
description: '',
|
|
350
|
+
marketingLevel: 'ENTERPRISE',
|
|
351
|
+
opsLevel: 'ENTERPRISE',
|
|
352
|
+
serviceLevel: 'ENTERPRISE',
|
|
353
|
+
salesLevel: 'ENTERPRISE',
|
|
354
|
+
contentLevel: 'ENTERPRISE',
|
|
355
|
+
};
|
|
356
|
+
const result = await tool.handler(input);
|
|
357
|
+
expect(mockRunCommandInDir).toHaveBeenCalled();
|
|
358
|
+
expect(mockAddFlag).toHaveBeenCalledTimes(7);
|
|
359
|
+
expect(result.content[1]).toEqual({
|
|
360
|
+
type: 'text',
|
|
361
|
+
text: 'Test account created with defaults',
|
|
362
|
+
});
|
|
363
|
+
});
|
|
364
|
+
it('should use ENTERPRISE defaults when values are undefined', async () => {
|
|
365
|
+
mockRunCommandInDir.mockResolvedValue({
|
|
366
|
+
stdout: 'Test account created',
|
|
367
|
+
stderr: '',
|
|
368
|
+
});
|
|
369
|
+
const input = {
|
|
370
|
+
absoluteCurrentWorkingDirectory: '/test/workspace',
|
|
371
|
+
name: 'BypassedDefaultsAccount',
|
|
372
|
+
};
|
|
373
|
+
await tool.handler(input);
|
|
374
|
+
expect(mockAddFlag).toHaveBeenCalledWith('hs test-account create', 'name', 'BypassedDefaultsAccount');
|
|
375
|
+
expect(mockAddFlag).toHaveBeenCalledTimes(7);
|
|
376
|
+
});
|
|
377
|
+
});
|
|
378
|
+
describe('interactive mode', () => {
|
|
379
|
+
it('should ask for parameters when neither config nor name provided', async () => {
|
|
380
|
+
const input = {
|
|
381
|
+
absoluteCurrentWorkingDirectory: '/test/workspace',
|
|
382
|
+
description: 'Test account',
|
|
383
|
+
marketingLevel: 'ENTERPRISE',
|
|
384
|
+
opsLevel: 'ENTERPRISE',
|
|
385
|
+
serviceLevel: 'ENTERPRISE',
|
|
386
|
+
salesLevel: 'ENTERPRISE',
|
|
387
|
+
contentLevel: 'ENTERPRISE',
|
|
388
|
+
};
|
|
389
|
+
const result = await tool.handler(input);
|
|
390
|
+
// Should NOT run the command
|
|
391
|
+
expect(mockRunCommandInDir).not.toHaveBeenCalled();
|
|
392
|
+
// Should return a message asking for information
|
|
393
|
+
expect(result).toEqual({
|
|
394
|
+
content: [
|
|
395
|
+
{
|
|
396
|
+
type: 'text',
|
|
397
|
+
text: 'Ask the user for the account config JSON path or the name of the test account to create.',
|
|
398
|
+
},
|
|
399
|
+
],
|
|
400
|
+
});
|
|
401
|
+
});
|
|
402
|
+
});
|
|
403
|
+
describe('error handling', () => {
|
|
404
|
+
it('should handle command output with stderr warnings', async () => {
|
|
405
|
+
mockRunCommandInDir.mockResolvedValue({
|
|
406
|
+
stdout: 'Test account created successfully',
|
|
407
|
+
stderr: 'Warning: Some non-critical warning message',
|
|
408
|
+
});
|
|
409
|
+
const input = {
|
|
410
|
+
absoluteCurrentWorkingDirectory: '/test/workspace',
|
|
411
|
+
configPath: './test-account.json',
|
|
412
|
+
description: 'Test account',
|
|
413
|
+
marketingLevel: 'ENTERPRISE',
|
|
414
|
+
opsLevel: 'ENTERPRISE',
|
|
415
|
+
serviceLevel: 'ENTERPRISE',
|
|
416
|
+
salesLevel: 'ENTERPRISE',
|
|
417
|
+
contentLevel: 'ENTERPRISE',
|
|
418
|
+
};
|
|
419
|
+
const result = await tool.handler(input);
|
|
420
|
+
expect(result).toEqual({
|
|
421
|
+
content: [
|
|
422
|
+
{ type: 'text', text: '/test/workspace' },
|
|
423
|
+
{ type: 'text', text: 'Test account created successfully' },
|
|
424
|
+
{
|
|
425
|
+
type: 'text',
|
|
426
|
+
text: 'Warning: Some non-critical warning message',
|
|
427
|
+
},
|
|
428
|
+
],
|
|
429
|
+
});
|
|
430
|
+
});
|
|
431
|
+
it('should handle command execution errors', async () => {
|
|
432
|
+
const error = new Error('Failed to create test account');
|
|
433
|
+
mockRunCommandInDir.mockRejectedValue(error);
|
|
434
|
+
const input = {
|
|
435
|
+
absoluteCurrentWorkingDirectory: '/test/workspace',
|
|
436
|
+
configPath: './test-account.json',
|
|
437
|
+
description: 'Test account',
|
|
438
|
+
marketingLevel: 'ENTERPRISE',
|
|
439
|
+
opsLevel: 'ENTERPRISE',
|
|
440
|
+
serviceLevel: 'ENTERPRISE',
|
|
441
|
+
salesLevel: 'ENTERPRISE',
|
|
442
|
+
contentLevel: 'ENTERPRISE',
|
|
443
|
+
};
|
|
444
|
+
const result = await tool.handler(input);
|
|
445
|
+
expect(result).toEqual({
|
|
446
|
+
content: [
|
|
447
|
+
{ type: 'text', text: '/test/workspace' },
|
|
448
|
+
{ type: 'text', text: 'Failed to create test account' },
|
|
449
|
+
],
|
|
450
|
+
});
|
|
451
|
+
});
|
|
452
|
+
});
|
|
453
|
+
});
|
|
454
|
+
});
|
|
@@ -2,12 +2,15 @@ import { DocFetchTool } from '../DocFetchTool.js';
|
|
|
2
2
|
import { http } from '@hubspot/local-dev-lib/http/unauthed';
|
|
3
3
|
import { isHubSpotHttpError } from '@hubspot/local-dev-lib/errors/index';
|
|
4
4
|
import { mcpFeedbackRequest } from '../../../utils/feedbackTracking.js';
|
|
5
|
+
import { trackToolUsage } from '../../../utils/toolUsageTracking.js';
|
|
5
6
|
vi.mock('@modelcontextprotocol/sdk/server/mcp.js');
|
|
6
7
|
vi.mock('@hubspot/local-dev-lib/http/unauthed');
|
|
7
8
|
vi.mock('@hubspot/local-dev-lib/errors/index');
|
|
8
|
-
vi.mock('
|
|
9
|
+
vi.mock('@hubspot/local-dev-lib/config');
|
|
10
|
+
vi.mock('../../../utils/toolUsageTracking');
|
|
9
11
|
vi.mock('../../../utils/feedbackTracking');
|
|
10
12
|
const mockMcpFeedbackRequest = mcpFeedbackRequest;
|
|
13
|
+
const mockTrackToolUsage = trackToolUsage;
|
|
11
14
|
const mockHttp = http;
|
|
12
15
|
const mockIsHubSpotHttpError = vi.mocked(isHubSpotHttpError);
|
|
13
16
|
describe('mcp-server/tools/project/DocFetchTool', () => {
|
|
@@ -23,6 +26,7 @@ describe('mcp-server/tools/project/DocFetchTool', () => {
|
|
|
23
26
|
mockRegisteredTool = {};
|
|
24
27
|
mockMcpServer.registerTool.mockReturnValue(mockRegisteredTool);
|
|
25
28
|
mockMcpFeedbackRequest.mockResolvedValue('');
|
|
29
|
+
mockTrackToolUsage.mockResolvedValue(undefined);
|
|
26
30
|
tool = new DocFetchTool(mockMcpServer);
|
|
27
31
|
});
|
|
28
32
|
describe('register', () => {
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import { DocsSearchTool } from '../DocsSearchTool.js';
|
|
2
2
|
import { http } from '@hubspot/local-dev-lib/http';
|
|
3
3
|
import { isHubSpotHttpError } from '@hubspot/local-dev-lib/errors/index';
|
|
4
|
-
import {
|
|
4
|
+
import { getConfigDefaultAccountIfExists } from '@hubspot/local-dev-lib/config';
|
|
5
5
|
import { mcpFeedbackRequest } from '../../../utils/feedbackTracking.js';
|
|
6
6
|
vi.mock('@modelcontextprotocol/sdk/server/mcp.js');
|
|
7
7
|
vi.mock('@hubspot/local-dev-lib/http');
|
|
8
8
|
vi.mock('@hubspot/local-dev-lib/errors/index');
|
|
9
|
+
vi.mock('@hubspot/local-dev-lib/config');
|
|
9
10
|
vi.mock('../../../utils/toolUsageTracking');
|
|
10
|
-
vi.mock('../../../utils/cliConfig.js');
|
|
11
11
|
vi.mock('../../../utils/feedbackTracking');
|
|
12
12
|
const mockMcpFeedbackRequest = mcpFeedbackRequest;
|
|
13
13
|
const mockHttp = http;
|
|
14
|
-
const mockGetAccountIdFromCliConfig = getAccountIdFromCliConfig;
|
|
15
14
|
const mockIsHubSpotHttpError = vi.mocked(isHubSpotHttpError);
|
|
15
|
+
const mockGetConfigDefaultAccountIfExists = getConfigDefaultAccountIfExists;
|
|
16
16
|
describe('mcp-server/tools/project/DocsSearchTool', () => {
|
|
17
17
|
let mockMcpServer;
|
|
18
18
|
let tool;
|
|
@@ -31,11 +31,11 @@ describe('mcp-server/tools/project/DocsSearchTool', () => {
|
|
|
31
31
|
describe('register', () => {
|
|
32
32
|
it('should register tool with correct parameters and enhanced description', () => {
|
|
33
33
|
const result = tool.register();
|
|
34
|
-
expect(mockMcpServer.registerTool).toHaveBeenCalledWith('search-docs', {
|
|
34
|
+
expect(mockMcpServer.registerTool).toHaveBeenCalledWith('search-docs', expect.objectContaining({
|
|
35
35
|
title: 'Search HubSpot Developer Documentation',
|
|
36
36
|
description: 'Use this first whenever you need details about HubSpot APIs, SDKs, integrations, or developer platform features. This searches the official HubSpot Developer Documentation and returns the most relevant pages, each with a URL for use in `fetch-doc`. Always follow this with a fetch to get the full, authoritative content before making plans or writing answers.',
|
|
37
37
|
inputSchema: expect.any(Object),
|
|
38
|
-
}, expect.any(Function));
|
|
38
|
+
}), expect.any(Function));
|
|
39
39
|
expect(result).toBe(mockRegisteredTool);
|
|
40
40
|
});
|
|
41
41
|
});
|
|
@@ -45,7 +45,7 @@ describe('mcp-server/tools/project/DocsSearchTool', () => {
|
|
|
45
45
|
absoluteCurrentWorkingDirectory: '/foo',
|
|
46
46
|
};
|
|
47
47
|
it('should return auth error message when no account ID is found', async () => {
|
|
48
|
-
|
|
48
|
+
mockGetConfigDefaultAccountIfExists.mockReturnValue(undefined);
|
|
49
49
|
const result = await tool.handler(mockInput);
|
|
50
50
|
expect(result).toEqual({
|
|
51
51
|
content: [
|
|
@@ -57,7 +57,9 @@ describe('mcp-server/tools/project/DocsSearchTool', () => {
|
|
|
57
57
|
});
|
|
58
58
|
});
|
|
59
59
|
it('should return successful results when docs are found', async () => {
|
|
60
|
-
|
|
60
|
+
mockGetConfigDefaultAccountIfExists.mockReturnValue({
|
|
61
|
+
accountId: 12345,
|
|
62
|
+
});
|
|
61
63
|
const mockResponse = {
|
|
62
64
|
results: [
|
|
63
65
|
{
|
|
@@ -81,7 +83,7 @@ describe('mcp-server/tools/project/DocsSearchTool', () => {
|
|
|
81
83
|
data: mockResponse,
|
|
82
84
|
});
|
|
83
85
|
const result = await tool.handler(mockInput);
|
|
84
|
-
expect(
|
|
86
|
+
expect(mockGetConfigDefaultAccountIfExists).toHaveBeenCalled();
|
|
85
87
|
expect(mockHttp.post).toHaveBeenCalledWith(12345, {
|
|
86
88
|
url: 'dev/docs/llms/v1/docs-search',
|
|
87
89
|
data: {
|
|
@@ -109,7 +111,9 @@ describe('mcp-server/tools/project/DocsSearchTool', () => {
|
|
|
109
111
|
expect(resultText).toContain('Test content 2');
|
|
110
112
|
});
|
|
111
113
|
it('should return no results message when no documentation is found', async () => {
|
|
112
|
-
|
|
114
|
+
mockGetConfigDefaultAccountIfExists.mockReturnValue({
|
|
115
|
+
accountId: 12345,
|
|
116
|
+
});
|
|
113
117
|
const mockResponse = {
|
|
114
118
|
results: [],
|
|
115
119
|
};
|
|
@@ -128,7 +132,9 @@ describe('mcp-server/tools/project/DocsSearchTool', () => {
|
|
|
128
132
|
});
|
|
129
133
|
});
|
|
130
134
|
it('should return no results message when results is null', async () => {
|
|
131
|
-
|
|
135
|
+
mockGetConfigDefaultAccountIfExists.mockReturnValue({
|
|
136
|
+
accountId: 12345,
|
|
137
|
+
});
|
|
132
138
|
const mockResponse = {
|
|
133
139
|
results: null,
|
|
134
140
|
};
|
|
@@ -147,7 +153,9 @@ describe('mcp-server/tools/project/DocsSearchTool', () => {
|
|
|
147
153
|
});
|
|
148
154
|
});
|
|
149
155
|
it('should handle HubSpot HTTP errors', async () => {
|
|
150
|
-
|
|
156
|
+
mockGetConfigDefaultAccountIfExists.mockReturnValue({
|
|
157
|
+
accountId: 12345,
|
|
158
|
+
});
|
|
151
159
|
const mockError = {
|
|
152
160
|
toString: () => 'HubSpot API Error: 404 Not Found',
|
|
153
161
|
};
|
|
@@ -164,7 +172,9 @@ describe('mcp-server/tools/project/DocsSearchTool', () => {
|
|
|
164
172
|
});
|
|
165
173
|
});
|
|
166
174
|
it('should handle generic errors', async () => {
|
|
167
|
-
|
|
175
|
+
mockGetConfigDefaultAccountIfExists.mockReturnValue({
|
|
176
|
+
accountId: 12345,
|
|
177
|
+
});
|
|
168
178
|
const mockError = new Error('Network error');
|
|
169
179
|
mockHttp.post.mockRejectedValue(mockError);
|
|
170
180
|
mockIsHubSpotHttpError.mockReturnValue(false);
|
|
@@ -179,7 +189,9 @@ describe('mcp-server/tools/project/DocsSearchTool', () => {
|
|
|
179
189
|
});
|
|
180
190
|
});
|
|
181
191
|
it('should handle non-Error rejections', async () => {
|
|
182
|
-
|
|
192
|
+
mockGetConfigDefaultAccountIfExists.mockReturnValue({
|
|
193
|
+
accountId: 12345,
|
|
194
|
+
});
|
|
183
195
|
mockHttp.post.mockRejectedValue('String error');
|
|
184
196
|
mockIsHubSpotHttpError.mockReturnValue(false);
|
|
185
197
|
const result = await tool.handler(mockInput);
|