@hubspot/cli 7.10.0-beta.1 → 7.10.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/commands/testAccount/__tests__/create.test.js +5 -5
- package/lang/en.js +5 -5
- package/lib/projects/__tests__/components.test.js +1 -1
- package/lib/projects/components.js +1 -1
- package/mcp-server/tools/project/CreateTestAccountTool.js +33 -20
- package/mcp-server/tools/project/__tests__/CreateTestAccountTool.test.js +215 -2
- package/package.json +1 -1
|
@@ -48,27 +48,27 @@ describe('commands/testAccount/create', () => {
|
|
|
48
48
|
testAccountCreateCommand.builder(yargsMock);
|
|
49
49
|
expect(yargsMock.option).toHaveBeenCalledWith('marketing-level', {
|
|
50
50
|
type: 'string',
|
|
51
|
-
description: 'Marketing Hub tier.
|
|
51
|
+
description: 'Marketing Hub tier. Options: FREE, STARTER, PROFESSIONAL, ENTERPRISE',
|
|
52
52
|
choices: ACCOUNT_LEVEL_CHOICES,
|
|
53
53
|
});
|
|
54
54
|
expect(yargsMock.option).toHaveBeenCalledWith('ops-level', {
|
|
55
55
|
type: 'string',
|
|
56
|
-
description: 'Operations Hub tier.
|
|
56
|
+
description: 'Operations Hub tier. Options: FREE, STARTER, PROFESSIONAL, ENTERPRISE',
|
|
57
57
|
choices: ACCOUNT_LEVEL_CHOICES,
|
|
58
58
|
});
|
|
59
59
|
expect(yargsMock.option).toHaveBeenCalledWith('service-level', {
|
|
60
60
|
type: 'string',
|
|
61
|
-
description: 'Service Hub tier.
|
|
61
|
+
description: 'Service Hub tier. Options: FREE, STARTER, PROFESSIONAL, ENTERPRISE',
|
|
62
62
|
choices: ACCOUNT_LEVEL_CHOICES,
|
|
63
63
|
});
|
|
64
64
|
expect(yargsMock.option).toHaveBeenCalledWith('sales-level', {
|
|
65
65
|
type: 'string',
|
|
66
|
-
description: 'Sales Hub tier.
|
|
66
|
+
description: 'Sales Hub tier. Options: FREE, STARTER, PROFESSIONAL, ENTERPRISE',
|
|
67
67
|
choices: ACCOUNT_LEVEL_CHOICES,
|
|
68
68
|
});
|
|
69
69
|
expect(yargsMock.option).toHaveBeenCalledWith('content-level', {
|
|
70
70
|
type: 'string',
|
|
71
|
-
description: 'CMS Hub tier.
|
|
71
|
+
description: 'CMS Hub tier. Options: FREE, STARTER, PROFESSIONAL, ENTERPRISE',
|
|
72
72
|
choices: ACCOUNT_LEVEL_CHOICES,
|
|
73
73
|
});
|
|
74
74
|
});
|
package/lang/en.js
CHANGED
|
@@ -2121,11 +2121,11 @@ export const commands = {
|
|
|
2121
2121
|
configPath: 'Path to config file (mutually exclusive with other flags)',
|
|
2122
2122
|
accountName: 'Name for the test account',
|
|
2123
2123
|
description: 'Description for the test account',
|
|
2124
|
-
marketingLevel: 'Marketing Hub tier.
|
|
2125
|
-
opsLevel: 'Operations Hub tier.
|
|
2126
|
-
serviceLevel: 'Service Hub tier.
|
|
2127
|
-
salesLevel: 'Sales Hub tier.
|
|
2128
|
-
contentLevel: 'CMS Hub tier.
|
|
2124
|
+
marketingLevel: 'Marketing Hub tier. Options: FREE, STARTER, PROFESSIONAL, ENTERPRISE',
|
|
2125
|
+
opsLevel: 'Operations Hub tier. Options: FREE, STARTER, PROFESSIONAL, ENTERPRISE',
|
|
2126
|
+
serviceLevel: 'Service Hub tier. Options: FREE, STARTER, PROFESSIONAL, ENTERPRISE',
|
|
2127
|
+
salesLevel: 'Sales Hub tier. Options: FREE, STARTER, PROFESSIONAL, ENTERPRISE',
|
|
2128
|
+
contentLevel: 'CMS Hub tier. Options: FREE, STARTER, PROFESSIONAL, ENTERPRISE',
|
|
2129
2129
|
},
|
|
2130
2130
|
example: (configPath) => `Create a test account from the config file at ${configPath}`,
|
|
2131
2131
|
examples: {
|
|
@@ -341,7 +341,7 @@ describe('lib/projects/components', () => {
|
|
|
341
341
|
// The differentiator is appended with a hyphen, so the final UID has a hyphen before the number
|
|
342
342
|
expect(mockedFs.writeFileSync).toHaveBeenCalledWith('/path/to/component1.meta.json', JSON.stringify({
|
|
343
343
|
type: 'card',
|
|
344
|
-
uid: '
|
|
344
|
+
uid: 'card_collision_project_2',
|
|
345
345
|
}, null, 2));
|
|
346
346
|
});
|
|
347
347
|
it('falls back to original uid when coerceToValidUid returns null', () => {
|
|
@@ -137,7 +137,7 @@ export function updateHsMetaFilesWithAutoGeneratedFields(projectName, hsMetaFile
|
|
|
137
137
|
let differentiator = 1;
|
|
138
138
|
while (existingUids.includes(uid)) {
|
|
139
139
|
differentiator++;
|
|
140
|
-
uid = `${getBaseUid()}
|
|
140
|
+
uid = `${getBaseUid()}_${differentiator}`;
|
|
141
141
|
}
|
|
142
142
|
component.uid = uid;
|
|
143
143
|
if (component.type === AppKey && component.config) {
|
|
@@ -6,6 +6,8 @@ import { formatTextContents, formatTextContent } from '../../utils/content.js';
|
|
|
6
6
|
import { addFlag } from '../../utils/command.js';
|
|
7
7
|
import { runCommandInDir } from '../../utils/project.js';
|
|
8
8
|
import { ACCOUNT_LEVEL_CHOICES } from '../../../lib/constants.js';
|
|
9
|
+
import { getAccountIdFromCliConfig } from '../../utils/cliConfig.js';
|
|
10
|
+
import fs from 'fs';
|
|
9
11
|
const inputSchema = {
|
|
10
12
|
absoluteCurrentWorkingDirectory,
|
|
11
13
|
configPath: z
|
|
@@ -29,7 +31,7 @@ const inputSchema = {
|
|
|
29
31
|
description: z
|
|
30
32
|
.string()
|
|
31
33
|
.optional()
|
|
32
|
-
.describe('Description for the test account.
|
|
34
|
+
.describe('Description for the test account. Required when not using configPath.'),
|
|
33
35
|
marketingLevel: z
|
|
34
36
|
.enum(ACCOUNT_LEVEL_CHOICES)
|
|
35
37
|
.optional()
|
|
@@ -64,29 +66,40 @@ export class CreateTestAccountTool extends Tool {
|
|
|
64
66
|
const content = [];
|
|
65
67
|
// Use config file if provided (LLM should check for config first)
|
|
66
68
|
if (configPath) {
|
|
69
|
+
let configJson;
|
|
70
|
+
try {
|
|
71
|
+
const config = fs.readFileSync(configPath, 'utf8');
|
|
72
|
+
configJson = JSON.parse(config);
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
76
|
+
return {
|
|
77
|
+
content: [
|
|
78
|
+
formatTextContent(`Failed to read or parse config file at "${configPath}": ${errorMessage}. Please ensure the file exists and contains valid JSON.`),
|
|
79
|
+
],
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
if (configJson.accountName) {
|
|
83
|
+
const nameInConfig = getAccountIdFromCliConfig(absoluteCurrentWorkingDirectory, configJson.accountName);
|
|
84
|
+
if (nameInConfig) {
|
|
85
|
+
content.push(formatTextContent(`The account name "${configJson.accountName}" already exists in the CLI config. Please use a different name.`));
|
|
86
|
+
}
|
|
87
|
+
}
|
|
67
88
|
command = addFlag(command, 'config-path', configPath);
|
|
68
89
|
}
|
|
69
90
|
// Use flags if name is provided (when no config used)
|
|
70
91
|
else if (name) {
|
|
71
|
-
|
|
72
|
-
if (
|
|
73
|
-
|
|
74
|
-
}
|
|
75
|
-
if (marketingLevel) {
|
|
76
|
-
command = addFlag(command, 'marketing-level', marketingLevel);
|
|
77
|
-
}
|
|
78
|
-
if (opsLevel) {
|
|
79
|
-
command = addFlag(command, 'ops-level', opsLevel);
|
|
80
|
-
}
|
|
81
|
-
if (serviceLevel) {
|
|
82
|
-
command = addFlag(command, 'service-level', serviceLevel);
|
|
83
|
-
}
|
|
84
|
-
if (salesLevel) {
|
|
85
|
-
command = addFlag(command, 'sales-level', salesLevel);
|
|
86
|
-
}
|
|
87
|
-
if (contentLevel) {
|
|
88
|
-
command = addFlag(command, 'content-level', contentLevel);
|
|
92
|
+
const nameInConfig = getAccountIdFromCliConfig(absoluteCurrentWorkingDirectory, name);
|
|
93
|
+
if (nameInConfig) {
|
|
94
|
+
content.push(formatTextContent(`The account name "${name}" already exists in the CLI config. Please use a different name.`));
|
|
89
95
|
}
|
|
96
|
+
command = addFlag(command, 'name', name);
|
|
97
|
+
command = addFlag(command, 'description', description || name);
|
|
98
|
+
command = addFlag(command, 'marketing-level', marketingLevel || 'ENTERPRISE');
|
|
99
|
+
command = addFlag(command, 'ops-level', opsLevel || 'ENTERPRISE');
|
|
100
|
+
command = addFlag(command, 'service-level', serviceLevel || 'ENTERPRISE');
|
|
101
|
+
command = addFlag(command, 'sales-level', salesLevel || 'ENTERPRISE');
|
|
102
|
+
command = addFlag(command, 'content-level', contentLevel || 'ENTERPRISE');
|
|
90
103
|
}
|
|
91
104
|
else {
|
|
92
105
|
content.push(formatTextContent(`Ask the user for the account config JSON path or the name of the test account to create.`));
|
|
@@ -119,7 +132,7 @@ export class CreateTestAccountTool extends Tool {
|
|
|
119
132
|
'3. If no config file OR user declined:\n' +
|
|
120
133
|
' - Ask the user for ALL account details:\n' +
|
|
121
134
|
' * Account name (required)\n' +
|
|
122
|
-
' * Description (
|
|
135
|
+
' * Description (optional, defaults to account name if not specified)\n' +
|
|
123
136
|
' * Hub tier levels for each hub (optional, default to ENTERPRISE if not specified)\n' +
|
|
124
137
|
' - Call this tool with name, description, and all tier level parameters\n' +
|
|
125
138
|
' - IMPORTANT: Always provide all parameters to ensure non-interactive execution\n\n' +
|
|
@@ -2,14 +2,17 @@ import { CreateTestAccountTool, } from '../CreateTestAccountTool.js';
|
|
|
2
2
|
import { runCommandInDir } from '../../../utils/project.js';
|
|
3
3
|
import { addFlag } from '../../../utils/command.js';
|
|
4
4
|
import { mcpFeedbackRequest } from '../../../utils/feedbackTracking.js';
|
|
5
|
+
import fs from 'fs';
|
|
5
6
|
vi.mock('@modelcontextprotocol/sdk/server/mcp.js');
|
|
6
7
|
vi.mock('../../../utils/project');
|
|
7
8
|
vi.mock('../../../utils/command');
|
|
8
9
|
vi.mock('../../../utils/toolUsageTracking');
|
|
9
10
|
vi.mock('../../../utils/feedbackTracking');
|
|
11
|
+
vi.mock('fs');
|
|
10
12
|
const mockMcpFeedbackRequest = mcpFeedbackRequest;
|
|
11
13
|
const mockRunCommandInDir = runCommandInDir;
|
|
12
14
|
const mockAddFlag = addFlag;
|
|
15
|
+
const mockReadFileSync = fs.readFileSync;
|
|
13
16
|
describe('mcp-server/tools/project/CreateTestAccountTool', () => {
|
|
14
17
|
let mockMcpServer;
|
|
15
18
|
let tool;
|
|
@@ -26,6 +29,12 @@ describe('mcp-server/tools/project/CreateTestAccountTool', () => {
|
|
|
26
29
|
tool = new CreateTestAccountTool(mockMcpServer);
|
|
27
30
|
// Mock addFlag to simulate command building
|
|
28
31
|
mockAddFlag.mockImplementation((command, flag, value) => `${command} --${flag} "${value}"`);
|
|
32
|
+
// Mock fs.readFileSync for config file tests
|
|
33
|
+
mockReadFileSync.mockReturnValue(JSON.stringify({
|
|
34
|
+
accountName: 'TestAccountFromConfig',
|
|
35
|
+
description: 'Test description',
|
|
36
|
+
marketingLevel: 'PROFESSIONAL',
|
|
37
|
+
}));
|
|
29
38
|
});
|
|
30
39
|
describe('register', () => {
|
|
31
40
|
it('should register tool with correct parameters', () => {
|
|
@@ -54,6 +63,12 @@ describe('mcp-server/tools/project/CreateTestAccountTool', () => {
|
|
|
54
63
|
const baseInput = {
|
|
55
64
|
absoluteCurrentWorkingDirectory: '/test/workspace',
|
|
56
65
|
configPath: './test-account.json',
|
|
66
|
+
description: 'Test account',
|
|
67
|
+
marketingLevel: 'ENTERPRISE',
|
|
68
|
+
opsLevel: 'ENTERPRISE',
|
|
69
|
+
serviceLevel: 'ENTERPRISE',
|
|
70
|
+
salesLevel: 'ENTERPRISE',
|
|
71
|
+
contentLevel: 'ENTERPRISE',
|
|
57
72
|
};
|
|
58
73
|
it('should create test account with config path', async () => {
|
|
59
74
|
mockRunCommandInDir.mockResolvedValue({
|
|
@@ -81,6 +96,12 @@ describe('mcp-server/tools/project/CreateTestAccountTool', () => {
|
|
|
81
96
|
const input = {
|
|
82
97
|
absoluteCurrentWorkingDirectory: '/test/workspace',
|
|
83
98
|
configPath: '/absolute/path/to/config.json',
|
|
99
|
+
description: 'Test account',
|
|
100
|
+
marketingLevel: 'ENTERPRISE',
|
|
101
|
+
opsLevel: 'ENTERPRISE',
|
|
102
|
+
serviceLevel: 'ENTERPRISE',
|
|
103
|
+
salesLevel: 'ENTERPRISE',
|
|
104
|
+
contentLevel: 'ENTERPRISE',
|
|
84
105
|
};
|
|
85
106
|
await tool.handler(input);
|
|
86
107
|
expect(mockAddFlag).toHaveBeenCalledWith('hs test-account create', 'config-path', '/absolute/path/to/config.json');
|
|
@@ -96,15 +117,57 @@ describe('mcp-server/tools/project/CreateTestAccountTool', () => {
|
|
|
96
117
|
configPath: './test-account.json',
|
|
97
118
|
name: 'FlagAccount',
|
|
98
119
|
description: 'This should be ignored',
|
|
120
|
+
marketingLevel: 'ENTERPRISE',
|
|
121
|
+
opsLevel: 'ENTERPRISE',
|
|
122
|
+
serviceLevel: 'ENTERPRISE',
|
|
123
|
+
salesLevel: 'ENTERPRISE',
|
|
124
|
+
contentLevel: 'ENTERPRISE',
|
|
99
125
|
};
|
|
100
126
|
await tool.handler(input);
|
|
101
127
|
expect(mockAddFlag).toHaveBeenCalledWith('hs test-account create', 'config-path', './test-account.json');
|
|
102
128
|
// Should not call addFlag for name or description
|
|
103
129
|
expect(mockAddFlag).not.toHaveBeenCalledWith(expect.anything(), 'name', expect.anything());
|
|
104
130
|
});
|
|
131
|
+
it('should return helpful error when config file does not exist', async () => {
|
|
132
|
+
mockReadFileSync.mockImplementation(() => {
|
|
133
|
+
throw new Error("ENOENT: no such file or directory, open './missing-config.json'");
|
|
134
|
+
});
|
|
135
|
+
const input = {
|
|
136
|
+
absoluteCurrentWorkingDirectory: '/test/workspace',
|
|
137
|
+
configPath: './missing-config.json',
|
|
138
|
+
};
|
|
139
|
+
const result = await tool.handler(input);
|
|
140
|
+
expect(mockRunCommandInDir).not.toHaveBeenCalled();
|
|
141
|
+
expect(result).toEqual({
|
|
142
|
+
content: [
|
|
143
|
+
{
|
|
144
|
+
type: 'text',
|
|
145
|
+
text: expect.stringContaining('Failed to read or parse config file at "./missing-config.json"'),
|
|
146
|
+
},
|
|
147
|
+
],
|
|
148
|
+
});
|
|
149
|
+
expect(result.content[0]).toHaveProperty('text', expect.stringContaining('Please ensure the file exists and contains valid JSON'));
|
|
150
|
+
});
|
|
151
|
+
it('should return helpful error when config file contains invalid JSON', async () => {
|
|
152
|
+
mockReadFileSync.mockReturnValue('{ invalid json }');
|
|
153
|
+
const input = {
|
|
154
|
+
absoluteCurrentWorkingDirectory: '/test/workspace',
|
|
155
|
+
configPath: './invalid-config.json',
|
|
156
|
+
};
|
|
157
|
+
const result = await tool.handler(input);
|
|
158
|
+
expect(mockRunCommandInDir).not.toHaveBeenCalled();
|
|
159
|
+
expect(result).toEqual({
|
|
160
|
+
content: [
|
|
161
|
+
{
|
|
162
|
+
type: 'text',
|
|
163
|
+
text: expect.stringContaining('Failed to read or parse config file at "./invalid-config.json"'),
|
|
164
|
+
},
|
|
165
|
+
],
|
|
166
|
+
});
|
|
167
|
+
});
|
|
105
168
|
});
|
|
106
169
|
describe('flag-based approach', () => {
|
|
107
|
-
it('should create test account with
|
|
170
|
+
it('should create test account with name and all defaults', async () => {
|
|
108
171
|
mockRunCommandInDir.mockResolvedValue({
|
|
109
172
|
stdout: 'Test account created successfully',
|
|
110
173
|
stderr: '',
|
|
@@ -112,10 +175,30 @@ describe('mcp-server/tools/project/CreateTestAccountTool', () => {
|
|
|
112
175
|
const input = {
|
|
113
176
|
absoluteCurrentWorkingDirectory: '/test/workspace',
|
|
114
177
|
name: 'MyTestAccount',
|
|
178
|
+
description: '',
|
|
179
|
+
marketingLevel: 'ENTERPRISE',
|
|
180
|
+
opsLevel: 'ENTERPRISE',
|
|
181
|
+
serviceLevel: 'ENTERPRISE',
|
|
182
|
+
salesLevel: 'ENTERPRISE',
|
|
183
|
+
contentLevel: 'ENTERPRISE',
|
|
115
184
|
};
|
|
116
185
|
await tool.handler(input);
|
|
117
186
|
expect(mockAddFlag).toHaveBeenCalledWith('hs test-account create', 'name', 'MyTestAccount');
|
|
118
|
-
|
|
187
|
+
});
|
|
188
|
+
it('should add all flags with defaults when only name is provided', async () => {
|
|
189
|
+
mockRunCommandInDir.mockResolvedValue({
|
|
190
|
+
stdout: 'Test account created successfully',
|
|
191
|
+
stderr: '',
|
|
192
|
+
});
|
|
193
|
+
const input = {
|
|
194
|
+
absoluteCurrentWorkingDirectory: '/test/workspace',
|
|
195
|
+
name: 'MyTestAccount',
|
|
196
|
+
};
|
|
197
|
+
await tool.handler(input);
|
|
198
|
+
expect(mockAddFlag).toHaveBeenCalledWith('hs test-account create', 'name', 'MyTestAccount');
|
|
199
|
+
// Implementation uses name as fallback for description, and adds all hub levels with ENTERPRISE defaults
|
|
200
|
+
expect(mockAddFlag).toHaveBeenCalledTimes(7);
|
|
201
|
+
expect(mockRunCommandInDir).toHaveBeenCalled();
|
|
119
202
|
});
|
|
120
203
|
it('should create test account with account name and description', async () => {
|
|
121
204
|
mockRunCommandInDir.mockResolvedValue({
|
|
@@ -126,6 +209,11 @@ describe('mcp-server/tools/project/CreateTestAccountTool', () => {
|
|
|
126
209
|
absoluteCurrentWorkingDirectory: '/test/workspace',
|
|
127
210
|
name: 'MyTestAccount',
|
|
128
211
|
description: 'Test account for development',
|
|
212
|
+
marketingLevel: 'ENTERPRISE',
|
|
213
|
+
opsLevel: 'ENTERPRISE',
|
|
214
|
+
serviceLevel: 'ENTERPRISE',
|
|
215
|
+
salesLevel: 'ENTERPRISE',
|
|
216
|
+
contentLevel: 'ENTERPRISE',
|
|
129
217
|
};
|
|
130
218
|
await tool.handler(input);
|
|
131
219
|
expect(mockAddFlag).toHaveBeenCalledWith('hs test-account create', 'name', 'MyTestAccount');
|
|
@@ -139,9 +227,12 @@ describe('mcp-server/tools/project/CreateTestAccountTool', () => {
|
|
|
139
227
|
const input = {
|
|
140
228
|
absoluteCurrentWorkingDirectory: '/test/workspace',
|
|
141
229
|
name: 'MixedTierAccount',
|
|
230
|
+
description: 'Test account',
|
|
142
231
|
marketingLevel: 'PROFESSIONAL',
|
|
143
232
|
salesLevel: 'STARTER',
|
|
144
233
|
contentLevel: 'FREE',
|
|
234
|
+
serviceLevel: 'ENTERPRISE',
|
|
235
|
+
opsLevel: 'ENTERPRISE',
|
|
145
236
|
};
|
|
146
237
|
await tool.handler(input);
|
|
147
238
|
expect(mockAddFlag).toHaveBeenCalledWith('hs test-account create', 'name', 'MixedTierAccount');
|
|
@@ -174,10 +265,120 @@ describe('mcp-server/tools/project/CreateTestAccountTool', () => {
|
|
|
174
265
|
expect(mockAddFlag).toHaveBeenCalledWith(expect.any(String), 'content-level', 'PROFESSIONAL');
|
|
175
266
|
});
|
|
176
267
|
});
|
|
268
|
+
describe('handler defaults', () => {
|
|
269
|
+
it('should use ENTERPRISE defaults for all hub levels when not specified', async () => {
|
|
270
|
+
mockRunCommandInDir.mockResolvedValue({
|
|
271
|
+
stdout: 'Test account created',
|
|
272
|
+
stderr: '',
|
|
273
|
+
});
|
|
274
|
+
const input = {
|
|
275
|
+
absoluteCurrentWorkingDirectory: '/test/workspace',
|
|
276
|
+
name: 'DefaultLevelsAccount',
|
|
277
|
+
description: '',
|
|
278
|
+
marketingLevel: 'ENTERPRISE',
|
|
279
|
+
opsLevel: 'ENTERPRISE',
|
|
280
|
+
serviceLevel: 'ENTERPRISE',
|
|
281
|
+
salesLevel: 'ENTERPRISE',
|
|
282
|
+
contentLevel: 'ENTERPRISE',
|
|
283
|
+
};
|
|
284
|
+
await tool.handler(input);
|
|
285
|
+
expect(mockAddFlag).toHaveBeenCalledWith('hs test-account create', 'name', 'DefaultLevelsAccount');
|
|
286
|
+
expect(mockAddFlag).toHaveBeenCalledWith(expect.any(String), 'marketing-level', 'ENTERPRISE');
|
|
287
|
+
expect(mockAddFlag).toHaveBeenCalledWith(expect.any(String), 'ops-level', 'ENTERPRISE');
|
|
288
|
+
expect(mockAddFlag).toHaveBeenCalledWith(expect.any(String), 'service-level', 'ENTERPRISE');
|
|
289
|
+
expect(mockAddFlag).toHaveBeenCalledWith(expect.any(String), 'sales-level', 'ENTERPRISE');
|
|
290
|
+
expect(mockAddFlag).toHaveBeenCalledWith(expect.any(String), 'content-level', 'ENTERPRISE');
|
|
291
|
+
});
|
|
292
|
+
it('should use name as fallback for description when description is empty', async () => {
|
|
293
|
+
mockRunCommandInDir.mockResolvedValue({
|
|
294
|
+
stdout: 'Test account created',
|
|
295
|
+
stderr: '',
|
|
296
|
+
});
|
|
297
|
+
const input = {
|
|
298
|
+
absoluteCurrentWorkingDirectory: '/test/workspace',
|
|
299
|
+
name: 'NoDescriptionAccount',
|
|
300
|
+
description: '',
|
|
301
|
+
marketingLevel: 'ENTERPRISE',
|
|
302
|
+
opsLevel: 'ENTERPRISE',
|
|
303
|
+
serviceLevel: 'ENTERPRISE',
|
|
304
|
+
salesLevel: 'ENTERPRISE',
|
|
305
|
+
contentLevel: 'ENTERPRISE',
|
|
306
|
+
};
|
|
307
|
+
await tool.handler(input);
|
|
308
|
+
expect(mockAddFlag).toHaveBeenCalledWith('hs test-account create', 'name', 'NoDescriptionAccount');
|
|
309
|
+
// Implementation uses name as fallback for description
|
|
310
|
+
expect(mockAddFlag).toHaveBeenCalledWith(expect.any(String), 'description', 'NoDescriptionAccount');
|
|
311
|
+
});
|
|
312
|
+
it('should use defaults for some hub levels while respecting explicit values', async () => {
|
|
313
|
+
mockRunCommandInDir.mockResolvedValue({
|
|
314
|
+
stdout: 'Test account created',
|
|
315
|
+
stderr: '',
|
|
316
|
+
});
|
|
317
|
+
const input = {
|
|
318
|
+
absoluteCurrentWorkingDirectory: '/test/workspace',
|
|
319
|
+
name: 'PartialLevelsAccount',
|
|
320
|
+
description: '',
|
|
321
|
+
marketingLevel: 'FREE',
|
|
322
|
+
salesLevel: 'STARTER',
|
|
323
|
+
opsLevel: 'ENTERPRISE',
|
|
324
|
+
serviceLevel: 'ENTERPRISE',
|
|
325
|
+
contentLevel: 'ENTERPRISE',
|
|
326
|
+
};
|
|
327
|
+
await tool.handler(input);
|
|
328
|
+
expect(mockAddFlag).toHaveBeenCalledWith('hs test-account create', 'name', 'PartialLevelsAccount');
|
|
329
|
+
expect(mockAddFlag).toHaveBeenCalledWith(expect.any(String), 'marketing-level', 'FREE');
|
|
330
|
+
expect(mockAddFlag).toHaveBeenCalledWith(expect.any(String), 'sales-level', 'STARTER');
|
|
331
|
+
expect(mockAddFlag).toHaveBeenCalledWith(expect.any(String), 'ops-level', 'ENTERPRISE');
|
|
332
|
+
expect(mockAddFlag).toHaveBeenCalledWith(expect.any(String), 'service-level', 'ENTERPRISE');
|
|
333
|
+
expect(mockAddFlag).toHaveBeenCalledWith(expect.any(String), 'content-level', 'ENTERPRISE');
|
|
334
|
+
});
|
|
335
|
+
it('should add all hub level flags when defaults are applied', async () => {
|
|
336
|
+
mockRunCommandInDir.mockResolvedValue({
|
|
337
|
+
stdout: 'Test account created with defaults',
|
|
338
|
+
stderr: '',
|
|
339
|
+
});
|
|
340
|
+
const input = {
|
|
341
|
+
absoluteCurrentWorkingDirectory: '/test/workspace',
|
|
342
|
+
name: 'MinimalAccount',
|
|
343
|
+
description: '',
|
|
344
|
+
marketingLevel: 'ENTERPRISE',
|
|
345
|
+
opsLevel: 'ENTERPRISE',
|
|
346
|
+
serviceLevel: 'ENTERPRISE',
|
|
347
|
+
salesLevel: 'ENTERPRISE',
|
|
348
|
+
contentLevel: 'ENTERPRISE',
|
|
349
|
+
};
|
|
350
|
+
const result = await tool.handler(input);
|
|
351
|
+
expect(mockRunCommandInDir).toHaveBeenCalled();
|
|
352
|
+
expect(mockAddFlag).toHaveBeenCalledTimes(7);
|
|
353
|
+
expect(result.content[0]).toEqual({
|
|
354
|
+
type: 'text',
|
|
355
|
+
text: 'Test account created with defaults',
|
|
356
|
+
});
|
|
357
|
+
});
|
|
358
|
+
it('should use ENTERPRISE defaults when values are undefined', async () => {
|
|
359
|
+
mockRunCommandInDir.mockResolvedValue({
|
|
360
|
+
stdout: 'Test account created',
|
|
361
|
+
stderr: '',
|
|
362
|
+
});
|
|
363
|
+
const input = {
|
|
364
|
+
absoluteCurrentWorkingDirectory: '/test/workspace',
|
|
365
|
+
name: 'BypassedDefaultsAccount',
|
|
366
|
+
};
|
|
367
|
+
await tool.handler(input);
|
|
368
|
+
expect(mockAddFlag).toHaveBeenCalledWith('hs test-account create', 'name', 'BypassedDefaultsAccount');
|
|
369
|
+
expect(mockAddFlag).toHaveBeenCalledTimes(7);
|
|
370
|
+
});
|
|
371
|
+
});
|
|
177
372
|
describe('interactive mode', () => {
|
|
178
373
|
it('should ask for parameters when neither config nor name provided', async () => {
|
|
179
374
|
const input = {
|
|
180
375
|
absoluteCurrentWorkingDirectory: '/test/workspace',
|
|
376
|
+
description: 'Test account',
|
|
377
|
+
marketingLevel: 'ENTERPRISE',
|
|
378
|
+
opsLevel: 'ENTERPRISE',
|
|
379
|
+
serviceLevel: 'ENTERPRISE',
|
|
380
|
+
salesLevel: 'ENTERPRISE',
|
|
381
|
+
contentLevel: 'ENTERPRISE',
|
|
181
382
|
};
|
|
182
383
|
const result = await tool.handler(input);
|
|
183
384
|
// Should NOT run the command
|
|
@@ -202,6 +403,12 @@ describe('mcp-server/tools/project/CreateTestAccountTool', () => {
|
|
|
202
403
|
const input = {
|
|
203
404
|
absoluteCurrentWorkingDirectory: '/test/workspace',
|
|
204
405
|
configPath: './test-account.json',
|
|
406
|
+
description: 'Test account',
|
|
407
|
+
marketingLevel: 'ENTERPRISE',
|
|
408
|
+
opsLevel: 'ENTERPRISE',
|
|
409
|
+
serviceLevel: 'ENTERPRISE',
|
|
410
|
+
salesLevel: 'ENTERPRISE',
|
|
411
|
+
contentLevel: 'ENTERPRISE',
|
|
205
412
|
};
|
|
206
413
|
const result = await tool.handler(input);
|
|
207
414
|
expect(result).toEqual({
|
|
@@ -220,6 +427,12 @@ describe('mcp-server/tools/project/CreateTestAccountTool', () => {
|
|
|
220
427
|
const input = {
|
|
221
428
|
absoluteCurrentWorkingDirectory: '/test/workspace',
|
|
222
429
|
configPath: './test-account.json',
|
|
430
|
+
description: 'Test account',
|
|
431
|
+
marketingLevel: 'ENTERPRISE',
|
|
432
|
+
opsLevel: 'ENTERPRISE',
|
|
433
|
+
serviceLevel: 'ENTERPRISE',
|
|
434
|
+
salesLevel: 'ENTERPRISE',
|
|
435
|
+
contentLevel: 'ENTERPRISE',
|
|
223
436
|
};
|
|
224
437
|
const result = await tool.handler(input);
|
|
225
438
|
expect(result).toEqual({
|