@hubspot/cli 7.6.0-beta.9 → 7.6.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/api/__tests__/migrate.test.js +5 -5
- package/api/migrate.d.ts +4 -5
- package/api/migrate.js +2 -10
- package/commands/__tests__/getStarted.test.js +2 -2
- package/commands/__tests__/mcp.test.js +1 -1
- package/commands/__tests__/project.test.js +0 -3
- package/commands/app/__tests__/migrate.test.js +1 -1
- package/commands/app/migrate.js +4 -5
- package/commands/app/secret/add.js +2 -1
- package/commands/app/secret/delete.js +2 -1
- package/commands/app/secret/list.js +2 -1
- package/commands/app/secret/update.js +2 -1
- package/commands/app/secret.js +2 -1
- package/commands/app.js +2 -2
- package/commands/config/set.js +0 -1
- package/commands/getStarted.d.ts +0 -2
- package/commands/getStarted.js +72 -24
- package/commands/mcp/__tests__/setup.test.js +2 -2
- package/commands/mcp/setup.d.ts +0 -1
- package/commands/mcp/setup.js +14 -13
- package/commands/mcp.js +3 -3
- package/commands/project/__tests__/add.test.js +64 -0
- package/commands/project/__tests__/create.test.js +57 -0
- package/commands/project/__tests__/deploy.test.js +3 -5
- package/commands/project/__tests__/devUnifiedFlow.test.js +20 -11
- package/commands/project/__tests__/logs.test.js +0 -3
- package/commands/project/__tests__/migrate.test.js +1 -2
- package/commands/project/__tests__/migrateApp.test.js +1 -2
- package/commands/project/__tests__/profile.test.js +1 -1
- package/commands/project/add.d.ts +1 -1
- package/commands/project/add.js +4 -10
- package/commands/project/create.js +10 -11
- package/commands/project/deploy.js +11 -63
- package/commands/project/dev/deprecatedFlow.js +2 -1
- package/commands/project/dev/index.js +36 -15
- package/commands/project/dev/unifiedFlow.js +14 -10
- package/commands/project/download.js +1 -2
- package/commands/project/installDeps.js +1 -2
- package/commands/project/listBuilds.js +2 -2
- package/commands/project/logs.js +2 -2
- package/commands/project/migrate.js +41 -13
- package/commands/project/migrateApp.js +1 -2
- package/commands/project/open.js +1 -2
- package/commands/project/profile/add.js +3 -3
- package/commands/project/profile/delete.js +1 -2
- package/commands/project/profile.js +2 -3
- package/commands/project/upload.js +4 -4
- package/commands/project/validate.js +2 -2
- package/commands/project/watch.js +4 -4
- package/commands/project.js +1 -2
- package/commands/sandbox/delete.js +1 -1
- package/commands/testAccount/importData.d.ts +1 -1
- package/commands/testAccount/importData.js +1 -1
- package/commands/testAccount.js +1 -1
- package/lang/en.d.ts +104 -56
- package/lang/en.js +118 -68
- package/lang/en.lyaml +12 -12
- package/lib/__tests__/hasFeature.test.js +145 -7
- package/lib/__tests__/importData.test.js +1 -1
- package/lib/app/__tests__/migrate.test.js +26 -31
- package/lib/app/migrate.d.ts +3 -10
- package/lib/app/migrate.js +14 -25
- package/lib/constants.d.ts +9 -0
- package/lib/constants.js +9 -0
- package/lib/errorHandlers/index.d.ts +4 -0
- package/lib/errorHandlers/index.js +1 -1
- package/lib/hasFeature.js +6 -0
- package/lib/importData.js +1 -1
- package/lib/links.d.ts +1 -0
- package/lib/links.js +10 -3
- package/lib/mcp/setup.d.ts +0 -2
- package/lib/mcp/setup.js +4 -29
- package/lib/middleware/fireAlarmMiddleware.js +15 -5
- package/lib/projects/__tests__/AppDevModeInterface.test.js +72 -44
- package/lib/projects/__tests__/LocalDevProcess.test.js +228 -16
- package/lib/projects/__tests__/LocalDevWebsocketServer.test.js +16 -21
- package/lib/projects/__tests__/components.test.js +164 -7
- package/lib/projects/__tests__/deploy.test.js +229 -0
- package/lib/projects/__tests__/{localDevHelpers.test.js → localDevProjectHelpers.test.js} +5 -3
- package/lib/projects/__tests__/platformVersion.test.d.ts +1 -0
- package/lib/projects/__tests__/{buildAndDeploy.test.js → platformVersion.test.js} +2 -2
- package/lib/projects/add/__tests__/legacyAddComponent.test.js +49 -6
- package/lib/projects/add/__tests__/v3AddComponent.test.js +142 -8
- package/lib/projects/add/legacyAddComponent.d.ts +1 -1
- package/lib/projects/add/legacyAddComponent.js +5 -1
- package/lib/projects/add/v3AddComponent.d.ts +2 -1
- package/lib/projects/add/v3AddComponent.js +22 -5
- package/lib/projects/components.d.ts +1 -0
- package/lib/projects/components.js +27 -1
- package/lib/projects/create/__tests__/v3.test.js +174 -11
- package/lib/projects/create/index.js +2 -2
- package/lib/projects/create/legacy.js +1 -1
- package/lib/projects/create/v3.d.ts +2 -2
- package/lib/projects/create/v3.js +38 -13
- package/lib/projects/deploy.d.ts +13 -0
- package/lib/projects/deploy.js +63 -0
- package/lib/projects/localDev/AppDevModeInterface.d.ts +5 -3
- package/lib/projects/localDev/AppDevModeInterface.js +132 -48
- package/lib/projects/localDev/DevServerManagerV2.js +1 -0
- package/lib/projects/localDev/LocalDevLogger.d.ts +4 -0
- package/lib/projects/localDev/LocalDevLogger.js +22 -0
- package/lib/projects/localDev/LocalDevManager.js +1 -1
- package/lib/projects/localDev/LocalDevProcess.d.ts +7 -5
- package/lib/projects/localDev/LocalDevProcess.js +93 -20
- package/lib/projects/localDev/LocalDevState.d.ts +13 -9
- package/lib/projects/localDev/LocalDevState.js +26 -17
- package/lib/projects/localDev/LocalDevWebsocketServer.d.ts +2 -0
- package/lib/projects/localDev/LocalDevWebsocketServer.js +55 -23
- package/lib/projects/localDev/{helpers.d.ts → helpers/account.d.ts} +1 -14
- package/lib/projects/localDev/helpers/account.js +233 -0
- package/lib/projects/localDev/helpers/project.d.ts +12 -0
- package/lib/projects/localDev/helpers/project.js +176 -0
- package/lib/projects/localDev/localDevWebsocketServerUtils.d.ts +4 -0
- package/lib/projects/localDev/localDevWebsocketServerUtils.js +10 -0
- package/lib/projects/platformVersion.d.ts +1 -0
- package/lib/projects/platformVersion.js +10 -0
- package/lib/projects/{buildAndDeploy.d.ts → pollProjectBuildAndDeploy.d.ts} +0 -1
- package/lib/projects/{buildAndDeploy.js → pollProjectBuildAndDeploy.js} +4 -14
- package/lib/projects/upload.js +1 -1
- package/lib/projects/urls.d.ts +2 -0
- package/lib/projects/urls.js +7 -0
- package/lib/prompts/__tests__/projectAddPrompt.test.d.ts +1 -0
- package/lib/prompts/__tests__/projectAddPrompt.test.js +143 -0
- package/lib/prompts/__tests__/selectProjectTemplatePrompt.test.d.ts +1 -0
- package/lib/prompts/__tests__/selectProjectTemplatePrompt.test.js +160 -0
- package/lib/prompts/createDeveloperTestAccountConfigPrompt.js +1 -0
- package/lib/prompts/importDataFilePathPrompt.js +4 -2
- package/lib/prompts/installAppPrompt.d.ts +6 -1
- package/lib/prompts/installAppPrompt.js +6 -1
- package/lib/prompts/projectAddPrompt.js +3 -2
- package/lib/prompts/projectDevTargetAccountPrompt.js +1 -0
- package/lib/prompts/promptUtils.d.ts +7 -1
- package/lib/prompts/promptUtils.js +17 -1
- package/lib/prompts/selectProjectTemplatePrompt.js +3 -1
- package/lib/theme/__tests__/migrate.test.d.ts +1 -0
- package/lib/theme/__tests__/migrate.test.js +233 -0
- package/lib/theme/migrate.d.ts +13 -0
- package/lib/theme/migrate.js +90 -0
- package/lib/ui/index.js +3 -6
- package/lib/usageTracking.js +2 -2
- package/mcp-server/server.js +2 -1
- package/mcp-server/tools/cms/HsCreateFunctionTool.d.ts +32 -0
- package/mcp-server/tools/cms/HsCreateFunctionTool.js +96 -0
- package/mcp-server/tools/cms/HsCreateModuleTool.d.ts +38 -0
- package/mcp-server/tools/cms/HsCreateModuleTool.js +118 -0
- package/mcp-server/tools/cms/HsCreateTemplateTool.d.ts +26 -0
- package/mcp-server/tools/cms/HsCreateTemplateTool.js +75 -0
- package/mcp-server/tools/cms/HsFunctionLogsTool.d.ts +32 -0
- package/mcp-server/tools/cms/HsFunctionLogsTool.js +76 -0
- package/mcp-server/tools/cms/HsListFunctionsTool.d.ts +23 -0
- package/mcp-server/tools/cms/HsListFunctionsTool.js +58 -0
- package/mcp-server/tools/cms/HsListTool.d.ts +23 -0
- package/mcp-server/tools/cms/HsListTool.js +58 -0
- package/mcp-server/tools/cms/__tests__/HsCreateFunctionTool.test.d.ts +1 -0
- package/mcp-server/tools/cms/__tests__/HsCreateFunctionTool.test.js +251 -0
- package/mcp-server/tools/cms/__tests__/HsCreateModuleTool.test.d.ts +1 -0
- package/mcp-server/tools/cms/__tests__/HsCreateModuleTool.test.js +224 -0
- package/mcp-server/tools/cms/__tests__/HsCreateTemplateTool.test.d.ts +1 -0
- package/mcp-server/tools/cms/__tests__/HsCreateTemplateTool.test.js +206 -0
- package/mcp-server/tools/cms/__tests__/HsFunctionLogsTool.test.d.ts +1 -0
- package/mcp-server/tools/cms/__tests__/HsFunctionLogsTool.test.js +183 -0
- package/mcp-server/tools/cms/__tests__/HsListFunctionsTool.test.d.ts +1 -0
- package/mcp-server/tools/cms/__tests__/HsListFunctionsTool.test.js +120 -0
- package/mcp-server/tools/cms/__tests__/HsListTool.test.d.ts +1 -0
- package/mcp-server/tools/cms/__tests__/HsListTool.test.js +120 -0
- package/mcp-server/tools/index.d.ts +1 -0
- package/mcp-server/tools/index.js +16 -0
- package/mcp-server/tools/project/AddFeatureToProjectTool.d.ts +3 -3
- package/mcp-server/tools/project/AddFeatureToProjectTool.js +3 -3
- package/mcp-server/tools/project/CreateProjectTool.d.ts +3 -3
- package/mcp-server/tools/project/CreateProjectTool.js +5 -5
- package/mcp-server/tools/project/DeployProjectTool.js +1 -1
- package/mcp-server/tools/project/DocFetchTool.js +3 -3
- package/mcp-server/tools/project/DocsSearchTool.d.ts +4 -1
- package/mcp-server/tools/project/DocsSearchTool.js +8 -8
- package/mcp-server/tools/project/GetConfigValuesTool.d.ts +4 -1
- package/mcp-server/tools/project/GetConfigValuesTool.js +14 -8
- package/mcp-server/tools/project/GuidedWalkthroughTool.js +1 -1
- package/mcp-server/tools/project/UploadProjectTools.js +2 -2
- package/mcp-server/tools/project/ValidateProjectTool.js +1 -1
- package/mcp-server/tools/project/__tests__/AddFeatureToProjectTool.test.js +1 -1
- package/mcp-server/tools/project/__tests__/CreateProjectTool.test.js +1 -1
- package/mcp-server/tools/project/__tests__/DeployProjectTool.test.js +1 -1
- package/mcp-server/tools/project/__tests__/DocFetchTool.test.js +3 -3
- package/mcp-server/tools/project/__tests__/DocsSearchTool.test.js +15 -13
- package/mcp-server/tools/project/__tests__/GetConfigValuesTool.test.js +9 -8
- package/mcp-server/tools/project/__tests__/GuidedWalkthroughTool.test.js +1 -1
- package/mcp-server/tools/project/__tests__/UploadProjectTools.test.js +1 -1
- package/mcp-server/tools/project/__tests__/ValidateProjectTool.test.js +1 -1
- package/mcp-server/tools/project/constants.d.ts +1 -1
- package/mcp-server/tools/project/constants.js +14 -6
- package/mcp-server/utils/__tests__/cliConfig.test.d.ts +1 -0
- package/mcp-server/utils/__tests__/cliConfig.test.js +110 -0
- package/mcp-server/utils/cliConfig.d.ts +1 -0
- package/mcp-server/utils/cliConfig.js +12 -0
- package/package.json +5 -4
- package/types/LocalDev.d.ts +21 -4
- package/types/Projects.d.ts +1 -0
- package/types/Prompts.d.ts +1 -0
- package/ui/components/BoxWithTitle.d.ts +8 -0
- package/ui/components/BoxWithTitle.js +9 -0
- package/ui/components/HorizontalSelectPrompt.d.ts +8 -0
- package/ui/components/HorizontalSelectPrompt.js +30 -0
- package/ui/components/StatusMessageBoxes.d.ts +12 -0
- package/ui/components/StatusMessageBoxes.js +31 -0
- package/ui/index.js +1 -1
- package/ui/lib/ui-testing-utils.d.ts +9 -0
- package/ui/lib/ui-testing-utils.js +47 -0
- package/ui/lib/useTerminalSize.d.ts +13 -0
- package/ui/lib/useTerminalSize.js +31 -0
- package/ui/styles.d.ts +18 -0
- package/ui/styles.js +18 -0
- package/ui/views/UiSandbox.d.ts +5 -0
- package/ui/views/UiSandbox.js +25 -0
- package/lib/projects/localDev/helpers.js +0 -388
- /package/lib/projects/__tests__/{buildAndDeploy.test.d.ts → deploy.test.d.ts} +0 -0
- /package/lib/projects/__tests__/{localDevHelpers.test.d.ts → localDevProjectHelpers.test.d.ts} +0 -0
|
@@ -1,7 +1,29 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
|
-
import { handleComponentCollision } from '../components.js';
|
|
2
|
+
import { handleComponentCollision, updateHsMetaFilesWithAutoGeneratedFields, } from '../components.js';
|
|
3
|
+
import { uiLogger } from '../../ui/logger.js';
|
|
4
|
+
import { coerceToValidUid } from '@hubspot/project-parsing-lib';
|
|
3
5
|
vi.mock('fs');
|
|
6
|
+
vi.mock('../../ui/logger.js');
|
|
7
|
+
vi.mock('@hubspot/project-parsing-lib', () => ({
|
|
8
|
+
coerceToValidUid: vi.fn(),
|
|
9
|
+
metafileExtension: '.module.meta.json',
|
|
10
|
+
}));
|
|
11
|
+
vi.mock('@hubspot/project-parsing-lib/src/lib/constants.js', () => ({
|
|
12
|
+
AppKey: 'app',
|
|
13
|
+
}));
|
|
14
|
+
vi.mock('../../../lang/en.js', () => ({
|
|
15
|
+
lib: {
|
|
16
|
+
projects: {
|
|
17
|
+
updateHsMetaFilesWithAutoGeneratedFields: {
|
|
18
|
+
header: 'Updating component metadata files...',
|
|
19
|
+
applicationLog: (type, uid, name) => `Updated ${type} component with uid: ${uid} and name: ${name}`,
|
|
20
|
+
componentLog: (type, uid) => `Updated ${type} component with uid: ${uid}`,
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
}));
|
|
4
25
|
const mockedFs = vi.mocked(fs);
|
|
26
|
+
const mockCoerceToValidUid = vi.mocked(coerceToValidUid);
|
|
5
27
|
describe('lib/projects/components', () => {
|
|
6
28
|
describe('handleComponentCollision()', () => {
|
|
7
29
|
const mockCollision = {
|
|
@@ -152,10 +174,9 @@ describe('lib/projects/components', () => {
|
|
|
152
174
|
collisions: [
|
|
153
175
|
'regular.js',
|
|
154
176
|
'nested/path/file.ts',
|
|
155
|
-
'component.
|
|
177
|
+
'component.meta.json',
|
|
156
178
|
'another.meta.json',
|
|
157
179
|
'package.json',
|
|
158
|
-
'nested/package.json',
|
|
159
180
|
],
|
|
160
181
|
};
|
|
161
182
|
// Mock metafileExtension
|
|
@@ -166,16 +187,152 @@ describe('lib/projects/components', () => {
|
|
|
166
187
|
const mockMetaContent = '{}';
|
|
167
188
|
mockedFs.readFileSync.mockReturnValue(mockMetaContent);
|
|
168
189
|
mockedFs.writeFileSync.mockImplementation(() => { });
|
|
190
|
+
// Track what files are being copied to debug the issue
|
|
169
191
|
mockedFs.copyFileSync.mockImplementation(() => { });
|
|
170
192
|
// Mock console.log for package.json handling
|
|
171
193
|
const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => { });
|
|
172
194
|
handleComponentCollision(collision);
|
|
173
|
-
|
|
174
|
-
expect(mockedFs.copyFileSync).toHaveBeenCalledTimes(2);
|
|
195
|
+
expect(mockedFs.readFileSync).toHaveBeenCalledTimes(2);
|
|
175
196
|
// Should handle 2 metafiles
|
|
176
|
-
expect(mockedFs.readFileSync).toHaveBeenCalledWith('/
|
|
177
|
-
expect(mockedFs.readFileSync).toHaveBeenCalledWith('/src/path/
|
|
197
|
+
expect(mockedFs.readFileSync).toHaveBeenCalledWith('/dest/path/package.json', 'utf-8');
|
|
198
|
+
expect(mockedFs.readFileSync).toHaveBeenCalledWith('/src/path/package.json', 'utf-8');
|
|
178
199
|
consoleSpy.mockRestore();
|
|
179
200
|
});
|
|
180
201
|
});
|
|
202
|
+
describe('updateHsMetaFilesWithAutoGeneratedFields()', () => {
|
|
203
|
+
const mockUiLogger = vi.mocked(uiLogger);
|
|
204
|
+
beforeEach(() => {
|
|
205
|
+
vi.resetAllMocks();
|
|
206
|
+
mockCoerceToValidUid.mockImplementation((input) => input);
|
|
207
|
+
});
|
|
208
|
+
afterEach(() => {
|
|
209
|
+
vi.restoreAllMocks();
|
|
210
|
+
});
|
|
211
|
+
it('updates component metadata files with project-specific UIDs', () => {
|
|
212
|
+
const projectName = 'my-project';
|
|
213
|
+
const hsMetaFilePaths = [
|
|
214
|
+
'/path/to/component1.meta.json',
|
|
215
|
+
'/path/to/component2.meta.json',
|
|
216
|
+
];
|
|
217
|
+
const component1 = {
|
|
218
|
+
type: 'card',
|
|
219
|
+
uid: 'old-uid-1',
|
|
220
|
+
config: {
|
|
221
|
+
name: 'Old Name',
|
|
222
|
+
},
|
|
223
|
+
};
|
|
224
|
+
const component2 = {
|
|
225
|
+
type: 'function',
|
|
226
|
+
uid: 'old-uid-2',
|
|
227
|
+
};
|
|
228
|
+
mockedFs.readFileSync
|
|
229
|
+
.mockReturnValueOnce(JSON.stringify(component1))
|
|
230
|
+
.mockReturnValueOnce(JSON.stringify(component2));
|
|
231
|
+
mockedFs.writeFileSync.mockImplementation(() => { });
|
|
232
|
+
mockCoerceToValidUid
|
|
233
|
+
.mockReturnValueOnce('card-my-project')
|
|
234
|
+
.mockReturnValueOnce('function-my-project');
|
|
235
|
+
updateHsMetaFilesWithAutoGeneratedFields(projectName, hsMetaFilePaths);
|
|
236
|
+
expect(mockedFs.writeFileSync).toHaveBeenCalledWith('/path/to/component1.meta.json', JSON.stringify({
|
|
237
|
+
type: 'card',
|
|
238
|
+
uid: 'card-my-project',
|
|
239
|
+
config: {
|
|
240
|
+
name: 'Old Name',
|
|
241
|
+
},
|
|
242
|
+
}, null, 2));
|
|
243
|
+
expect(mockedFs.writeFileSync).toHaveBeenCalledWith('/path/to/component2.meta.json', JSON.stringify({
|
|
244
|
+
type: 'function',
|
|
245
|
+
uid: 'function-my-project',
|
|
246
|
+
}, null, 2));
|
|
247
|
+
expect(mockUiLogger.log).toHaveBeenCalledWith('Updating component metadata files...');
|
|
248
|
+
expect(mockUiLogger.log).toHaveBeenCalledWith('Updated card component with uid: card-my-project');
|
|
249
|
+
expect(mockUiLogger.log).toHaveBeenCalledWith('Updated function component with uid: function-my-project');
|
|
250
|
+
});
|
|
251
|
+
it('handles app components by updating both uid and config.name', () => {
|
|
252
|
+
const projectName = 'test-app';
|
|
253
|
+
const hsMetaFilePaths = ['/path/to/app.meta.json'];
|
|
254
|
+
const appComponent = {
|
|
255
|
+
type: 'app',
|
|
256
|
+
uid: 'old-app-uid',
|
|
257
|
+
config: {
|
|
258
|
+
name: 'Old App Name',
|
|
259
|
+
other: 'property',
|
|
260
|
+
},
|
|
261
|
+
};
|
|
262
|
+
mockedFs.readFileSync.mockReturnValue(JSON.stringify(appComponent));
|
|
263
|
+
mockedFs.writeFileSync.mockImplementation(() => { });
|
|
264
|
+
mockCoerceToValidUid.mockReturnValue('app-test-app');
|
|
265
|
+
updateHsMetaFilesWithAutoGeneratedFields(projectName, hsMetaFilePaths);
|
|
266
|
+
expect(mockedFs.writeFileSync).toHaveBeenCalledWith('/path/to/app.meta.json', JSON.stringify({
|
|
267
|
+
type: 'app',
|
|
268
|
+
uid: 'app-test-app',
|
|
269
|
+
config: {
|
|
270
|
+
name: 'test-app-Application',
|
|
271
|
+
other: 'property',
|
|
272
|
+
},
|
|
273
|
+
}, null, 2));
|
|
274
|
+
expect(mockUiLogger.log).toHaveBeenCalledWith('Updated app component with uid: app-test-app and name: test-app-Application');
|
|
275
|
+
});
|
|
276
|
+
it('handles UID collisions by using timestamps', () => {
|
|
277
|
+
const projectName = 'collision-project';
|
|
278
|
+
const hsMetaFilePaths = ['/path/to/component1.meta.json'];
|
|
279
|
+
const existingUids = ['card-collision-project'];
|
|
280
|
+
const component1 = { type: 'card', uid: 'old-uid-1' };
|
|
281
|
+
mockedFs.readFileSync.mockReturnValue(JSON.stringify(component1));
|
|
282
|
+
mockedFs.writeFileSync.mockImplementation(() => { });
|
|
283
|
+
// Mock Date.now to return consistent value for testing
|
|
284
|
+
vi.spyOn(Date, 'now').mockReturnValue(1234567890);
|
|
285
|
+
mockCoerceToValidUid
|
|
286
|
+
.mockReturnValueOnce('card-collision-project')
|
|
287
|
+
.mockReturnValueOnce('card-1234567890-collision-project');
|
|
288
|
+
updateHsMetaFilesWithAutoGeneratedFields(projectName, hsMetaFilePaths, existingUids);
|
|
289
|
+
expect(mockedFs.writeFileSync).toHaveBeenCalledWith('/path/to/component1.meta.json', JSON.stringify({
|
|
290
|
+
type: 'card',
|
|
291
|
+
uid: 'card-1234567890-collision-project',
|
|
292
|
+
}, null, 2));
|
|
293
|
+
});
|
|
294
|
+
it('falls back to original uid when coerceToValidUid returns null', () => {
|
|
295
|
+
const projectName = 'fallback-project';
|
|
296
|
+
const hsMetaFilePaths = ['/path/to/component.meta.json'];
|
|
297
|
+
const component = {
|
|
298
|
+
type: 'card',
|
|
299
|
+
uid: 'original-uid',
|
|
300
|
+
};
|
|
301
|
+
mockedFs.readFileSync.mockReturnValue(JSON.stringify(component));
|
|
302
|
+
mockedFs.writeFileSync.mockImplementation(() => { });
|
|
303
|
+
mockCoerceToValidUid.mockReturnValue(undefined);
|
|
304
|
+
updateHsMetaFilesWithAutoGeneratedFields(projectName, hsMetaFilePaths);
|
|
305
|
+
expect(mockedFs.writeFileSync).toHaveBeenCalledWith('/path/to/component.meta.json', JSON.stringify({
|
|
306
|
+
type: 'card',
|
|
307
|
+
uid: 'original-uid',
|
|
308
|
+
}, null, 2));
|
|
309
|
+
});
|
|
310
|
+
it('handles empty hsMetaFilePaths array', () => {
|
|
311
|
+
const projectName = 'empty-project';
|
|
312
|
+
const hsMetaFilePaths = [];
|
|
313
|
+
updateHsMetaFilesWithAutoGeneratedFields(projectName, hsMetaFilePaths);
|
|
314
|
+
expect(mockedFs.readFileSync).not.toHaveBeenCalled();
|
|
315
|
+
expect(mockedFs.writeFileSync).not.toHaveBeenCalled();
|
|
316
|
+
expect(mockUiLogger.log).toHaveBeenCalledWith('Updating component metadata files...');
|
|
317
|
+
expect(mockUiLogger.log).toHaveBeenCalledWith('');
|
|
318
|
+
});
|
|
319
|
+
it('handles components without config property for app type', () => {
|
|
320
|
+
const projectName = 'no-config-project';
|
|
321
|
+
const hsMetaFilePaths = ['/path/to/app.meta.json'];
|
|
322
|
+
const appComponent = {
|
|
323
|
+
type: 'app',
|
|
324
|
+
uid: 'app-uid',
|
|
325
|
+
// No config property
|
|
326
|
+
};
|
|
327
|
+
mockedFs.readFileSync.mockReturnValue(JSON.stringify(appComponent));
|
|
328
|
+
mockedFs.writeFileSync.mockImplementation(() => { });
|
|
329
|
+
mockCoerceToValidUid.mockReturnValue('app-no-config-project');
|
|
330
|
+
updateHsMetaFilesWithAutoGeneratedFields(projectName, hsMetaFilePaths);
|
|
331
|
+
expect(mockedFs.writeFileSync).toHaveBeenCalledWith('/path/to/app.meta.json', JSON.stringify({
|
|
332
|
+
type: 'app',
|
|
333
|
+
uid: 'app-no-config-project',
|
|
334
|
+
}, null, 2));
|
|
335
|
+
expect(mockUiLogger.log).toHaveBeenCalledWith('Updated app component with uid: app-no-config-project');
|
|
336
|
+
});
|
|
337
|
+
});
|
|
181
338
|
});
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import { vi } from 'vitest';
|
|
2
|
+
import { validateBuildIdForDeploy, logDeployErrors, handleProjectDeploy, } from '../deploy.js';
|
|
3
|
+
import { uiLogger } from '../../ui/logger.js';
|
|
4
|
+
import { commands } from '../../../lang/en.js';
|
|
5
|
+
import { PROJECT_ERROR_TYPES } from '../../constants.js';
|
|
6
|
+
import { deployProject } from '@hubspot/local-dev-lib/api/projects';
|
|
7
|
+
import { pollDeployStatus } from '../pollProjectBuildAndDeploy.js';
|
|
8
|
+
// Mock external dependencies
|
|
9
|
+
vi.mock('../../ui/logger.js');
|
|
10
|
+
vi.mock('@hubspot/local-dev-lib/api/projects');
|
|
11
|
+
vi.mock('../pollProjectBuildAndDeploy.js');
|
|
12
|
+
const mockUiLogger = vi.mocked(uiLogger);
|
|
13
|
+
const mockDeployProject = vi.mocked(deployProject);
|
|
14
|
+
const mockPollDeployStatus = vi.mocked(pollDeployStatus);
|
|
15
|
+
describe('lib/projects/deploy', () => {
|
|
16
|
+
beforeEach(() => {
|
|
17
|
+
vi.resetAllMocks();
|
|
18
|
+
});
|
|
19
|
+
describe('validateBuildIdForDeploy()', () => {
|
|
20
|
+
const accountId = 12345;
|
|
21
|
+
const projectName = 'test-project';
|
|
22
|
+
it('returns true when build ID is valid for deployment', () => {
|
|
23
|
+
const buildId = 5;
|
|
24
|
+
const deployedBuildId = 3;
|
|
25
|
+
const latestBuildId = 10;
|
|
26
|
+
const result = validateBuildIdForDeploy(buildId, deployedBuildId, latestBuildId, projectName, accountId);
|
|
27
|
+
expect(result).toBe(true);
|
|
28
|
+
});
|
|
29
|
+
it('returns error message when build ID does not exist', () => {
|
|
30
|
+
const buildId = 15;
|
|
31
|
+
const deployedBuildId = 3;
|
|
32
|
+
const latestBuildId = 10;
|
|
33
|
+
const result = validateBuildIdForDeploy(buildId, deployedBuildId, latestBuildId, projectName, accountId);
|
|
34
|
+
expect(result).toBe(commands.project.deploy.errors.buildIdDoesNotExist(accountId, buildId, projectName));
|
|
35
|
+
});
|
|
36
|
+
it('returns error message when build is already deployed', () => {
|
|
37
|
+
const buildId = 3;
|
|
38
|
+
const deployedBuildId = 3;
|
|
39
|
+
const latestBuildId = 10;
|
|
40
|
+
const result = validateBuildIdForDeploy(buildId, deployedBuildId, latestBuildId, projectName, accountId);
|
|
41
|
+
expect(result).toBe(commands.project.deploy.errors.buildAlreadyDeployed(accountId, buildId, projectName));
|
|
42
|
+
});
|
|
43
|
+
it('handles edge case when deployedBuildId is undefined', () => {
|
|
44
|
+
const buildId = 5;
|
|
45
|
+
const deployedBuildId = undefined;
|
|
46
|
+
const latestBuildId = 10;
|
|
47
|
+
const result = validateBuildIdForDeploy(buildId, deployedBuildId, latestBuildId, projectName, accountId);
|
|
48
|
+
expect(result).toBe(true);
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
describe('logDeployErrors()', () => {
|
|
52
|
+
it('logs main error message and individual error messages', () => {
|
|
53
|
+
const errorData = {
|
|
54
|
+
message: 'Deploy failed with errors',
|
|
55
|
+
errors: [
|
|
56
|
+
{
|
|
57
|
+
message: 'Component error 1',
|
|
58
|
+
subCategory: 'SOME_ERROR',
|
|
59
|
+
context: { COMPONENT_NAME: 'test-component' },
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
message: 'Component error 2',
|
|
63
|
+
subCategory: 'ANOTHER_ERROR',
|
|
64
|
+
context: { COMPONENT_NAME: 'another-component' },
|
|
65
|
+
},
|
|
66
|
+
],
|
|
67
|
+
};
|
|
68
|
+
logDeployErrors(errorData);
|
|
69
|
+
expect(mockUiLogger.error).toHaveBeenCalledWith('Deploy failed with errors');
|
|
70
|
+
expect(mockUiLogger.log).toHaveBeenCalledWith('Component error 1');
|
|
71
|
+
expect(mockUiLogger.log).toHaveBeenCalledWith('Component error 2');
|
|
72
|
+
});
|
|
73
|
+
it('handles DEPLOY_CONTAINS_REMOVALS error type specially', () => {
|
|
74
|
+
const errorData = {
|
|
75
|
+
message: 'Deploy contains removals',
|
|
76
|
+
errors: [
|
|
77
|
+
{
|
|
78
|
+
message: 'Component will be removed',
|
|
79
|
+
subCategory: PROJECT_ERROR_TYPES.DEPLOY_CONTAINS_REMOVALS,
|
|
80
|
+
context: { COMPONENT_NAME: 'removed-component' },
|
|
81
|
+
},
|
|
82
|
+
],
|
|
83
|
+
};
|
|
84
|
+
logDeployErrors(errorData);
|
|
85
|
+
expect(mockUiLogger.error).toHaveBeenCalledWith('Deploy contains removals');
|
|
86
|
+
expect(mockUiLogger.log).toHaveBeenCalledWith(commands.project.deploy.errors.deployContainsRemovals('removed-component'));
|
|
87
|
+
});
|
|
88
|
+
it('handles empty errors array', () => {
|
|
89
|
+
const errorData = {
|
|
90
|
+
message: 'No specific errors',
|
|
91
|
+
errors: [],
|
|
92
|
+
};
|
|
93
|
+
logDeployErrors(errorData);
|
|
94
|
+
expect(mockUiLogger.error).toHaveBeenCalledWith('No specific errors');
|
|
95
|
+
expect(mockUiLogger.log).not.toHaveBeenCalled();
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
describe('handleProjectDeploy()', () => {
|
|
99
|
+
const targetAccountId = 12345;
|
|
100
|
+
const projectName = 'test-project';
|
|
101
|
+
const buildId = 5;
|
|
102
|
+
const useV3Api = true;
|
|
103
|
+
const force = false;
|
|
104
|
+
it('successfully deploys and returns deploy result', async () => {
|
|
105
|
+
const mockDeployResponseData = {
|
|
106
|
+
id: 'deploy-123',
|
|
107
|
+
buildResultType: 'DEPLOY_QUEUED',
|
|
108
|
+
links: {
|
|
109
|
+
status: 'http://status-url',
|
|
110
|
+
},
|
|
111
|
+
};
|
|
112
|
+
const mockDeployResult = {
|
|
113
|
+
deployId: 123,
|
|
114
|
+
buildId: 5,
|
|
115
|
+
status: 'SUCCESS',
|
|
116
|
+
enqueuedAt: '2023-01-01T00:00:00Z',
|
|
117
|
+
startedAt: '2023-01-01T00:01:00Z',
|
|
118
|
+
finishedAt: '2023-01-01T00:05:00Z',
|
|
119
|
+
portalId: targetAccountId,
|
|
120
|
+
projectName: 'test-project',
|
|
121
|
+
userId: 456,
|
|
122
|
+
source: 'HUBSPOT_USER',
|
|
123
|
+
subdeployStatuses: [],
|
|
124
|
+
};
|
|
125
|
+
mockDeployProject.mockResolvedValue({
|
|
126
|
+
data: mockDeployResponseData,
|
|
127
|
+
});
|
|
128
|
+
mockPollDeployStatus.mockResolvedValue(mockDeployResult);
|
|
129
|
+
const deploy = await handleProjectDeploy(targetAccountId, projectName, buildId, useV3Api, force);
|
|
130
|
+
expect(mockDeployProject).toHaveBeenCalledWith(targetAccountId, projectName, buildId, useV3Api, force);
|
|
131
|
+
expect(deploy).toEqual(mockDeployResult);
|
|
132
|
+
});
|
|
133
|
+
it('handles blocked deploy with warnings', async () => {
|
|
134
|
+
const mockBlockedResponse = {
|
|
135
|
+
buildResultType: 'DEPLOY_BLOCKED',
|
|
136
|
+
issues: [
|
|
137
|
+
{
|
|
138
|
+
uid: 'component-1',
|
|
139
|
+
componentTypeName: 'module',
|
|
140
|
+
errorMessages: [],
|
|
141
|
+
blockingMessages: [
|
|
142
|
+
{
|
|
143
|
+
message: 'This is a warning',
|
|
144
|
+
isWarning: true,
|
|
145
|
+
},
|
|
146
|
+
],
|
|
147
|
+
},
|
|
148
|
+
],
|
|
149
|
+
};
|
|
150
|
+
mockDeployProject.mockResolvedValue({
|
|
151
|
+
data: mockBlockedResponse,
|
|
152
|
+
});
|
|
153
|
+
await handleProjectDeploy(targetAccountId, projectName, buildId, useV3Api, force);
|
|
154
|
+
expect(mockUiLogger.warn).toHaveBeenCalledWith(commands.project.deploy.errors.deployWarningsHeader);
|
|
155
|
+
});
|
|
156
|
+
it('handles blocked deploy with errors (cannot be forced)', async () => {
|
|
157
|
+
const mockBlockedResponse = {
|
|
158
|
+
buildResultType: 'DEPLOY_BLOCKED',
|
|
159
|
+
issues: [
|
|
160
|
+
{
|
|
161
|
+
uid: 'component-1',
|
|
162
|
+
componentTypeName: 'module',
|
|
163
|
+
errorMessages: [],
|
|
164
|
+
blockingMessages: [
|
|
165
|
+
{
|
|
166
|
+
message: 'This is an error',
|
|
167
|
+
isWarning: false,
|
|
168
|
+
},
|
|
169
|
+
],
|
|
170
|
+
},
|
|
171
|
+
],
|
|
172
|
+
};
|
|
173
|
+
mockDeployProject.mockResolvedValue({
|
|
174
|
+
data: mockBlockedResponse,
|
|
175
|
+
});
|
|
176
|
+
await handleProjectDeploy(targetAccountId, projectName, buildId, useV3Api, force);
|
|
177
|
+
expect(mockUiLogger.error).toHaveBeenCalledWith(commands.project.deploy.errors.deployBlockedHeader);
|
|
178
|
+
expect(mockUiLogger.log).toHaveBeenCalledWith(commands.project.deploy.errors.deployIssueComponentWarning('component-1', 'module', 'This is an error'));
|
|
179
|
+
});
|
|
180
|
+
it('handles blocked deploy with no blocking messages', async () => {
|
|
181
|
+
const mockBlockedResponse = {
|
|
182
|
+
buildResultType: 'DEPLOY_BLOCKED',
|
|
183
|
+
issues: [
|
|
184
|
+
{
|
|
185
|
+
uid: 'component-1',
|
|
186
|
+
componentTypeName: 'module',
|
|
187
|
+
errorMessages: [],
|
|
188
|
+
blockingMessages: [],
|
|
189
|
+
},
|
|
190
|
+
],
|
|
191
|
+
};
|
|
192
|
+
mockDeployProject.mockResolvedValue({
|
|
193
|
+
data: mockBlockedResponse,
|
|
194
|
+
});
|
|
195
|
+
await handleProjectDeploy(targetAccountId, projectName, buildId, useV3Api, force);
|
|
196
|
+
expect(mockUiLogger.warn).toHaveBeenCalledWith(commands.project.deploy.errors.deployWarningsHeader);
|
|
197
|
+
expect(mockUiLogger.log).toHaveBeenCalledWith(commands.project.deploy.errors.deployIssueComponentGeneric('component-1', 'module'));
|
|
198
|
+
});
|
|
199
|
+
it('handles general deploy failure', async () => {
|
|
200
|
+
mockDeployProject.mockResolvedValue({ data: null });
|
|
201
|
+
const deploy = await handleProjectDeploy(targetAccountId, projectName, buildId, useV3Api, force);
|
|
202
|
+
expect(mockUiLogger.error).toHaveBeenCalledWith(commands.project.deploy.errors.deploy);
|
|
203
|
+
expect(deploy).toBeUndefined();
|
|
204
|
+
});
|
|
205
|
+
it('handles undefined deploy response', async () => {
|
|
206
|
+
mockDeployProject.mockResolvedValue({ data: undefined });
|
|
207
|
+
const deploy = await handleProjectDeploy(targetAccountId, projectName, buildId, useV3Api, force);
|
|
208
|
+
expect(mockUiLogger.error).toHaveBeenCalledWith(commands.project.deploy.errors.deploy);
|
|
209
|
+
expect(deploy).toBeUndefined();
|
|
210
|
+
});
|
|
211
|
+
it('passes correct parameters to deployProject', async () => {
|
|
212
|
+
const mockDeployResponseData = {
|
|
213
|
+
id: 'deploy-123',
|
|
214
|
+
buildResultType: 'DEPLOY_QUEUED',
|
|
215
|
+
links: {
|
|
216
|
+
status: 'http://status-url',
|
|
217
|
+
},
|
|
218
|
+
};
|
|
219
|
+
mockDeployProject.mockResolvedValue({
|
|
220
|
+
data: mockDeployResponseData,
|
|
221
|
+
});
|
|
222
|
+
mockPollDeployStatus.mockResolvedValue({});
|
|
223
|
+
await handleProjectDeploy(targetAccountId, projectName, buildId, false, true);
|
|
224
|
+
expect(mockDeployProject).toHaveBeenCalledWith(targetAccountId, projectName, buildId, false, // useV3Api
|
|
225
|
+
true // force
|
|
226
|
+
);
|
|
227
|
+
});
|
|
228
|
+
});
|
|
229
|
+
});
|
|
@@ -5,7 +5,7 @@ import { downloadProject } from '@hubspot/local-dev-lib/api/projects';
|
|
|
5
5
|
import { extractZipArchive } from '@hubspot/local-dev-lib/archive';
|
|
6
6
|
import { isDeepEqual } from '@hubspot/local-dev-lib/isDeepEqual';
|
|
7
7
|
import { translate } from '@hubspot/project-parsing-lib';
|
|
8
|
-
import { isDeployedProjectUpToDateWithLocal } from '../localDev/helpers.js';
|
|
8
|
+
import { isDeployedProjectUpToDateWithLocal } from '../localDev/helpers/project.js';
|
|
9
9
|
// Mock all external dependencies
|
|
10
10
|
vi.mock('@hubspot/local-dev-lib/api/projects');
|
|
11
11
|
vi.mock('@hubspot/local-dev-lib/archive');
|
|
@@ -99,7 +99,8 @@ describe('isDeployedProjectUpToDateWithLocal', () => {
|
|
|
99
99
|
it('should clean up temp directory even when errors occur', async () => {
|
|
100
100
|
// Mock downloadProject to throw an error after temp dir is created
|
|
101
101
|
downloadProject.mockRejectedValue(new Error('Download Error'));
|
|
102
|
-
await
|
|
102
|
+
const result = await isDeployedProjectUpToDateWithLocal(mockProjectConfig, mockAccountId, mockBuildId, mockLocalProjectNodes);
|
|
103
|
+
expect(result).toBe(false);
|
|
103
104
|
expect(fs.remove).toHaveBeenCalledWith(mockTempDir);
|
|
104
105
|
});
|
|
105
106
|
it('should handle translateForLocalDev errors', async () => {
|
|
@@ -111,7 +112,8 @@ describe('isDeployedProjectUpToDateWithLocal', () => {
|
|
|
111
112
|
extractZipArchive.mockResolvedValue(undefined);
|
|
112
113
|
// Mock translate to throw an error
|
|
113
114
|
translate.mockRejectedValue(new Error('Translation Error'));
|
|
114
|
-
await
|
|
115
|
+
const result = await isDeployedProjectUpToDateWithLocal(mockProjectConfig, mockAccountId, mockBuildId, mockLocalProjectNodes);
|
|
116
|
+
expect(result).toBe(false);
|
|
115
117
|
expect(fs.remove).toHaveBeenCalledWith(mockTempDir);
|
|
116
118
|
});
|
|
117
119
|
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { useV3Api } from '../
|
|
2
|
-
describe('
|
|
1
|
+
import { useV3Api } from '../platformVersion.js';
|
|
2
|
+
describe('platformVersion', () => {
|
|
3
3
|
describe('useV3Api', () => {
|
|
4
4
|
it('returns true if platform version is UNSTABLE', () => {
|
|
5
5
|
expect(useV3Api('UNSTABLE')).toBe(true);
|
|
@@ -4,6 +4,7 @@ import { getProjectComponentListFromRepo } from '../../create/legacy.js';
|
|
|
4
4
|
import { projectAddPrompt } from '../../../prompts/projectAddPrompt.js';
|
|
5
5
|
import { logger } from '@hubspot/local-dev-lib/logger';
|
|
6
6
|
import { cloneGithubRepo } from '@hubspot/local-dev-lib/github';
|
|
7
|
+
import { trackCommandUsage } from '../../../usageTracking.js';
|
|
7
8
|
import { ComponentTypes, } from '../../../../types/Projects.js';
|
|
8
9
|
import { commands } from '../../../../lang/en.js';
|
|
9
10
|
vi.mock('../../structure');
|
|
@@ -11,21 +12,25 @@ vi.mock('../../create/legacy');
|
|
|
11
12
|
vi.mock('../../../prompts/projectAddPrompt');
|
|
12
13
|
vi.mock('@hubspot/local-dev-lib/logger');
|
|
13
14
|
vi.mock('@hubspot/local-dev-lib/github');
|
|
15
|
+
vi.mock('../../../usageTracking.js');
|
|
14
16
|
const mockedFindProjectComponents = vi.mocked(findProjectComponents);
|
|
15
17
|
const mockedGetProjectComponentListFromRepo = vi.mocked(getProjectComponentListFromRepo);
|
|
16
18
|
const mockedProjectAddPrompt = vi.mocked(projectAddPrompt);
|
|
17
19
|
const mockedLogger = vi.mocked(logger);
|
|
18
20
|
const mockedCloneGithubRepo = vi.mocked(cloneGithubRepo);
|
|
21
|
+
const mockedTrackCommandUsage = vi.mocked(trackCommandUsage);
|
|
19
22
|
describe('lib/projects/add/legacyAddComponent', () => {
|
|
20
23
|
const mockProjectConfig = {
|
|
21
24
|
name: 'test-project',
|
|
22
25
|
srcDir: 'src',
|
|
23
26
|
platformVersion: 'v1',
|
|
24
27
|
};
|
|
28
|
+
const accountId = 1234567890;
|
|
25
29
|
const mockArgs = { name: 'test-component', type: 'module' };
|
|
26
30
|
const projectDir = '/path/to/project';
|
|
27
31
|
beforeEach(() => {
|
|
28
32
|
vi.resetAllMocks();
|
|
33
|
+
mockedTrackCommandUsage.mockResolvedValue();
|
|
29
34
|
});
|
|
30
35
|
describe('legacyAddComponent()', () => {
|
|
31
36
|
it('successfully adds a component to a project without public apps', async () => {
|
|
@@ -58,7 +63,7 @@ describe('lib/projects/add/legacyAddComponent', () => {
|
|
|
58
63
|
mockedGetProjectComponentListFromRepo.mockResolvedValue(mockComponentList);
|
|
59
64
|
mockedProjectAddPrompt.mockResolvedValue(mockPromptResponse);
|
|
60
65
|
mockedCloneGithubRepo.mockResolvedValue(true);
|
|
61
|
-
await legacyAddComponent(mockArgs, projectDir, mockProjectConfig);
|
|
66
|
+
await legacyAddComponent(mockArgs, projectDir, mockProjectConfig, accountId);
|
|
62
67
|
expect(mockedFindProjectComponents).toHaveBeenCalledWith(projectDir);
|
|
63
68
|
expect(mockedGetProjectComponentListFromRepo).toHaveBeenCalledWith('v1');
|
|
64
69
|
expect(mockedProjectAddPrompt).toHaveBeenCalledWith(mockComponentList, mockArgs);
|
|
@@ -67,6 +72,9 @@ describe('lib/projects/add/legacyAddComponent', () => {
|
|
|
67
72
|
branch: 'main',
|
|
68
73
|
hideLogs: true,
|
|
69
74
|
}));
|
|
75
|
+
expect(mockedTrackCommandUsage).toHaveBeenCalledWith('project-add', {
|
|
76
|
+
type: 'module',
|
|
77
|
+
}, accountId);
|
|
70
78
|
expect(mockedLogger.log).toHaveBeenCalledWith(commands.project.add.creatingComponent('test-project'));
|
|
71
79
|
expect(mockedLogger.success).toHaveBeenCalledWith(commands.project.add.success('new-component'));
|
|
72
80
|
});
|
|
@@ -97,7 +105,7 @@ describe('lib/projects/add/legacyAddComponent', () => {
|
|
|
97
105
|
},
|
|
98
106
|
];
|
|
99
107
|
mockedFindProjectComponents.mockResolvedValue(mockComponents);
|
|
100
|
-
await expect(legacyAddComponent(mockArgs, projectDir, mockProjectConfig)).rejects.toThrow(commands.project.add.error.projectContainsPublicApp);
|
|
108
|
+
await expect(legacyAddComponent(mockArgs, projectDir, mockProjectConfig, accountId)).rejects.toThrow(commands.project.add.error.projectContainsPublicApp);
|
|
101
109
|
expect(mockedGetProjectComponentListFromRepo).not.toHaveBeenCalled();
|
|
102
110
|
expect(mockedProjectAddPrompt).not.toHaveBeenCalled();
|
|
103
111
|
expect(mockedCloneGithubRepo).not.toHaveBeenCalled();
|
|
@@ -118,7 +126,7 @@ describe('lib/projects/add/legacyAddComponent', () => {
|
|
|
118
126
|
mockedGetProjectComponentListFromRepo.mockResolvedValue(mockComponentList);
|
|
119
127
|
mockedProjectAddPrompt.mockResolvedValue(mockPromptResponse);
|
|
120
128
|
mockedCloneGithubRepo.mockResolvedValue(true);
|
|
121
|
-
await legacyAddComponent(mockArgs, projectDir, mockProjectConfig);
|
|
129
|
+
await legacyAddComponent(mockArgs, projectDir, mockProjectConfig, accountId);
|
|
122
130
|
expect(mockedGetProjectComponentListFromRepo).toHaveBeenCalledWith('v1');
|
|
123
131
|
expect(mockedProjectAddPrompt).toHaveBeenCalledWith(mockComponentList, mockArgs);
|
|
124
132
|
expect(mockedCloneGithubRepo).toHaveBeenCalled();
|
|
@@ -140,7 +148,7 @@ describe('lib/projects/add/legacyAddComponent', () => {
|
|
|
140
148
|
];
|
|
141
149
|
mockedFindProjectComponents.mockResolvedValue(mockComponents);
|
|
142
150
|
mockedGetProjectComponentListFromRepo.mockResolvedValue([]);
|
|
143
|
-
await expect(legacyAddComponent(mockArgs, projectDir, mockProjectConfig)).rejects.toThrow(commands.project.add.error.failedToFetchComponentList);
|
|
151
|
+
await expect(legacyAddComponent(mockArgs, projectDir, mockProjectConfig, accountId)).rejects.toThrow(commands.project.add.error.failedToFetchComponentList);
|
|
144
152
|
expect(mockedProjectAddPrompt).not.toHaveBeenCalled();
|
|
145
153
|
expect(mockedCloneGithubRepo).not.toHaveBeenCalled();
|
|
146
154
|
});
|
|
@@ -162,7 +170,7 @@ describe('lib/projects/add/legacyAddComponent', () => {
|
|
|
162
170
|
mockedFindProjectComponents.mockResolvedValue(mockComponents);
|
|
163
171
|
// @ts-expect-error Breaking stuff on purpose
|
|
164
172
|
mockedGetProjectComponentListFromRepo.mockResolvedValue(null);
|
|
165
|
-
await expect(legacyAddComponent(mockArgs, projectDir, mockProjectConfig)).rejects.toThrow(commands.project.add.error.failedToFetchComponentList);
|
|
173
|
+
await expect(legacyAddComponent(mockArgs, projectDir, mockProjectConfig, accountId)).rejects.toThrow(commands.project.add.error.failedToFetchComponentList);
|
|
166
174
|
expect(mockedProjectAddPrompt).not.toHaveBeenCalled();
|
|
167
175
|
expect(mockedCloneGithubRepo).not.toHaveBeenCalled();
|
|
168
176
|
});
|
|
@@ -196,9 +204,44 @@ describe('lib/projects/add/legacyAddComponent', () => {
|
|
|
196
204
|
mockedGetProjectComponentListFromRepo.mockResolvedValue(mockComponentList);
|
|
197
205
|
mockedProjectAddPrompt.mockResolvedValue(mockPromptResponse);
|
|
198
206
|
mockedCloneGithubRepo.mockRejectedValue(new Error('Clone failed'));
|
|
199
|
-
await expect(legacyAddComponent(mockArgs, projectDir, mockProjectConfig)).rejects.toThrow(commands.project.add.error.failedToDownloadComponent);
|
|
207
|
+
await expect(legacyAddComponent(mockArgs, projectDir, mockProjectConfig, accountId)).rejects.toThrow(commands.project.add.error.failedToDownloadComponent);
|
|
200
208
|
expect(mockedCloneGithubRepo).toHaveBeenCalled();
|
|
201
209
|
expect(mockedLogger.success).not.toHaveBeenCalled();
|
|
202
210
|
});
|
|
211
|
+
it('calls trackCommandUsage with correct component type', async () => {
|
|
212
|
+
const mockComponents = [
|
|
213
|
+
{
|
|
214
|
+
type: ComponentTypes.PrivateApp,
|
|
215
|
+
config: {
|
|
216
|
+
name: 'private-app',
|
|
217
|
+
description: '',
|
|
218
|
+
uid: '',
|
|
219
|
+
scopes: [],
|
|
220
|
+
public: false,
|
|
221
|
+
},
|
|
222
|
+
runnable: true,
|
|
223
|
+
path: '/path/to/private-app',
|
|
224
|
+
},
|
|
225
|
+
];
|
|
226
|
+
const mockComponentList = [
|
|
227
|
+
{ label: 'Card Component', path: 'card-component', type: 'card' },
|
|
228
|
+
];
|
|
229
|
+
const mockPromptResponse = {
|
|
230
|
+
name: 'new-card',
|
|
231
|
+
componentTemplate: {
|
|
232
|
+
label: 'Card Component',
|
|
233
|
+
path: 'card-template-path',
|
|
234
|
+
type: 'card',
|
|
235
|
+
},
|
|
236
|
+
};
|
|
237
|
+
mockedFindProjectComponents.mockResolvedValue(mockComponents);
|
|
238
|
+
mockedGetProjectComponentListFromRepo.mockResolvedValue(mockComponentList);
|
|
239
|
+
mockedProjectAddPrompt.mockResolvedValue(mockPromptResponse);
|
|
240
|
+
mockedCloneGithubRepo.mockResolvedValue(true);
|
|
241
|
+
await legacyAddComponent(mockArgs, projectDir, mockProjectConfig, accountId);
|
|
242
|
+
expect(mockedTrackCommandUsage).toHaveBeenCalledWith('project-add', {
|
|
243
|
+
type: 'card',
|
|
244
|
+
}, accountId);
|
|
245
|
+
});
|
|
203
246
|
});
|
|
204
247
|
});
|