@hubspot/cli 7.8.0-beta.0 → 7.8.0-beta.1
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/__tests__/project.test.js +2 -0
- package/commands/account/auth.js +1 -0
- package/commands/auth.js +1 -0
- package/commands/feedback.js +1 -1
- package/commands/project/__tests__/add.test.js +12 -12
- package/commands/project/__tests__/list.test.js +31 -0
- package/commands/project/__tests__/migrate.test.js +1 -0
- package/commands/project/add.d.ts +2 -2
- package/commands/project/add.js +3 -2
- package/commands/project/create.js +1 -1
- package/commands/project/dev/deprecatedFlow.js +2 -2
- package/commands/project/dev/index.js +5 -5
- package/commands/project/dev/unifiedFlow.js +6 -3
- package/commands/project/download.js +5 -2
- package/commands/project/installDeps.d.ts +2 -2
- package/commands/project/installDeps.js +1 -0
- package/commands/project/list.d.ts +4 -0
- package/commands/project/list.js +62 -0
- package/commands/project/migrate.js +5 -2
- package/commands/project.js +2 -0
- package/commands/sandbox/delete.js +5 -2
- package/commands/testAccount/create.js +2 -2
- package/commands/theme/preview.js +1 -4
- package/lang/en.d.ts +49 -14
- package/lang/en.js +121 -86
- package/lang/en.lyaml +2 -2
- package/lib/__tests__/buildAccount.test.js +2 -2
- package/lib/app/migrate.js +1 -1
- package/lib/buildAccount.d.ts +2 -2
- package/lib/buildAccount.js +7 -7
- package/lib/configMigrate.js +88 -9
- package/lib/constants.d.ts +8 -1
- package/lib/constants.js +8 -1
- package/lib/doctor/Doctor.js +2 -2
- package/lib/errorHandlers/suppressError.js +2 -2
- package/lib/middleware/commandTargetingUtils.d.ts +1 -1
- package/lib/middleware/commandTargetingUtils.js +16 -20
- package/lib/projects/__tests__/AppDevModeInterface.test.js +85 -90
- package/lib/projects/__tests__/LocalDevProcess.test.js +6 -5
- package/lib/projects/__tests__/LocalDevWebsocketServer.test.js +6 -6
- package/lib/projects/__tests__/deploy.test.js +9 -9
- package/lib/projects/__tests__/upload.test.js +2 -2
- package/lib/projects/add/__tests__/{v3AddComponent.test.js → v2AddComponent.test.js} +35 -35
- package/lib/projects/add/{v3AddComponent.d.ts → v2AddComponent.d.ts} +1 -1
- package/lib/projects/add/{v3AddComponent.js → v2AddComponent.js} +5 -5
- package/lib/projects/create/__tests__/v2.test.d.ts +1 -0
- package/lib/projects/create/__tests__/{v3.test.js → v2.test.js} +2 -2
- package/lib/projects/create/index.js +2 -2
- package/lib/projects/create/{v3.d.ts → v2.d.ts} +3 -3
- package/lib/projects/create/{v3.js → v2.js} +3 -3
- package/lib/projects/deploy.d.ts +1 -1
- package/lib/projects/deploy.js +2 -2
- package/lib/projects/localDev/AppDevModeInterface.d.ts +8 -1
- package/lib/projects/localDev/AppDevModeInterface.js +106 -86
- package/lib/projects/localDev/DevServerManager.d.ts +11 -29
- package/lib/projects/localDev/DevServerManager.js +19 -61
- package/lib/projects/localDev/DevServerManager_DEPRECATED.d.ts +40 -0
- package/lib/projects/localDev/DevServerManager_DEPRECATED.js +120 -0
- package/lib/projects/localDev/{LocalDevManager.js → LocalDevManager_DEPRECATED.js} +6 -6
- package/lib/projects/localDev/LocalDevProcess.js +3 -2
- package/lib/projects/localDev/LocalDevState.d.ts +3 -0
- package/lib/projects/localDev/LocalDevState.js +9 -0
- package/lib/projects/localDev/LocalDevWebsocketServer.d.ts +4 -0
- package/lib/projects/localDev/LocalDevWebsocketServer.js +34 -2
- package/lib/projects/localDev/helpers/account.d.ts +1 -1
- package/lib/projects/localDev/helpers/account.js +2 -2
- package/lib/projects/localDev/helpers/project.js +2 -3
- package/lib/projects/localDev/localDevWebsocketServerUtils.d.ts +3 -0
- package/lib/projects/localDev/localDevWebsocketServerUtils.js +9 -0
- package/lib/projects/urls.d.ts +0 -1
- package/lib/projects/urls.js +0 -3
- package/lib/prompts/__tests__/downloadProjectPrompt.test.js +1 -0
- package/lib/prompts/__tests__/projectAddPrompt.test.js +10 -10
- package/lib/prompts/installAppPrompt.d.ts +1 -6
- package/lib/prompts/installAppPrompt.js +1 -6
- package/lib/prompts/projectAddPrompt.d.ts +2 -2
- package/lib/prompts/projectAddPrompt.js +1 -1
- package/lib/prompts/projectDevTargetAccountPrompt.js +1 -1
- package/lib/theme/__tests__/migrate.test.js +4 -4
- package/lib/ui/index.d.ts +4 -0
- package/lib/ui/index.js +9 -1
- package/lib/ui/uiMessages.d.ts +4 -0
- package/lib/ui/uiMessages.js +4 -0
- package/mcp-server/tools/project/__tests__/CreateProjectTool.test.js +1 -1
- package/package.json +6 -5
- package/lib/projects/localDev/DevServerManagerV2.d.ts +0 -22
- package/lib/projects/localDev/DevServerManagerV2.js +0 -81
- /package/{lib/projects/add/__tests__/v3AddComponent.test.d.ts → commands/project/__tests__/list.test.d.ts} +0 -0
- /package/lib/projects/{create/__tests__/v3.test.d.ts → add/__tests__/v2AddComponent.test.d.ts} +0 -0
- /package/lib/projects/localDev/{LocalDevManager.d.ts → LocalDevManager_DEPRECATED.d.ts} +0 -0
|
@@ -11,7 +11,7 @@ vi.mock('@hubspot/ui-extensions-dev-server', () => {
|
|
|
11
11
|
};
|
|
12
12
|
});
|
|
13
13
|
import { fetchAppInstallationData } from '@hubspot/local-dev-lib/api/localDevAuth';
|
|
14
|
-
import {
|
|
14
|
+
import { fetchAppMetadataByUid, fetchPublicAppProductionInstallCounts, installStaticAuthAppOnTestAccount, } from '@hubspot/local-dev-lib/api/appsDev';
|
|
15
15
|
import { DevModeUnifiedInterface as UIEDevModeInterface } from '@hubspot/ui-extensions-dev-server';
|
|
16
16
|
import { requestPorts } from '@hubspot/local-dev-lib/portManager';
|
|
17
17
|
import { getAccountConfig } from '@hubspot/local-dev-lib/config';
|
|
@@ -109,8 +109,8 @@ describe('AppDevModeInterface', () => {
|
|
|
109
109
|
LocalDevState.mockImplementation(() => mockLocalDevState);
|
|
110
110
|
LocalDevLogger.mockImplementation(() => mockLocalDevLogger);
|
|
111
111
|
// Mock external dependencies
|
|
112
|
-
|
|
113
|
-
data:
|
|
112
|
+
fetchAppMetadataByUid.mockResolvedValue({
|
|
113
|
+
data: mockPublicApp,
|
|
114
114
|
});
|
|
115
115
|
fetchPublicAppProductionInstallCounts.mockResolvedValue({
|
|
116
116
|
data: { uniquePortalInstallCount: 5 },
|
|
@@ -129,7 +129,16 @@ describe('AppDevModeInterface', () => {
|
|
|
129
129
|
getOauthAppInstallUrl.mockReturnValue('http://oauth-install-url');
|
|
130
130
|
getStaticAuthAppInstallUrl.mockReturnValue('http://static-install-url');
|
|
131
131
|
installAppAutoPrompt.mockResolvedValue(true);
|
|
132
|
-
installAppBrowserPrompt.
|
|
132
|
+
installAppBrowserPrompt.mockImplementation(async () => {
|
|
133
|
+
setTimeout(() => {
|
|
134
|
+
const addListenerCall = mockLocalDevState.addListener.mock.calls.find(call => call[0] === 'devServerMessage');
|
|
135
|
+
if (addListenerCall) {
|
|
136
|
+
const callback = addListenerCall[1];
|
|
137
|
+
callback(LOCAL_DEV_SERVER_MESSAGE_TYPES.STATIC_AUTH_APP_INSTALL_SUCCESS);
|
|
138
|
+
}
|
|
139
|
+
}, 0);
|
|
140
|
+
return undefined;
|
|
141
|
+
});
|
|
133
142
|
confirmPrompt.mockResolvedValue(true);
|
|
134
143
|
installStaticAuthAppOnTestAccount.mockResolvedValue(undefined);
|
|
135
144
|
// Mock process.exit
|
|
@@ -191,12 +200,12 @@ describe('AppDevModeInterface', () => {
|
|
|
191
200
|
it('should return early if no app node exists', async () => {
|
|
192
201
|
mockLocalDevState.projectNodes = {};
|
|
193
202
|
await appDevModeInterface.setup({});
|
|
194
|
-
expect(
|
|
203
|
+
expect(fetchAppMetadataByUid).not.toHaveBeenCalled();
|
|
195
204
|
expect(UIEDevModeInterface.setup).not.toHaveBeenCalled();
|
|
196
205
|
});
|
|
197
206
|
it('should setup successfully with private app', async () => {
|
|
198
207
|
await appDevModeInterface.setup({});
|
|
199
|
-
expect(
|
|
208
|
+
expect(fetchAppMetadataByUid).toHaveBeenCalledWith('test-app-uid', 12345);
|
|
200
209
|
expect(fetchPublicAppProductionInstallCounts).toHaveBeenCalledWith(123, 12345);
|
|
201
210
|
expect(fetchAppInstallationData).toHaveBeenCalledWith(67890, 999, 'test-app-uid', ['test-scope'], []);
|
|
202
211
|
expect(UIEDevModeInterface.setup).toHaveBeenCalled();
|
|
@@ -242,21 +251,16 @@ describe('AppDevModeInterface', () => {
|
|
|
242
251
|
await newAppDevModeInterface.setup({});
|
|
243
252
|
expect(process.exit).toHaveBeenCalledWith(0);
|
|
244
253
|
});
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
// 123,
|
|
256
|
-
// 67890,
|
|
257
|
-
// [1, 2, 3]
|
|
258
|
-
// );
|
|
259
|
-
// });
|
|
254
|
+
it('should auto-install static auth app on test account', async () => {
|
|
255
|
+
fetchAppInstallationData.mockResolvedValue({
|
|
256
|
+
data: {
|
|
257
|
+
isInstalledWithScopeGroups: false,
|
|
258
|
+
previouslyAuthorizedScopeGroups: [],
|
|
259
|
+
},
|
|
260
|
+
});
|
|
261
|
+
await appDevModeInterface.setup({});
|
|
262
|
+
expect(installStaticAuthAppOnTestAccount).toHaveBeenCalledWith(123, 67890, [1, 2, 3]);
|
|
263
|
+
});
|
|
260
264
|
it('should open browser for OAuth app installation', async () => {
|
|
261
265
|
const oauthAppNode = {
|
|
262
266
|
...mockAppNode,
|
|
@@ -295,81 +299,47 @@ describe('AppDevModeInterface', () => {
|
|
|
295
299
|
},
|
|
296
300
|
});
|
|
297
301
|
await appDevModeInterface.setup({});
|
|
298
|
-
expect(installAppBrowserPrompt).toHaveBeenCalledWith('http://static-install-url', true
|
|
299
|
-
appUid: 'test-app-uid',
|
|
300
|
-
projectAccountId: 12345,
|
|
301
|
-
projectName: 'test-project',
|
|
302
|
-
testingAccountId: 67890,
|
|
303
|
-
});
|
|
302
|
+
expect(installAppBrowserPrompt).toHaveBeenCalledWith('http://static-install-url', true);
|
|
304
303
|
});
|
|
305
304
|
it('should handle errors during setup', async () => {
|
|
306
305
|
const error = new Error('Setup failed');
|
|
307
|
-
|
|
306
|
+
fetchAppMetadataByUid.mockRejectedValue(error);
|
|
308
307
|
await appDevModeInterface.setup({});
|
|
309
308
|
expect(logError).toHaveBeenCalledWith(error);
|
|
310
309
|
});
|
|
311
|
-
it('should exit if
|
|
312
|
-
// Set up conditions for
|
|
313
|
-
getAccountConfig.mockReturnValue(
|
|
314
|
-
|
|
315
|
-
fetchPublicAppsForPortal
|
|
316
|
-
.mockResolvedValueOnce({
|
|
317
|
-
data: { results: [mockPublicApp] },
|
|
318
|
-
})
|
|
319
|
-
// Second call for getAppInstallUrl fails (app not found)
|
|
320
|
-
.mockResolvedValueOnce({
|
|
321
|
-
data: { results: [] },
|
|
310
|
+
it('should exit if user declines auto-install', async () => {
|
|
311
|
+
// Set up conditions for automatic installation
|
|
312
|
+
getAccountConfig.mockReturnValue({
|
|
313
|
+
parentAccountId: 12345, // matches targetProjectAccountId
|
|
322
314
|
});
|
|
315
|
+
isDeveloperTestAccount.mockReturnValue(true);
|
|
323
316
|
fetchAppInstallationData.mockResolvedValue({
|
|
324
317
|
data: {
|
|
325
318
|
isInstalledWithScopeGroups: false,
|
|
326
319
|
previouslyAuthorizedScopeGroups: [],
|
|
327
320
|
},
|
|
328
321
|
});
|
|
322
|
+
installAppAutoPrompt.mockResolvedValue(false);
|
|
323
|
+
// Create a new instance to trigger the exit during setup
|
|
324
|
+
const newAppDevModeInterface = new AppDevModeInterface({
|
|
325
|
+
localDevState: mockLocalDevState,
|
|
326
|
+
localDevLogger: mockLocalDevLogger,
|
|
327
|
+
});
|
|
329
328
|
// The setup method catches the error, so we check that process.exit was called
|
|
329
|
+
await newAppDevModeInterface.setup({});
|
|
330
|
+
expect(process.exit).toHaveBeenCalledWith(0);
|
|
331
|
+
});
|
|
332
|
+
it('should fallback to browser install if auto-install fails', async () => {
|
|
333
|
+
fetchAppInstallationData.mockResolvedValue({
|
|
334
|
+
data: {
|
|
335
|
+
isInstalledWithScopeGroups: false,
|
|
336
|
+
previouslyAuthorizedScopeGroups: [],
|
|
337
|
+
},
|
|
338
|
+
});
|
|
339
|
+
installStaticAuthAppOnTestAccount.mockRejectedValue(new Error('Install failed'));
|
|
330
340
|
await appDevModeInterface.setup({});
|
|
331
|
-
expect(
|
|
332
|
-
});
|
|
333
|
-
// @TODO: Restore test account auto install functionality
|
|
334
|
-
// it('should exit if user declines auto-install', async () => {
|
|
335
|
-
// // Set up conditions for automatic installation
|
|
336
|
-
// (getAccountConfig as Mock).mockReturnValue({
|
|
337
|
-
// parentAccountId: 12345, // matches targetProjectAccountId
|
|
338
|
-
// });
|
|
339
|
-
// (isDeveloperTestAccount as Mock).mockReturnValue(true);
|
|
340
|
-
// (fetchAppInstallationData as Mock).mockResolvedValue({
|
|
341
|
-
// data: {
|
|
342
|
-
// isInstalledWithScopeGroups: false,
|
|
343
|
-
// previouslyAuthorizedScopeGroups: [],
|
|
344
|
-
// },
|
|
345
|
-
// });
|
|
346
|
-
// (installAppAutoPrompt as Mock).mockResolvedValue(false);
|
|
347
|
-
// // Create a new instance to trigger the exit during setup
|
|
348
|
-
// const newAppDevModeInterface = new AppDevModeInterface({
|
|
349
|
-
// localDevState: mockLocalDevState,
|
|
350
|
-
// localDevLogger: mockLocalDevLogger,
|
|
351
|
-
// });
|
|
352
|
-
// // The setup method catches the error, so we check that process.exit was called
|
|
353
|
-
// await newAppDevModeInterface.setup({});
|
|
354
|
-
// expect(process.exit).toHaveBeenCalledWith(0);
|
|
355
|
-
// });
|
|
356
|
-
// @TODO: Restore test account auto install functionality
|
|
357
|
-
// it('should fallback to browser install if auto-install fails', async () => {
|
|
358
|
-
// (fetchAppInstallationData as Mock).mockResolvedValue({
|
|
359
|
-
// data: {
|
|
360
|
-
// isInstalledWithScopeGroups: false,
|
|
361
|
-
// previouslyAuthorizedScopeGroups: [],
|
|
362
|
-
// },
|
|
363
|
-
// });
|
|
364
|
-
// (installStaticAuthAppOnTestAccount as Mock).mockRejectedValue(
|
|
365
|
-
// new Error('Install failed')
|
|
366
|
-
// );
|
|
367
|
-
// await appDevModeInterface.setup({});
|
|
368
|
-
// expect(installAppBrowserPrompt).toHaveBeenCalledWith(
|
|
369
|
-
// 'http://static-install-url',
|
|
370
|
-
// false
|
|
371
|
-
// );
|
|
372
|
-
// });
|
|
341
|
+
expect(installAppBrowserPrompt).toHaveBeenCalledWith('http://static-install-url', false);
|
|
342
|
+
});
|
|
373
343
|
});
|
|
374
344
|
describe('start()', () => {
|
|
375
345
|
it('should return early if no app node exists', async () => {
|
|
@@ -426,14 +396,21 @@ describe('AppDevModeInterface', () => {
|
|
|
426
396
|
// Reset mocks to ensure clean state
|
|
427
397
|
vi.clearAllMocks();
|
|
428
398
|
// Set up basic mocks
|
|
429
|
-
|
|
430
|
-
data:
|
|
399
|
+
fetchAppMetadataByUid.mockResolvedValue({
|
|
400
|
+
data: mockPublicApp,
|
|
431
401
|
});
|
|
432
402
|
fetchPublicAppProductionInstallCounts.mockResolvedValue({
|
|
433
403
|
data: { uniquePortalInstallCount: 5 },
|
|
434
404
|
});
|
|
435
405
|
getStaticAuthAppInstallUrl.mockReturnValue('http://static-install-url');
|
|
436
|
-
installAppBrowserPrompt.
|
|
406
|
+
installAppBrowserPrompt.mockImplementation(async () => {
|
|
407
|
+
const addListenerCall = mockLocalDevState.addListener.mock.calls.find(call => call[0] === 'devServerMessage');
|
|
408
|
+
if (addListenerCall) {
|
|
409
|
+
const callback = addListenerCall[1];
|
|
410
|
+
callback(LOCAL_DEV_SERVER_MESSAGE_TYPES.STATIC_AUTH_APP_INSTALL_SUCCESS);
|
|
411
|
+
}
|
|
412
|
+
return undefined;
|
|
413
|
+
});
|
|
437
414
|
// Reset the mock LocalDevState
|
|
438
415
|
mockLocalDevState.getAppDataByUid = vi.fn().mockReturnValue(mockAppData);
|
|
439
416
|
mockLocalDevState.setAppDataForUid = vi.fn();
|
|
@@ -459,14 +436,23 @@ describe('AppDevModeInterface', () => {
|
|
|
459
436
|
// Reset mocks to ensure clean state
|
|
460
437
|
vi.clearAllMocks();
|
|
461
438
|
// Set up basic mocks
|
|
462
|
-
|
|
463
|
-
data:
|
|
439
|
+
fetchAppMetadataByUid.mockResolvedValue({
|
|
440
|
+
data: mockPublicApp,
|
|
464
441
|
});
|
|
465
442
|
fetchPublicAppProductionInstallCounts.mockResolvedValue({
|
|
466
443
|
data: { uniquePortalInstallCount: 5 },
|
|
467
444
|
});
|
|
468
445
|
getOauthAppInstallUrl.mockReturnValue('http://oauth-install-url');
|
|
469
|
-
installAppBrowserPrompt.
|
|
446
|
+
installAppBrowserPrompt.mockImplementation(async () => {
|
|
447
|
+
setTimeout(() => {
|
|
448
|
+
const addListenerCall = mockLocalDevState.addListener.mock.calls.find(call => call[0] === 'devServerMessage');
|
|
449
|
+
if (addListenerCall) {
|
|
450
|
+
const callback = addListenerCall[1];
|
|
451
|
+
callback(LOCAL_DEV_SERVER_MESSAGE_TYPES.STATIC_AUTH_APP_INSTALL_SUCCESS);
|
|
452
|
+
}
|
|
453
|
+
}, 0);
|
|
454
|
+
return undefined;
|
|
455
|
+
});
|
|
470
456
|
// Reset the mock LocalDevState
|
|
471
457
|
mockLocalDevState.getAppDataByUid = vi.fn().mockReturnValue(mockAppData);
|
|
472
458
|
mockLocalDevState.setAppDataForUid = vi.fn();
|
|
@@ -503,14 +489,23 @@ describe('AppDevModeInterface', () => {
|
|
|
503
489
|
// Reset mocks to ensure clean state
|
|
504
490
|
vi.clearAllMocks();
|
|
505
491
|
// Set up basic mocks
|
|
506
|
-
|
|
507
|
-
data:
|
|
492
|
+
fetchAppMetadataByUid.mockResolvedValue({
|
|
493
|
+
data: mockPublicApp,
|
|
508
494
|
});
|
|
509
495
|
fetchPublicAppProductionInstallCounts.mockResolvedValue({
|
|
510
496
|
data: { uniquePortalInstallCount: 5 },
|
|
511
497
|
});
|
|
512
498
|
getStaticAuthAppInstallUrl.mockReturnValue('http://static-install-url');
|
|
513
|
-
installAppBrowserPrompt.
|
|
499
|
+
installAppBrowserPrompt.mockImplementation(async () => {
|
|
500
|
+
setTimeout(() => {
|
|
501
|
+
const addListenerCall = mockLocalDevState.addListener.mock.calls.find(call => call[0] === 'devServerMessage');
|
|
502
|
+
if (addListenerCall) {
|
|
503
|
+
const callback = addListenerCall[1];
|
|
504
|
+
callback(LOCAL_DEV_SERVER_MESSAGE_TYPES.STATIC_AUTH_APP_INSTALL_SUCCESS);
|
|
505
|
+
}
|
|
506
|
+
}, 0);
|
|
507
|
+
return undefined;
|
|
508
|
+
});
|
|
514
509
|
// Reset the mock LocalDevState
|
|
515
510
|
mockLocalDevState.getAppDataByUid = vi.fn().mockReturnValue(mockAppData);
|
|
516
511
|
mockLocalDevState.setAppDataForUid = vi.fn();
|
|
@@ -7,7 +7,7 @@ import { fetchProject } from '@hubspot/local-dev-lib/api/projects';
|
|
|
7
7
|
import { isHubSpotHttpError } from '@hubspot/local-dev-lib/errors/index';
|
|
8
8
|
import LocalDevProcess from '../localDev/LocalDevProcess.js';
|
|
9
9
|
import LocalDevLogger from '../localDev/LocalDevLogger.js';
|
|
10
|
-
import
|
|
10
|
+
import DevServerManager from '../localDev/DevServerManager.js';
|
|
11
11
|
import { ENVIRONMENTS } from '@hubspot/local-dev-lib/constants/environments';
|
|
12
12
|
import { vi } from 'vitest';
|
|
13
13
|
// Mock @hubspot/ui-extensions-dev-server
|
|
@@ -27,7 +27,7 @@ vi.mock('../config');
|
|
|
27
27
|
vi.mock('@hubspot/local-dev-lib/api/projects');
|
|
28
28
|
vi.mock('@hubspot/local-dev-lib/errors/index');
|
|
29
29
|
vi.mock('../localDev/LocalDevLogger');
|
|
30
|
-
vi.mock('../localDev/
|
|
30
|
+
vi.mock('../localDev/DevServerManager');
|
|
31
31
|
// Tests for LocalDevProcess and LocalDevState
|
|
32
32
|
describe('LocalDevProcess', () => {
|
|
33
33
|
let mockLocalDevLogger;
|
|
@@ -67,6 +67,7 @@ describe('LocalDevProcess', () => {
|
|
|
67
67
|
subbuildStatuses: [],
|
|
68
68
|
uploadMessage: 'Build completed',
|
|
69
69
|
autoDeployId: 0,
|
|
70
|
+
platformVersion: '2025.2',
|
|
70
71
|
},
|
|
71
72
|
},
|
|
72
73
|
initialProjectNodes: {},
|
|
@@ -104,7 +105,7 @@ describe('LocalDevProcess', () => {
|
|
|
104
105
|
};
|
|
105
106
|
// Mock constructors
|
|
106
107
|
LocalDevLogger.mockImplementation(() => mockLocalDevLogger);
|
|
107
|
-
|
|
108
|
+
DevServerManager.mockImplementation(() => mockDevServerManager);
|
|
108
109
|
// Mock external functions
|
|
109
110
|
isHubSpotHttpError.mockReturnValue(false);
|
|
110
111
|
// Create process instance
|
|
@@ -398,7 +399,7 @@ describe('LocalDevProcess', () => {
|
|
|
398
399
|
expect(handleProjectDeploy).toHaveBeenCalledWith(123, // targetProjectAccountId
|
|
399
400
|
'test-project', // projectName
|
|
400
401
|
123, // buildId
|
|
401
|
-
true, //
|
|
402
|
+
true, // useV2Api
|
|
402
403
|
false // force
|
|
403
404
|
);
|
|
404
405
|
expect(mockLocalDevLogger.deploySuccess).toHaveBeenCalled();
|
|
@@ -426,7 +427,7 @@ describe('LocalDevProcess', () => {
|
|
|
426
427
|
expect(handleProjectDeploy).toHaveBeenCalledWith(123, // targetProjectAccountId
|
|
427
428
|
'test-project', // projectName
|
|
428
429
|
123, // buildId
|
|
429
|
-
true, //
|
|
430
|
+
true, // useV2Api
|
|
430
431
|
true // force
|
|
431
432
|
);
|
|
432
433
|
expect(result).toEqual({
|
|
@@ -252,7 +252,7 @@ describe('LocalDevWebsocketServer', () => {
|
|
|
252
252
|
expect(mockWebSocket2.on).toHaveBeenCalledWith('message', expect.any(Function));
|
|
253
253
|
expect(mockWebSocket3.on).toHaveBeenCalledWith('message', expect.any(Function));
|
|
254
254
|
// Each connection should trigger state listener setup
|
|
255
|
-
expect(mockLocalDevProcess.addStateListener).toHaveBeenCalledTimes(
|
|
255
|
+
expect(mockLocalDevProcess.addStateListener).toHaveBeenCalledTimes(12); // 4 listeners per connection * 3 connections
|
|
256
256
|
// Each connection should trigger dev server message
|
|
257
257
|
expect(mockLocalDevProcess.sendDevServerMessage).toHaveBeenCalledTimes(3);
|
|
258
258
|
expect(mockLocalDevProcess.sendDevServerMessage).toHaveBeenCalledWith(LOCAL_DEV_SERVER_MESSAGE_TYPES.WEBSOCKET_SERVER_CONNECTED);
|
|
@@ -308,16 +308,16 @@ describe('LocalDevWebsocketServer', () => {
|
|
|
308
308
|
const closeCallbacks2 = mockWebSocket2.on.mock.calls
|
|
309
309
|
.filter(call => call[0] === 'close')
|
|
310
310
|
.map(call => call[1]);
|
|
311
|
-
expect(closeCallbacks1).toHaveLength(
|
|
312
|
-
expect(closeCallbacks2).toHaveLength(
|
|
311
|
+
expect(closeCallbacks1).toHaveLength(4); // projectNodes, appData, devServersStarted, and uploadWarnings listeners
|
|
312
|
+
expect(closeCallbacks2).toHaveLength(4); // projectNodes, appData, devServersStarted, and uploadWarnings listeners
|
|
313
313
|
// Simulate first connection closing (call all close callbacks)
|
|
314
314
|
closeCallbacks1.forEach(callback => callback());
|
|
315
|
-
// Should have removed listeners for first connection (
|
|
316
|
-
expect(mockLocalDevProcess.removeStateListener).toHaveBeenCalledTimes(
|
|
315
|
+
// Should have removed listeners for first connection (4 listeners: projectNodes, appData, devServersStarted, and uploadWarnings)
|
|
316
|
+
expect(mockLocalDevProcess.removeStateListener).toHaveBeenCalledTimes(4);
|
|
317
317
|
// Simulate second connection closing
|
|
318
318
|
closeCallbacks2.forEach(callback => callback());
|
|
319
319
|
// Should have removed listeners for second connection as well
|
|
320
|
-
expect(mockLocalDevProcess.removeStateListener).toHaveBeenCalledTimes(
|
|
320
|
+
expect(mockLocalDevProcess.removeStateListener).toHaveBeenCalledTimes(8);
|
|
321
321
|
});
|
|
322
322
|
it('should broadcast state changes to all connected clients', () => {
|
|
323
323
|
// Establish connections
|
|
@@ -99,7 +99,7 @@ describe('lib/projects/deploy', () => {
|
|
|
99
99
|
const targetAccountId = 12345;
|
|
100
100
|
const projectName = 'test-project';
|
|
101
101
|
const buildId = 5;
|
|
102
|
-
const
|
|
102
|
+
const useV2Api = true;
|
|
103
103
|
const force = false;
|
|
104
104
|
it('successfully deploys and returns deploy result', async () => {
|
|
105
105
|
const mockDeployResponseData = {
|
|
@@ -126,8 +126,8 @@ describe('lib/projects/deploy', () => {
|
|
|
126
126
|
data: mockDeployResponseData,
|
|
127
127
|
});
|
|
128
128
|
mockPollDeployStatus.mockResolvedValue(mockDeployResult);
|
|
129
|
-
const deploy = await handleProjectDeploy(targetAccountId, projectName, buildId,
|
|
130
|
-
expect(mockDeployProject).toHaveBeenCalledWith(targetAccountId, projectName, buildId,
|
|
129
|
+
const deploy = await handleProjectDeploy(targetAccountId, projectName, buildId, useV2Api, force);
|
|
130
|
+
expect(mockDeployProject).toHaveBeenCalledWith(targetAccountId, projectName, buildId, useV2Api, force);
|
|
131
131
|
expect(deploy).toEqual(mockDeployResult);
|
|
132
132
|
});
|
|
133
133
|
it('handles blocked deploy with warnings', async () => {
|
|
@@ -150,7 +150,7 @@ describe('lib/projects/deploy', () => {
|
|
|
150
150
|
mockDeployProject.mockResolvedValue({
|
|
151
151
|
data: mockBlockedResponse,
|
|
152
152
|
});
|
|
153
|
-
await handleProjectDeploy(targetAccountId, projectName, buildId,
|
|
153
|
+
await handleProjectDeploy(targetAccountId, projectName, buildId, useV2Api, force);
|
|
154
154
|
expect(mockUiLogger.warn).toHaveBeenCalledWith(commands.project.deploy.errors.deployWarningsHeader);
|
|
155
155
|
});
|
|
156
156
|
it('handles blocked deploy with errors (cannot be forced)', async () => {
|
|
@@ -173,7 +173,7 @@ describe('lib/projects/deploy', () => {
|
|
|
173
173
|
mockDeployProject.mockResolvedValue({
|
|
174
174
|
data: mockBlockedResponse,
|
|
175
175
|
});
|
|
176
|
-
await handleProjectDeploy(targetAccountId, projectName, buildId,
|
|
176
|
+
await handleProjectDeploy(targetAccountId, projectName, buildId, useV2Api, force);
|
|
177
177
|
expect(mockUiLogger.error).toHaveBeenCalledWith(commands.project.deploy.errors.deployBlockedHeader);
|
|
178
178
|
expect(mockUiLogger.log).toHaveBeenCalledWith(commands.project.deploy.errors.deployIssueComponentWarning('component-1', 'module', 'This is an error'));
|
|
179
179
|
});
|
|
@@ -192,19 +192,19 @@ describe('lib/projects/deploy', () => {
|
|
|
192
192
|
mockDeployProject.mockResolvedValue({
|
|
193
193
|
data: mockBlockedResponse,
|
|
194
194
|
});
|
|
195
|
-
await handleProjectDeploy(targetAccountId, projectName, buildId,
|
|
195
|
+
await handleProjectDeploy(targetAccountId, projectName, buildId, useV2Api, force);
|
|
196
196
|
expect(mockUiLogger.warn).toHaveBeenCalledWith(commands.project.deploy.errors.deployWarningsHeader);
|
|
197
197
|
expect(mockUiLogger.log).toHaveBeenCalledWith(commands.project.deploy.errors.deployIssueComponentGeneric('component-1', 'module'));
|
|
198
198
|
});
|
|
199
199
|
it('handles general deploy failure', async () => {
|
|
200
200
|
mockDeployProject.mockResolvedValue({ data: null });
|
|
201
|
-
const deploy = await handleProjectDeploy(targetAccountId, projectName, buildId,
|
|
201
|
+
const deploy = await handleProjectDeploy(targetAccountId, projectName, buildId, useV2Api, force);
|
|
202
202
|
expect(mockUiLogger.error).toHaveBeenCalledWith(commands.project.deploy.errors.deploy);
|
|
203
203
|
expect(deploy).toBeUndefined();
|
|
204
204
|
});
|
|
205
205
|
it('handles undefined deploy response', async () => {
|
|
206
206
|
mockDeployProject.mockResolvedValue({ data: undefined });
|
|
207
|
-
const deploy = await handleProjectDeploy(targetAccountId, projectName, buildId,
|
|
207
|
+
const deploy = await handleProjectDeploy(targetAccountId, projectName, buildId, useV2Api, force);
|
|
208
208
|
expect(mockUiLogger.error).toHaveBeenCalledWith(commands.project.deploy.errors.deploy);
|
|
209
209
|
expect(deploy).toBeUndefined();
|
|
210
210
|
});
|
|
@@ -221,7 +221,7 @@ describe('lib/projects/deploy', () => {
|
|
|
221
221
|
});
|
|
222
222
|
mockPollDeployStatus.mockResolvedValue({});
|
|
223
223
|
await handleProjectDeploy(targetAccountId, projectName, buildId, false, true);
|
|
224
|
-
expect(mockDeployProject).toHaveBeenCalledWith(targetAccountId, projectName, buildId, false, //
|
|
224
|
+
expect(mockDeployProject).toHaveBeenCalledWith(targetAccountId, projectName, buildId, false, // useV2Api
|
|
225
225
|
true // force
|
|
226
226
|
);
|
|
227
227
|
});
|
|
@@ -36,7 +36,7 @@ describe('lib/projects/upload', () => {
|
|
|
36
36
|
await expect(validateSourceDirectory(srcDir, projectConfig, tempDir)).rejects.toThrow(ProjectValidationError);
|
|
37
37
|
expect(walk).toHaveBeenCalledWith(srcDir, ['node_modules']);
|
|
38
38
|
});
|
|
39
|
-
it('should warn about legacy files in
|
|
39
|
+
it('should warn about legacy files in V2 projects', async () => {
|
|
40
40
|
vi.mocked(isV2Project).mockReturnValue(true);
|
|
41
41
|
const legacyFilePath = path.join(srcDir, 'app', 'serverless.json');
|
|
42
42
|
vi.mocked(walk).mockResolvedValue([legacyFilePath]);
|
|
@@ -67,7 +67,7 @@ describe('lib/projects/upload', () => {
|
|
|
67
67
|
await validateSourceDirectory(srcDir, projectConfig, tempDir);
|
|
68
68
|
expect(uiLogger.warn).not.toHaveBeenCalled();
|
|
69
69
|
});
|
|
70
|
-
it('should not warn about legacy files in non-
|
|
70
|
+
it('should not warn about legacy files in non-V2 projects', async () => {
|
|
71
71
|
vi.mocked(isV2Project).mockReturnValue(false);
|
|
72
72
|
projectConfig.platformVersion = '2025.1';
|
|
73
73
|
const filePaths = [
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
|
-
import {
|
|
2
|
+
import { v2AddComponent } from '../v2AddComponent.js';
|
|
3
3
|
import { getConfigForPlatformVersion } from '../../create/legacy.js';
|
|
4
|
-
import {
|
|
4
|
+
import { createV2App } from '../../create/v2.js';
|
|
5
5
|
import { confirmPrompt } from '../../../prompts/promptUtils.js';
|
|
6
|
-
import {
|
|
6
|
+
import { projectAddPromptV2 } from '../../../prompts/projectAddPrompt.js';
|
|
7
7
|
import { cloneGithubRepo } from '@hubspot/local-dev-lib/github';
|
|
8
8
|
import { uiLogger } from '../../../ui/logger.js';
|
|
9
9
|
import { getProjectMetadata } from '@hubspot/project-parsing-lib/src/lib/project.js';
|
|
@@ -12,7 +12,7 @@ import { commands } from '../../../../lang/en.js';
|
|
|
12
12
|
vi.mock('fs');
|
|
13
13
|
vi.mock('../../../prompts/promptUtils');
|
|
14
14
|
vi.mock('../../create/legacy');
|
|
15
|
-
vi.mock('../../create/
|
|
15
|
+
vi.mock('../../create/v2');
|
|
16
16
|
vi.mock('../../../prompts/projectAddPrompt');
|
|
17
17
|
vi.mock('@hubspot/local-dev-lib/github');
|
|
18
18
|
vi.mock('../../../ui/logger.js');
|
|
@@ -21,17 +21,17 @@ vi.mock('../../../usageTracking');
|
|
|
21
21
|
const mockedFs = vi.mocked(fs);
|
|
22
22
|
const mockedGetConfigForPlatformVersion = vi.mocked(getConfigForPlatformVersion);
|
|
23
23
|
const mockedConfirmPrompt = vi.mocked(confirmPrompt);
|
|
24
|
-
const
|
|
25
|
-
const
|
|
24
|
+
const mockedCreateV2App = vi.mocked(createV2App);
|
|
25
|
+
const mockedProjectAddPromptV2 = vi.mocked(projectAddPromptV2);
|
|
26
26
|
const mockedCloneGithubRepo = vi.mocked(cloneGithubRepo);
|
|
27
27
|
const mockedUiLogger = vi.mocked(uiLogger);
|
|
28
28
|
const mockedGetProjectMetadata = vi.mocked(getProjectMetadata);
|
|
29
29
|
const mockedTrackCommandUsage = vi.mocked(trackCommandUsage);
|
|
30
|
-
describe('lib/projects/add/
|
|
30
|
+
describe('lib/projects/add/v2AddComponent', () => {
|
|
31
31
|
const mockProjectConfig = {
|
|
32
32
|
name: 'test-project',
|
|
33
33
|
srcDir: 'src',
|
|
34
|
-
platformVersion: '
|
|
34
|
+
platformVersion: '2025.2',
|
|
35
35
|
};
|
|
36
36
|
const mockArgs = {
|
|
37
37
|
name: 'test-component',
|
|
@@ -66,13 +66,13 @@ describe('lib/projects/add/v3AddComponent', () => {
|
|
|
66
66
|
},
|
|
67
67
|
};
|
|
68
68
|
beforeEach(() => {
|
|
69
|
-
|
|
69
|
+
mockedCreateV2App.mockResolvedValue({
|
|
70
70
|
authType: 'oauth',
|
|
71
71
|
distribution: 'private',
|
|
72
72
|
});
|
|
73
73
|
mockedTrackCommandUsage.mockResolvedValue();
|
|
74
74
|
});
|
|
75
|
-
describe('
|
|
75
|
+
describe('v2AddComponent()', () => {
|
|
76
76
|
it('successfully adds a component when app already exists', async () => {
|
|
77
77
|
const mockAppMeta = {
|
|
78
78
|
config: {
|
|
@@ -86,17 +86,17 @@ describe('lib/projects/add/v3AddComponent', () => {
|
|
|
86
86
|
mockedGetConfigForPlatformVersion.mockResolvedValue(mockConfig);
|
|
87
87
|
mockedGetProjectMetadata.mockResolvedValue(mockProjectMetadata);
|
|
88
88
|
mockedFs.readFileSync.mockReturnValue(JSON.stringify(mockAppMeta));
|
|
89
|
-
|
|
89
|
+
mockedProjectAddPromptV2.mockResolvedValue(mockPromptResponse);
|
|
90
90
|
mockedCloneGithubRepo.mockResolvedValue(true);
|
|
91
|
-
await
|
|
92
|
-
expect(mockedGetConfigForPlatformVersion).toHaveBeenCalledWith('
|
|
91
|
+
await v2AddComponent(mockArgs, projectDir, mockProjectConfig, mockAccountId);
|
|
92
|
+
expect(mockedGetConfigForPlatformVersion).toHaveBeenCalledWith('2025.2');
|
|
93
93
|
expect(mockedGetProjectMetadata).toHaveBeenCalledWith('/path/to/project/src');
|
|
94
|
-
expect(
|
|
94
|
+
expect(mockedProjectAddPromptV2).toHaveBeenCalled();
|
|
95
95
|
expect(mockedTrackCommandUsage).toHaveBeenCalledWith('project-add', {
|
|
96
96
|
type: 'module',
|
|
97
97
|
}, mockAccountId);
|
|
98
98
|
expect(mockedCloneGithubRepo).toHaveBeenCalledWith(expect.any(String), projectDir, expect.objectContaining({
|
|
99
|
-
sourceDir: ['
|
|
99
|
+
sourceDir: ['2025.2/test-component'],
|
|
100
100
|
hideLogs: true,
|
|
101
101
|
branch: 'main',
|
|
102
102
|
}));
|
|
@@ -116,15 +116,15 @@ describe('lib/projects/add/v3AddComponent', () => {
|
|
|
116
116
|
mockedGetConfigForPlatformVersion.mockResolvedValue(mockConfig);
|
|
117
117
|
mockedGetProjectMetadata.mockResolvedValue(mockProjectMetadataNoApps);
|
|
118
118
|
mockedConfirmPrompt.mockResolvedValue(true);
|
|
119
|
-
|
|
119
|
+
mockedProjectAddPromptV2.mockResolvedValue(mockPromptResponse);
|
|
120
120
|
mockedCloneGithubRepo.mockResolvedValue(true);
|
|
121
|
-
await
|
|
122
|
-
expect(
|
|
121
|
+
await v2AddComponent(mockArgs, projectDir, mockProjectConfig, mockAccountId);
|
|
122
|
+
expect(mockedCreateV2App).toHaveBeenCalled();
|
|
123
123
|
expect(mockedTrackCommandUsage).toHaveBeenCalledWith('project-add', {
|
|
124
124
|
type: 'module',
|
|
125
125
|
}, mockAccountId);
|
|
126
126
|
expect(mockedCloneGithubRepo).toHaveBeenCalledWith(expect.any(String), projectDir, expect.objectContaining({
|
|
127
|
-
sourceDir: ['
|
|
127
|
+
sourceDir: ['2025.2/test-component', '2025.2/app-template'],
|
|
128
128
|
}));
|
|
129
129
|
});
|
|
130
130
|
it('should not call clone', async () => {
|
|
@@ -145,10 +145,10 @@ describe('lib/projects/add/v3AddComponent', () => {
|
|
|
145
145
|
mockedGetConfigForPlatformVersion.mockResolvedValue(mockConfig);
|
|
146
146
|
mockedGetProjectMetadata.mockResolvedValue(mockProjectMetadataNoApps);
|
|
147
147
|
mockedConfirmPrompt.mockResolvedValue(true);
|
|
148
|
-
|
|
148
|
+
mockedProjectAddPromptV2.mockResolvedValue(mockPromptResponse);
|
|
149
149
|
mockedCloneGithubRepo.mockResolvedValue(true);
|
|
150
|
-
await
|
|
151
|
-
expect(
|
|
150
|
+
await v2AddComponent(mockArgs, projectDir, mockProjectConfig, mockAccountId);
|
|
151
|
+
expect(mockedCreateV2App).not.toHaveBeenCalled();
|
|
152
152
|
expect(mockedTrackCommandUsage).toHaveBeenCalledWith('project-add', {
|
|
153
153
|
type: '',
|
|
154
154
|
}, mockAccountId);
|
|
@@ -164,7 +164,7 @@ describe('lib/projects/add/v3AddComponent', () => {
|
|
|
164
164
|
};
|
|
165
165
|
mockedGetConfigForPlatformVersion.mockResolvedValue(mockConfig);
|
|
166
166
|
mockedGetProjectMetadata.mockResolvedValue(mockProjectMetadataMaxApps);
|
|
167
|
-
await expect(
|
|
167
|
+
await expect(v2AddComponent(mockArgs, projectDir, mockProjectConfig, mockAccountId)).rejects.toThrow('This project currently has the maximum number of apps: 1');
|
|
168
168
|
});
|
|
169
169
|
it('throws an error when components list is empty', async () => {
|
|
170
170
|
const mockEmptyConfig = {
|
|
@@ -172,7 +172,7 @@ describe('lib/projects/add/v3AddComponent', () => {
|
|
|
172
172
|
parentComponents: [],
|
|
173
173
|
};
|
|
174
174
|
mockedGetConfigForPlatformVersion.mockResolvedValue(mockEmptyConfig);
|
|
175
|
-
await expect(
|
|
175
|
+
await expect(v2AddComponent(mockArgs, projectDir, mockProjectConfig, mockAccountId)).rejects.toThrow(commands.project.add.error.failedToFetchComponentList);
|
|
176
176
|
});
|
|
177
177
|
it('throws an error when app meta file cannot be parsed', async () => {
|
|
178
178
|
mockedGetConfigForPlatformVersion.mockResolvedValue(mockConfig);
|
|
@@ -180,7 +180,7 @@ describe('lib/projects/add/v3AddComponent', () => {
|
|
|
180
180
|
mockedFs.readFileSync.mockImplementation(() => {
|
|
181
181
|
throw new Error('File read error');
|
|
182
182
|
});
|
|
183
|
-
await expect(
|
|
183
|
+
await expect(v2AddComponent(mockArgs, projectDir, mockProjectConfig, mockAccountId)).rejects.toThrow('Unable to parse app file');
|
|
184
184
|
});
|
|
185
185
|
it('throws an error when cloning fails', async () => {
|
|
186
186
|
const mockAppMeta = {
|
|
@@ -195,9 +195,9 @@ describe('lib/projects/add/v3AddComponent', () => {
|
|
|
195
195
|
mockedGetConfigForPlatformVersion.mockResolvedValue(mockConfig);
|
|
196
196
|
mockedGetProjectMetadata.mockResolvedValue(mockProjectMetadata);
|
|
197
197
|
mockedFs.readFileSync.mockReturnValue(JSON.stringify(mockAppMeta));
|
|
198
|
-
|
|
198
|
+
mockedProjectAddPromptV2.mockResolvedValue(mockPromptResponse);
|
|
199
199
|
mockedCloneGithubRepo.mockRejectedValue(new Error('Clone failed'));
|
|
200
|
-
await expect(
|
|
200
|
+
await expect(v2AddComponent(mockArgs, projectDir, mockProjectConfig, mockAccountId)).rejects.toThrow(commands.project.add.error.failedToDownloadComponent);
|
|
201
201
|
});
|
|
202
202
|
it('should track usage with multiple component types', async () => {
|
|
203
203
|
const mockAppMeta = {
|
|
@@ -219,9 +219,9 @@ describe('lib/projects/add/v3AddComponent', () => {
|
|
|
219
219
|
mockedGetConfigForPlatformVersion.mockResolvedValue(mockConfig);
|
|
220
220
|
mockedGetProjectMetadata.mockResolvedValue(mockProjectMetadata);
|
|
221
221
|
mockedFs.readFileSync.mockReturnValue(JSON.stringify(mockAppMeta));
|
|
222
|
-
|
|
222
|
+
mockedProjectAddPromptV2.mockResolvedValue(mockPromptResponse);
|
|
223
223
|
mockedCloneGithubRepo.mockResolvedValue(true);
|
|
224
|
-
await
|
|
224
|
+
await v2AddComponent(mockArgs, projectDir, mockProjectConfig, mockAccountId);
|
|
225
225
|
expect(mockedTrackCommandUsage).toHaveBeenCalledWith('project-add', {
|
|
226
226
|
type: 'module,card',
|
|
227
227
|
}, mockAccountId);
|
|
@@ -243,8 +243,8 @@ describe('lib/projects/add/v3AddComponent', () => {
|
|
|
243
243
|
};
|
|
244
244
|
mockedGetConfigForPlatformVersion.mockResolvedValue(mockConfig);
|
|
245
245
|
mockedGetProjectMetadata.mockResolvedValue(mockProjectMetadataNoApps);
|
|
246
|
-
|
|
247
|
-
await
|
|
246
|
+
mockedProjectAddPromptV2.mockResolvedValue(mockPromptResponse);
|
|
247
|
+
await v2AddComponent(mockArgs, projectDir, mockProjectConfig, mockAccountId);
|
|
248
248
|
expect(mockedTrackCommandUsage).toHaveBeenCalledWith('project-add', {
|
|
249
249
|
type: '',
|
|
250
250
|
}, mockAccountId);
|
|
@@ -270,9 +270,9 @@ describe('lib/projects/add/v3AddComponent', () => {
|
|
|
270
270
|
mockedGetConfigForPlatformVersion.mockResolvedValue(mockConfig);
|
|
271
271
|
mockedGetProjectMetadata.mockResolvedValue(mockProjectMetadata);
|
|
272
272
|
mockedFs.readFileSync.mockReturnValue(JSON.stringify(mockAppMeta));
|
|
273
|
-
|
|
273
|
+
mockedProjectAddPromptV2.mockResolvedValue(mockPromptResponse);
|
|
274
274
|
mockedCloneGithubRepo.mockResolvedValue(true);
|
|
275
|
-
await
|
|
275
|
+
await v2AddComponent(mockArgs, projectDir, mockProjectConfig, mockAccountId);
|
|
276
276
|
expect(mockedTrackCommandUsage).toHaveBeenCalledWith('project-add', {
|
|
277
277
|
type: 'workflow-action-tool',
|
|
278
278
|
}, mockAccountId);
|
|
@@ -308,9 +308,9 @@ describe('lib/projects/add/v3AddComponent', () => {
|
|
|
308
308
|
mockedGetConfigForPlatformVersion.mockResolvedValue(mockConfig);
|
|
309
309
|
mockedGetProjectMetadata.mockResolvedValue(mockProjectMetadata);
|
|
310
310
|
mockedFs.readFileSync.mockReturnValue(JSON.stringify(mockAppMeta));
|
|
311
|
-
|
|
311
|
+
mockedProjectAddPromptV2.mockResolvedValue(mockPromptResponse);
|
|
312
312
|
mockedCloneGithubRepo.mockResolvedValue(true);
|
|
313
|
-
await
|
|
313
|
+
await v2AddComponent(mockArgs, projectDir, mockProjectConfig, mockAccountId);
|
|
314
314
|
expect(mockedTrackCommandUsage).toHaveBeenCalledWith('project-add', {
|
|
315
315
|
type: 'workflow-action-tool,module',
|
|
316
316
|
}, mockAccountId);
|