@hubspot/cli 7.8.12-experimental.0 → 7.8.12-experimental.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/bin/cli.js +31 -25
- package/commands/__tests__/auth.test.js +5 -0
- package/commands/__tests__/doctor.test.js +16 -16
- package/commands/account/clean.js +18 -27
- package/commands/account/createOverride.js +13 -31
- package/commands/account/info.js +20 -31
- package/commands/account/list.js +16 -22
- package/commands/account/remove.js +12 -20
- package/commands/account/removeOverride.js +11 -21
- package/commands/account/rename.js +6 -9
- package/commands/account/use.js +12 -26
- package/commands/account.js +2 -2
- package/commands/app/__tests__/migrate.test.js +5 -5
- package/commands/app/migrate.js +13 -18
- package/commands/app.js +1 -6
- package/commands/auth.d.ts +1 -0
- package/commands/auth.js +16 -7
- package/commands/cms/convertFields.js +7 -9
- package/commands/cms/getReactModule.js +9 -14
- package/commands/cms/lighthouseScore.js +33 -36
- package/commands/cms.js +2 -2
- package/commands/completion.js +3 -3
- package/commands/config/set.d.ts +1 -1
- package/commands/config/set.js +64 -36
- package/commands/config.js +2 -2
- package/commands/create.js +2 -2
- package/commands/customObject/create.js +10 -12
- package/commands/customObject/schema/create.js +9 -11
- package/commands/customObject/schema/delete.js +16 -16
- package/commands/customObject/schema/fetch-all.js +12 -11
- package/commands/customObject/schema/fetch.js +15 -15
- package/commands/customObject/schema/list.js +4 -4
- package/commands/customObject/schema/update.js +13 -13
- package/commands/customObject/schema.js +2 -2
- package/commands/customObject.js +6 -7
- package/commands/doctor.js +8 -11
- package/commands/feedback.js +6 -11
- package/commands/fetch.js +8 -8
- package/commands/filemanager/fetch.js +7 -7
- package/commands/filemanager/upload.js +15 -34
- package/commands/filemanager.js +2 -2
- package/commands/function/deploy.js +11 -29
- package/commands/function/list.js +8 -8
- package/commands/function/server.js +9 -11
- package/commands/function.d.ts +1 -1
- package/commands/function.js +2 -2
- package/commands/getStarted.js +2 -2
- package/commands/hubdb/clear.js +7 -15
- package/commands/hubdb/create.js +9 -15
- package/commands/hubdb/delete.js +8 -15
- package/commands/hubdb/fetch.js +6 -9
- package/commands/hubdb.d.ts +1 -1
- package/commands/hubdb.js +2 -2
- package/commands/init.js +2 -3
- package/commands/lint.js +16 -16
- package/commands/list.js +8 -14
- package/commands/logs.js +14 -20
- package/commands/mv.js +6 -17
- package/commands/open.js +5 -5
- package/commands/project/__tests__/add.test.js +4 -2
- package/commands/project/__tests__/deploy.test.js +3 -4
- package/commands/project/__tests__/installDeps.test.js +8 -8
- package/commands/project/__tests__/logs.test.js +1 -1
- package/commands/project/__tests__/migrate.test.js +5 -5
- package/commands/project/__tests__/migrateApp.test.js +2 -5
- package/commands/project/__tests__/validate.test.js +98 -0
- package/commands/project/add.js +3 -3
- package/commands/project/cloneApp.js +14 -19
- package/commands/project/create.js +0 -1
- package/commands/project/deploy.js +3 -3
- package/commands/project/dev/deprecatedFlow.js +7 -16
- package/commands/project/dev/index.js +14 -12
- package/commands/project/dev/unifiedFlow.js +3 -1
- package/commands/project/download.js +10 -13
- package/commands/project/installDeps.js +8 -8
- package/commands/project/listBuilds.js +11 -20
- package/commands/project/logs.js +21 -24
- package/commands/project/migrateApp.js +9 -15
- package/commands/project/open.js +6 -13
- package/commands/project/upload.d.ts +2 -2
- package/commands/project/upload.js +17 -26
- package/commands/project/validate.js +6 -6
- package/commands/project/watch.js +13 -22
- package/commands/project.js +2 -2
- package/commands/sandbox/__tests__/create.test.js +5 -5
- package/commands/sandbox/create.js +22 -32
- package/commands/sandbox/delete.js +38 -63
- package/commands/sandbox.js +2 -2
- package/commands/secret/addSecret.js +7 -17
- package/commands/secret/deleteSecret.js +10 -20
- package/commands/secret/listSecret.js +8 -10
- package/commands/secret/updateSecret.js +9 -17
- package/commands/secret.js +2 -2
- package/commands/testAccount/__tests__/delete.test.js +2 -4
- package/commands/testAccount/create.js +0 -3
- package/commands/testAccount/delete.d.ts +4 -3
- package/commands/testAccount/delete.js +155 -14
- package/commands/theme/preview.js +1 -4
- package/lang/en.d.ts +310 -124
- package/lang/en.js +351 -169
- package/lang/en.lyaml +2 -2
- package/lib/__tests__/buildAccount.test.js +2 -1
- package/lib/__tests__/commonOpts.test.js +1 -1
- package/lib/__tests__/dependencyManagement.test.js +1 -1
- package/lib/__tests__/developerTestAccounts.test.js +3 -3
- package/lib/__tests__/npm.test.js +1 -1
- package/lib/__tests__/oauth.test.js +4 -4
- package/lib/__tests__/process.test.js +10 -5
- package/lib/__tests__/sandboxSync.test.js +8 -8
- package/lib/__tests__/sandboxes.test.js +8 -8
- package/lib/__tests__/serverlessLogs.test.js +1 -1
- package/lib/__tests__/usageTracking.test.js +5 -5
- package/lib/__tests__/validation.test.js +2 -1
- package/lib/__tests__/yargsUtils.test.js +83 -9
- package/lib/app/__tests__/migrate.test.js +5 -5
- package/lib/app/__tests__/migrate_legacy.test.js +1 -1
- package/lib/app/migrate.js +1 -1
- package/lib/app/migrate_legacy.js +20 -24
- package/lib/buildAccount.js +25 -57
- package/lib/commonOpts.d.ts +1 -1
- package/lib/commonOpts.js +25 -22
- package/lib/configOptions.js +7 -0
- package/lib/constants.d.ts +6 -1
- package/lib/constants.js +10 -1
- package/lib/dependencyManagement.js +9 -27
- package/lib/developerTestAccounts.js +9 -23
- package/lib/doctor/Diagnosis.js +11 -23
- package/lib/doctor/DiagnosticInfoBuilder.js +12 -11
- package/lib/doctor/Doctor.js +42 -90
- package/lib/doctor/__tests__/Doctor.test.js +4 -4
- package/lib/errorHandlers/index.js +12 -20
- package/lib/errorHandlers/suppressError.js +11 -18
- package/lib/lang.js +6 -5
- package/lib/links.js +4 -4
- package/lib/middleware/__test__/commandTargetingUtils.test.js +99 -0
- package/lib/middleware/__test__/configMiddleware.test.js +11 -11
- package/lib/middleware/__test__/yargsChecksMiddleware.test.js +6 -8
- package/lib/middleware/commandTargetingUtils.d.ts +8 -0
- package/lib/middleware/commandTargetingUtils.js +78 -0
- package/lib/middleware/configMiddleware.d.ts +1 -1
- package/lib/middleware/configMiddleware.js +21 -81
- package/lib/middleware/gitMiddleware.js +5 -1
- package/lib/middleware/notificationsMiddleware.js +5 -11
- package/lib/middleware/yargsChecksMiddleware.js +6 -9
- package/lib/npm.js +2 -2
- package/lib/oauth.js +5 -5
- package/lib/process.js +5 -4
- package/lib/projectProfiles.d.ts +1 -1
- package/lib/projectProfiles.js +2 -10
- package/lib/projects/__tests__/AppDevModeInterface.test.js +14 -34
- package/lib/projects/__tests__/LocalDevWebsocketServer.test.js +70 -39
- package/lib/projects/__tests__/localDevProjectHelpers.test.js +2 -0
- package/lib/projects/__tests__/platformVersion.test.js +8 -8
- package/lib/projects/__tests__/projects.test.js +12 -12
- package/lib/projects/__tests__/structure.test.js +3 -3
- package/lib/projects/__tests__/upload.test.d.ts +1 -0
- package/lib/projects/__tests__/upload.test.js +82 -0
- package/lib/projects/add/__tests__/legacyAddComponent.test.js +6 -6
- package/lib/projects/add/__tests__/v3AddComponent.test.js +4 -4
- package/lib/projects/create/__tests__/legacy.test.js +5 -5
- package/lib/projects/create/__tests__/v3.test.js +1 -1
- package/lib/projects/create/index.js +2 -2
- package/lib/projects/create/legacy.js +2 -2
- package/lib/projects/create/v3.js +2 -2
- package/lib/projects/localDev/AppDevModeInterface.d.ts +2 -0
- package/lib/projects/localDev/AppDevModeInterface.js +22 -20
- package/lib/projects/localDev/LocalDevLogger.js +10 -11
- package/lib/projects/localDev/LocalDevManager.js +4 -5
- package/lib/projects/localDev/LocalDevWebsocketServer.d.ts +0 -1
- package/lib/projects/localDev/LocalDevWebsocketServer.js +7 -10
- package/lib/projects/localDev/helpers/project.d.ts +1 -0
- package/lib/projects/localDev/helpers/project.js +37 -0
- package/lib/projects/platformVersion.d.ts +1 -1
- package/lib/projects/platformVersion.js +1 -1
- package/lib/projects/structure.d.ts +2 -2
- package/lib/projects/structure.js +6 -6
- package/lib/projects/upload.d.ts +2 -3
- package/lib/projects/upload.js +17 -9
- package/lib/prompts/__tests__/downloadProjectPrompt.test.js +1 -0
- package/lib/prompts/accountNamePrompt.js +14 -19
- package/lib/prompts/accountsPrompt.js +2 -2
- package/lib/prompts/cmsFieldPrompt.js +2 -2
- package/lib/prompts/createApiSamplePrompt.js +5 -5
- package/lib/prompts/createDeveloperTestAccountConfigPrompt.js +10 -1
- package/lib/prompts/createFunctionPrompt.js +14 -14
- package/lib/prompts/createModulePrompt.js +9 -9
- package/lib/prompts/createTemplatePrompt.js +2 -2
- package/lib/prompts/downloadProjectPrompt.js +5 -8
- package/lib/prompts/personalAccessKeyPrompt.js +3 -3
- package/lib/prompts/previewPrompt.js +6 -6
- package/lib/prompts/projectAddPrompt.js +6 -0
- package/lib/prompts/projectDevTargetAccountPrompt.js +20 -32
- package/lib/prompts/projectNamePrompt.js +4 -8
- package/lib/prompts/projectsLogsPrompt.js +2 -4
- package/lib/prompts/promptUtils.js +27 -9
- package/lib/prompts/sandboxesPrompt.js +7 -7
- package/lib/prompts/secretPrompt.js +3 -3
- package/lib/prompts/selectAppPrompt.js +3 -3
- package/lib/prompts/selectHubDBTablePrompt.js +9 -13
- package/lib/prompts/selectPublicAppForMigrationPrompt.js +15 -19
- package/lib/prompts/setAsDefaultAccountPrompt.js +4 -8
- package/lib/prompts/uploadPrompt.js +5 -5
- package/lib/sandboxSync.js +24 -41
- package/lib/sandboxes.js +19 -47
- package/lib/schema.js +3 -3
- package/lib/serverlessLogs.js +11 -13
- package/lib/theme/__tests__/migrate.test.js +3 -3
- package/lib/theme/migrate.js +2 -2
- package/lib/ui/SpinniesManager.d.ts +2 -0
- package/lib/ui/SpinniesManager.js +7 -0
- package/lib/ui/boxen.js +1 -2
- package/lib/ui/git.js +13 -10
- package/lib/ui/index.d.ts +4 -0
- package/lib/ui/index.js +47 -38
- package/lib/ui/serverlessFunctionLogs.js +9 -7
- package/lib/ui/uiMessages.d.ts +68 -0
- package/lib/ui/uiMessages.js +71 -0
- package/lib/usageTracking.js +7 -7
- package/lib/validation.js +20 -23
- package/lib/yargsUtils.d.ts +1 -1
- package/lib/yargsUtils.js +12 -5
- package/mcp-server/tools/cms/HsCreateModuleTool.d.ts +2 -2
- package/mcp-server/tools/index.js +4 -0
- package/mcp-server/tools/project/GetApiUsagePatternsByAppIdTool.d.ts +23 -0
- package/mcp-server/tools/project/GetApiUsagePatternsByAppIdTool.js +68 -0
- package/mcp-server/tools/project/GetApplicationInfoTool.d.ts +11 -0
- package/mcp-server/tools/project/GetApplicationInfoTool.js +49 -0
- package/mcp-server/tools/project/GetConfigValuesTool.js +2 -2
- package/mcp-server/tools/project/GuidedWalkthroughTool.d.ts +2 -2
- package/mcp-server/tools/project/__tests__/GetApiUsagePatternsByAppIdTool.test.d.ts +1 -0
- package/mcp-server/tools/project/__tests__/GetApiUsagePatternsByAppIdTool.test.js +169 -0
- package/mcp-server/tools/project/__tests__/GetApplicationInfoTool.test.d.ts +1 -0
- package/mcp-server/tools/project/__tests__/GetApplicationInfoTool.test.js +115 -0
- package/mcp-server/utils/toolUsageTracking.js +2 -2
- package/package.json +6 -6
- package/types/Yargs.d.ts +1 -1
- package/commands/app/__tests__/install.test.js +0 -47
- package/commands/app/install.d.ts +0 -8
- package/commands/app/install.js +0 -122
- package/lib/middleware/__test__/utils.test.js +0 -51
- package/lib/middleware/utils.d.ts +0 -8
- package/lib/middleware/utils.js +0 -14
- /package/commands/{app/__tests__/install.test.d.ts → project/__tests__/validate.test.d.ts} +0 -0
- /package/lib/middleware/__test__/{utils.test.d.ts → commandTargetingUtils.test.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';
|
|
@@ -67,6 +67,8 @@ describe('AppDevModeInterface', () => {
|
|
|
67
67
|
componentRoot: '/test/path',
|
|
68
68
|
componentConfigPath: '/test/path/config.json',
|
|
69
69
|
configUpdatedSinceLastUpload: false,
|
|
70
|
+
removed: false,
|
|
71
|
+
parsingErrors: [],
|
|
70
72
|
},
|
|
71
73
|
componentDeps: {},
|
|
72
74
|
metaFilePath: '/test/path',
|
|
@@ -107,8 +109,8 @@ describe('AppDevModeInterface', () => {
|
|
|
107
109
|
LocalDevState.mockImplementation(() => mockLocalDevState);
|
|
108
110
|
LocalDevLogger.mockImplementation(() => mockLocalDevLogger);
|
|
109
111
|
// Mock external dependencies
|
|
110
|
-
|
|
111
|
-
data:
|
|
112
|
+
fetchAppMetadataByUid.mockResolvedValue({
|
|
113
|
+
data: mockPublicApp,
|
|
112
114
|
});
|
|
113
115
|
fetchPublicAppProductionInstallCounts.mockResolvedValue({
|
|
114
116
|
data: { uniquePortalInstallCount: 5 },
|
|
@@ -189,12 +191,12 @@ describe('AppDevModeInterface', () => {
|
|
|
189
191
|
it('should return early if no app node exists', async () => {
|
|
190
192
|
mockLocalDevState.projectNodes = {};
|
|
191
193
|
await appDevModeInterface.setup({});
|
|
192
|
-
expect(
|
|
194
|
+
expect(fetchAppMetadataByUid).not.toHaveBeenCalled();
|
|
193
195
|
expect(UIEDevModeInterface.setup).not.toHaveBeenCalled();
|
|
194
196
|
});
|
|
195
197
|
it('should setup successfully with private app', async () => {
|
|
196
198
|
await appDevModeInterface.setup({});
|
|
197
|
-
expect(
|
|
199
|
+
expect(fetchAppMetadataByUid).toHaveBeenCalledWith('test-app-uid', 12345);
|
|
198
200
|
expect(fetchPublicAppProductionInstallCounts).toHaveBeenCalledWith(123, 12345);
|
|
199
201
|
expect(fetchAppInstallationData).toHaveBeenCalledWith(67890, 999, 'test-app-uid', ['test-scope'], []);
|
|
200
202
|
expect(UIEDevModeInterface.setup).toHaveBeenCalled();
|
|
@@ -302,32 +304,10 @@ describe('AppDevModeInterface', () => {
|
|
|
302
304
|
});
|
|
303
305
|
it('should handle errors during setup', async () => {
|
|
304
306
|
const error = new Error('Setup failed');
|
|
305
|
-
|
|
307
|
+
fetchAppMetadataByUid.mockRejectedValue(error);
|
|
306
308
|
await appDevModeInterface.setup({});
|
|
307
309
|
expect(logError).toHaveBeenCalledWith(error);
|
|
308
310
|
});
|
|
309
|
-
it('should exit if app not found in portal', async () => {
|
|
310
|
-
// Set up conditions for non-automatic installation to force getAppInstallUrl call
|
|
311
|
-
getAccountConfig.mockReturnValue(null);
|
|
312
|
-
// First call for fetchAppData succeeds
|
|
313
|
-
fetchPublicAppsForPortal
|
|
314
|
-
.mockResolvedValueOnce({
|
|
315
|
-
data: { results: [mockPublicApp] },
|
|
316
|
-
})
|
|
317
|
-
// Second call for getAppInstallUrl fails (app not found)
|
|
318
|
-
.mockResolvedValueOnce({
|
|
319
|
-
data: { results: [] },
|
|
320
|
-
});
|
|
321
|
-
fetchAppInstallationData.mockResolvedValue({
|
|
322
|
-
data: {
|
|
323
|
-
isInstalledWithScopeGroups: false,
|
|
324
|
-
previouslyAuthorizedScopeGroups: [],
|
|
325
|
-
},
|
|
326
|
-
});
|
|
327
|
-
// The setup method catches the error, so we check that process.exit was called
|
|
328
|
-
await appDevModeInterface.setup({});
|
|
329
|
-
expect(process.exit).toHaveBeenCalledWith(1);
|
|
330
|
-
});
|
|
331
311
|
// @TODO: Restore test account auto install functionality
|
|
332
312
|
// it('should exit if user declines auto-install', async () => {
|
|
333
313
|
// // Set up conditions for automatic installation
|
|
@@ -424,8 +404,8 @@ describe('AppDevModeInterface', () => {
|
|
|
424
404
|
// Reset mocks to ensure clean state
|
|
425
405
|
vi.clearAllMocks();
|
|
426
406
|
// Set up basic mocks
|
|
427
|
-
|
|
428
|
-
data:
|
|
407
|
+
fetchAppMetadataByUid.mockResolvedValue({
|
|
408
|
+
data: mockPublicApp,
|
|
429
409
|
});
|
|
430
410
|
fetchPublicAppProductionInstallCounts.mockResolvedValue({
|
|
431
411
|
data: { uniquePortalInstallCount: 5 },
|
|
@@ -457,8 +437,8 @@ describe('AppDevModeInterface', () => {
|
|
|
457
437
|
// Reset mocks to ensure clean state
|
|
458
438
|
vi.clearAllMocks();
|
|
459
439
|
// Set up basic mocks
|
|
460
|
-
|
|
461
|
-
data:
|
|
440
|
+
fetchAppMetadataByUid.mockResolvedValue({
|
|
441
|
+
data: mockPublicApp,
|
|
462
442
|
});
|
|
463
443
|
fetchPublicAppProductionInstallCounts.mockResolvedValue({
|
|
464
444
|
data: { uniquePortalInstallCount: 5 },
|
|
@@ -501,8 +481,8 @@ describe('AppDevModeInterface', () => {
|
|
|
501
481
|
// Reset mocks to ensure clean state
|
|
502
482
|
vi.clearAllMocks();
|
|
503
483
|
// Set up basic mocks
|
|
504
|
-
|
|
505
|
-
data:
|
|
484
|
+
fetchAppMetadataByUid.mockResolvedValue({
|
|
485
|
+
data: mockPublicApp,
|
|
506
486
|
});
|
|
507
487
|
fetchPublicAppProductionInstallCounts.mockResolvedValue({
|
|
508
488
|
data: { uniquePortalInstallCount: 5 },
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { WebSocketServer } from 'ws';
|
|
2
2
|
import { isPortManagerServerRunning, requestPorts, } from '@hubspot/local-dev-lib/portManager';
|
|
3
|
-
import {
|
|
3
|
+
import { uiLogger } from '../../ui/logger.js';
|
|
4
4
|
import { LOCAL_DEV_UI_MESSAGE_RECEIVE_TYPES, LOCAL_DEV_UI_MESSAGE_SEND_TYPES, LOCAL_DEV_SERVER_MESSAGE_TYPES, } from '../../constants.js';
|
|
5
5
|
import LocalDevWebsocketServer from '../localDev/LocalDevWebsocketServer.js';
|
|
6
6
|
import { lib } from '../../../lang/en.js';
|
|
7
7
|
vi.mock('ws');
|
|
8
8
|
vi.mock('@hubspot/local-dev-lib/portManager');
|
|
9
|
-
vi.mock('
|
|
9
|
+
vi.mock('../../ui/logger.js');
|
|
10
10
|
describe('LocalDevWebsocketServer', () => {
|
|
11
11
|
let mockLocalDevProcess;
|
|
12
12
|
let mockWebSocket;
|
|
@@ -59,39 +59,68 @@ describe('LocalDevWebsocketServer', () => {
|
|
|
59
59
|
await server.start();
|
|
60
60
|
expect(WebSocketServer).toHaveBeenCalledWith({ port: 1234 });
|
|
61
61
|
expect(mockWebSocketServer.on).toHaveBeenCalledWith('connection', expect.any(Function));
|
|
62
|
-
expect(
|
|
62
|
+
expect(uiLogger.log).toHaveBeenCalled();
|
|
63
63
|
});
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
'
|
|
64
|
+
describe('valid origins', () => {
|
|
65
|
+
const validOrigins = [
|
|
66
|
+
'https://app.hubspot.com',
|
|
67
|
+
'https://app.hubspotqa.com',
|
|
68
|
+
'https://local.hubspot.com',
|
|
69
|
+
'https://local.hubspotqa.com',
|
|
70
|
+
'https://app-na2.hubspot.com',
|
|
71
|
+
'https://app-na2.hubspotqa.com',
|
|
72
|
+
'https://app-na3.hubspot.com',
|
|
73
|
+
'https://app-na3.hubspotqa.com',
|
|
74
|
+
'https://app-ap1.hubspot.com',
|
|
75
|
+
'https://app-ap1.hubspotqa.com',
|
|
76
|
+
'https://app-eu1.hubspot.com',
|
|
77
|
+
'https://app-eu1.hubspotqa.com',
|
|
78
|
+
];
|
|
79
|
+
validOrigins.forEach(origin => {
|
|
80
|
+
it(`should accept connection from ${origin}`, async () => {
|
|
81
|
+
isPortManagerServerRunning.mockResolvedValue(true);
|
|
82
|
+
requestPorts.mockResolvedValue({
|
|
83
|
+
'local-dev-ui-websocket-server': 1234,
|
|
84
|
+
});
|
|
85
|
+
await server.start();
|
|
86
|
+
// Get the connection callback
|
|
87
|
+
const connectionCallback = mockWebSocketServer.on.mock
|
|
88
|
+
.calls[0][1];
|
|
89
|
+
// Simulate connection from valid origin
|
|
90
|
+
connectionCallback(mockWebSocket, {
|
|
91
|
+
headers: { origin },
|
|
92
|
+
});
|
|
93
|
+
expect(mockWebSocket.on).toHaveBeenCalledWith('message', expect.any(Function));
|
|
94
|
+
expect(mockLocalDevProcess.addStateListener).toHaveBeenCalledWith('projectNodes', expect.any(Function));
|
|
95
|
+
expect(mockWebSocket.close).not.toHaveBeenCalled();
|
|
96
|
+
});
|
|
68
97
|
});
|
|
69
|
-
await server.start();
|
|
70
|
-
// Get the connection callback
|
|
71
|
-
const connectionCallback = mockWebSocketServer.on.mock.calls[0][1];
|
|
72
|
-
// Simulate connection from valid origin
|
|
73
|
-
connectionCallback(mockWebSocket, {
|
|
74
|
-
headers: { origin: 'https://app.hubspot.com' },
|
|
75
|
-
});
|
|
76
|
-
expect(mockWebSocket.on).toHaveBeenCalledWith('message', expect.any(Function));
|
|
77
|
-
expect(mockLocalDevProcess.addStateListener).toHaveBeenCalledWith('projectNodes', expect.any(Function));
|
|
78
|
-
expect(mockWebSocket.close).not.toHaveBeenCalled();
|
|
79
98
|
});
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
'
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
99
|
+
describe('invalid origins', () => {
|
|
100
|
+
const invalidOrigins = [
|
|
101
|
+
'https://malicious-site.com',
|
|
102
|
+
'https://app.malicious-site.com',
|
|
103
|
+
'https://app.hubspot.com.evil.com',
|
|
104
|
+
];
|
|
105
|
+
invalidOrigins.forEach(origin => {
|
|
106
|
+
it(`should reject connection from "${origin}"`, async () => {
|
|
107
|
+
isPortManagerServerRunning.mockResolvedValue(true);
|
|
108
|
+
requestPorts.mockResolvedValue({
|
|
109
|
+
'local-dev-ui-websocket-server': 1234,
|
|
110
|
+
});
|
|
111
|
+
await server.start();
|
|
112
|
+
// Get the connection callback
|
|
113
|
+
const connectionCallback = mockWebSocketServer.on.mock
|
|
114
|
+
.calls[0][1];
|
|
115
|
+
// Simulate connection from invalid origin
|
|
116
|
+
connectionCallback(mockWebSocket, {
|
|
117
|
+
headers: { origin },
|
|
118
|
+
});
|
|
119
|
+
expect(mockWebSocket.close).toHaveBeenCalledWith(1008, lib.LocalDevWebsocketServer.errors.originNotAllowed(origin));
|
|
120
|
+
expect(mockWebSocket.on).not.toHaveBeenCalled();
|
|
121
|
+
expect(mockLocalDevProcess.addStateListener).not.toHaveBeenCalled();
|
|
122
|
+
});
|
|
91
123
|
});
|
|
92
|
-
expect(mockWebSocket.close).toHaveBeenCalledWith(1008, lib.LocalDevWebsocketServer.errors.originNotAllowed('https://malicious-site.com'));
|
|
93
|
-
expect(mockWebSocket.on).not.toHaveBeenCalled();
|
|
94
|
-
expect(mockLocalDevProcess.addStateListener).not.toHaveBeenCalled();
|
|
95
124
|
});
|
|
96
125
|
it('should reject connection with no origin header', async () => {
|
|
97
126
|
isPortManagerServerRunning.mockResolvedValue(true);
|
|
@@ -119,7 +148,7 @@ describe('LocalDevWebsocketServer', () => {
|
|
|
119
148
|
const connectionCallback = mockWebSocketServer.on.mock.calls[0][1];
|
|
120
149
|
// Simulate connection from valid origin
|
|
121
150
|
connectionCallback(mockWebSocket, {
|
|
122
|
-
headers: { origin: 'https://app.hubspot.com' },
|
|
151
|
+
headers: { origin: 'https://app-na3.hubspot.com' },
|
|
123
152
|
});
|
|
124
153
|
expect(mockLocalDevProcess.sendDevServerMessage).toHaveBeenCalledWith(LOCAL_DEV_SERVER_MESSAGE_TYPES.WEBSOCKET_SERVER_CONNECTED);
|
|
125
154
|
});
|
|
@@ -148,7 +177,7 @@ describe('LocalDevWebsocketServer', () => {
|
|
|
148
177
|
const messageCallback = mockWebSocket.on.mock.calls[0][1];
|
|
149
178
|
const message = {};
|
|
150
179
|
messageCallback(JSON.stringify(message));
|
|
151
|
-
expect(
|
|
180
|
+
expect(uiLogger.error).toHaveBeenCalled();
|
|
152
181
|
});
|
|
153
182
|
it('should log error for unknown message type', () => {
|
|
154
183
|
const messageCallback = mockWebSocket.on.mock.calls[0][1];
|
|
@@ -156,13 +185,13 @@ describe('LocalDevWebsocketServer', () => {
|
|
|
156
185
|
type: 'UNKNOWN_TYPE',
|
|
157
186
|
};
|
|
158
187
|
messageCallback(JSON.stringify(message));
|
|
159
|
-
expect(
|
|
188
|
+
expect(uiLogger.error).toHaveBeenCalled();
|
|
160
189
|
});
|
|
161
190
|
it('should log error for invalid JSON', () => {
|
|
162
191
|
const messageCallback = mockWebSocket.on.mock.calls[0][1];
|
|
163
192
|
const invalidJson = 'invalid json';
|
|
164
193
|
messageCallback(invalidJson);
|
|
165
|
-
expect(
|
|
194
|
+
expect(uiLogger.error).toHaveBeenCalled();
|
|
166
195
|
});
|
|
167
196
|
});
|
|
168
197
|
describe('shutdown()', () => {
|
|
@@ -213,7 +242,7 @@ describe('LocalDevWebsocketServer', () => {
|
|
|
213
242
|
headers: { origin: 'https://app.hubspot.com' },
|
|
214
243
|
});
|
|
215
244
|
connectionCallback(mockWebSocket2, {
|
|
216
|
-
headers: { origin: 'https://app.hubspotqa.com' },
|
|
245
|
+
headers: { origin: 'https://app-na2.hubspotqa.com' },
|
|
217
246
|
});
|
|
218
247
|
connectionCallback(mockWebSocket3, {
|
|
219
248
|
headers: { origin: 'https://local.hubspot.com' },
|
|
@@ -238,7 +267,7 @@ describe('LocalDevWebsocketServer', () => {
|
|
|
238
267
|
headers: { origin: 'https://app.hubspot.com' },
|
|
239
268
|
});
|
|
240
269
|
connectionCallback(mockWebSocket2, {
|
|
241
|
-
headers: { origin: 'https://app.hubspotqa.com' },
|
|
270
|
+
headers: { origin: 'https://app-eu1.hubspotqa.com' },
|
|
242
271
|
});
|
|
243
272
|
// Each websocket should receive project data
|
|
244
273
|
expect(mockWebSocket1.send).toHaveBeenCalledWith(JSON.stringify({
|
|
@@ -270,7 +299,7 @@ describe('LocalDevWebsocketServer', () => {
|
|
|
270
299
|
headers: { origin: 'https://app.hubspot.com' },
|
|
271
300
|
});
|
|
272
301
|
connectionCallback(mockWebSocket2, {
|
|
273
|
-
headers: { origin: 'https://app.hubspotqa.com' },
|
|
302
|
+
headers: { origin: 'https://app-ap1.hubspotqa.com' },
|
|
274
303
|
});
|
|
275
304
|
// Get all the close callbacks for both connections (there should be 2 per connection)
|
|
276
305
|
const closeCallbacks1 = mockWebSocket1.on.mock.calls
|
|
@@ -296,7 +325,7 @@ describe('LocalDevWebsocketServer', () => {
|
|
|
296
325
|
headers: { origin: 'https://app.hubspot.com' },
|
|
297
326
|
});
|
|
298
327
|
connectionCallback(mockWebSocket2, {
|
|
299
|
-
headers: { origin: 'https://
|
|
328
|
+
headers: { origin: 'https://local.hubspotqa.com' },
|
|
300
329
|
});
|
|
301
330
|
// Get the projectNodes listeners that were registered
|
|
302
331
|
const projectNodesListeners = mockLocalDevProcess.addStateListener.mock.calls
|
|
@@ -312,6 +341,8 @@ describe('LocalDevWebsocketServer', () => {
|
|
|
312
341
|
componentRoot: '/test/path',
|
|
313
342
|
componentConfigPath: '/test/path/config.json',
|
|
314
343
|
configUpdatedSinceLastUpload: false,
|
|
344
|
+
removed: false,
|
|
345
|
+
parsingErrors: [],
|
|
315
346
|
},
|
|
316
347
|
componentDeps: {},
|
|
317
348
|
metaFilePath: '/test/path',
|
|
@@ -30,6 +30,8 @@ describe('isDeployedProjectUpToDateWithLocal', () => {
|
|
|
30
30
|
componentRoot: '/local/path',
|
|
31
31
|
componentConfigPath: '/local/path/config.json',
|
|
32
32
|
configUpdatedSinceLastUpload: false,
|
|
33
|
+
removed: false,
|
|
34
|
+
parsingErrors: [],
|
|
33
35
|
},
|
|
34
36
|
componentDeps: {},
|
|
35
37
|
metaFilePath: '/local/path',
|
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { isV2Project } from '../platformVersion.js';
|
|
2
2
|
describe('platformVersion', () => {
|
|
3
|
-
describe('
|
|
3
|
+
describe('isV2Project', () => {
|
|
4
4
|
it('returns true if platform version is UNSTABLE', () => {
|
|
5
|
-
expect(
|
|
5
|
+
expect(isV2Project('UNSTABLE')).toBe(true);
|
|
6
6
|
});
|
|
7
7
|
it('returns true if platform version is equal to the minimum', () => {
|
|
8
|
-
expect(
|
|
8
|
+
expect(isV2Project('2025.2')).toBe(true);
|
|
9
9
|
});
|
|
10
10
|
it('returns true if platform version is greater than the minimum', () => {
|
|
11
|
-
expect(
|
|
11
|
+
expect(isV2Project('2026.2')).toBe(true);
|
|
12
12
|
});
|
|
13
13
|
it('returns false if platform version is less than the minimum', () => {
|
|
14
|
-
expect(
|
|
14
|
+
expect(isV2Project('2025.0')).toBe(false);
|
|
15
15
|
});
|
|
16
16
|
it('returns false if platform version is invalid', () => {
|
|
17
|
-
expect(
|
|
17
|
+
expect(isV2Project(null)).toBe(false);
|
|
18
18
|
});
|
|
19
19
|
it('returns false for an invalid platform version', () => {
|
|
20
|
-
expect(
|
|
20
|
+
expect(isV2Project('notplaformversion')).toBe(false);
|
|
21
21
|
});
|
|
22
22
|
});
|
|
23
23
|
});
|
|
@@ -3,8 +3,8 @@ import os from 'os';
|
|
|
3
3
|
import path from 'path';
|
|
4
4
|
import { EXIT_CODES } from '../../enums/exitCodes.js';
|
|
5
5
|
import { validateProjectConfig } from '../../projects/config.js';
|
|
6
|
-
import {
|
|
7
|
-
vi.mock('
|
|
6
|
+
import { uiLogger } from '../../ui/logger.js';
|
|
7
|
+
vi.mock('../../ui/logger.js');
|
|
8
8
|
describe('lib/projects', () => {
|
|
9
9
|
describe('validateProjectConfig()', () => {
|
|
10
10
|
let projectDir;
|
|
@@ -26,58 +26,58 @@ describe('lib/projects', () => {
|
|
|
26
26
|
// @ts-ignore Testing invalid input
|
|
27
27
|
validateProjectConfig(null, projectDir);
|
|
28
28
|
expect(exitMock).toHaveBeenCalledWith(EXIT_CODES.ERROR);
|
|
29
|
-
expect(
|
|
29
|
+
expect(uiLogger.error).toHaveBeenCalledWith(expect.stringMatching(/.*Unable to locate a project configuration file. Try running again from a project directory, or run*/));
|
|
30
30
|
});
|
|
31
31
|
it('rejects configuration with missing name', () => {
|
|
32
32
|
// @ts-ignore Testing invalid input
|
|
33
33
|
validateProjectConfig({ srcDir: '.' }, projectDir);
|
|
34
34
|
expect(exitMock).toHaveBeenCalledWith(EXIT_CODES.ERROR);
|
|
35
|
-
expect(
|
|
35
|
+
expect(uiLogger.error).toHaveBeenCalledWith(expect.stringMatching(/.*missing required fields*/));
|
|
36
36
|
});
|
|
37
37
|
it('rejects configuration with missing srcDir', () => {
|
|
38
38
|
// @ts-ignore Testing invalid input
|
|
39
39
|
validateProjectConfig({ name: 'hello' }, projectDir);
|
|
40
40
|
expect(exitMock).toHaveBeenCalledWith(EXIT_CODES.ERROR);
|
|
41
|
-
expect(
|
|
41
|
+
expect(uiLogger.error).toHaveBeenCalledWith(expect.stringMatching(/.*missing required fields.*/));
|
|
42
42
|
});
|
|
43
43
|
describe('rejects configuration with srcDir outside project directory', () => {
|
|
44
44
|
it('for parent directory', () => {
|
|
45
45
|
validateProjectConfig({ name: 'hello', srcDir: '..', platformVersion: '' }, projectDir);
|
|
46
46
|
expect(exitMock).toHaveBeenCalledWith(EXIT_CODES.ERROR);
|
|
47
|
-
expect(
|
|
47
|
+
expect(uiLogger.error).toHaveBeenCalledWith(expect.stringContaining('srcDir: ".."'));
|
|
48
48
|
});
|
|
49
49
|
it('for root directory', () => {
|
|
50
50
|
validateProjectConfig({ name: 'hello', srcDir: '/', platformVersion: '' }, projectDir);
|
|
51
51
|
expect(exitMock).toHaveBeenCalledWith(EXIT_CODES.ERROR);
|
|
52
|
-
expect(
|
|
52
|
+
expect(uiLogger.error).toHaveBeenCalledWith(expect.stringContaining('srcDir: "/"'));
|
|
53
53
|
});
|
|
54
54
|
it('for complicated directory', () => {
|
|
55
55
|
const srcDir = './src/././../src/../../src';
|
|
56
56
|
validateProjectConfig({ name: 'hello', srcDir, platformVersion: '' }, projectDir);
|
|
57
57
|
expect(exitMock).toHaveBeenCalledWith(EXIT_CODES.ERROR);
|
|
58
|
-
expect(
|
|
58
|
+
expect(uiLogger.error).toHaveBeenCalledWith(expect.stringContaining(`srcDir: "${srcDir}"`));
|
|
59
59
|
});
|
|
60
60
|
});
|
|
61
61
|
it('rejects configuration with srcDir that does not exist', () => {
|
|
62
62
|
validateProjectConfig({ name: 'hello', srcDir: 'foo', platformVersion: '' }, projectDir);
|
|
63
63
|
expect(exitMock).toHaveBeenCalledWith(EXIT_CODES.ERROR);
|
|
64
|
-
expect(
|
|
64
|
+
expect(uiLogger.error).toHaveBeenCalledWith(expect.stringMatching(/.*could not be found in.*/));
|
|
65
65
|
});
|
|
66
66
|
describe('accepts configuration with valid srcDir', () => {
|
|
67
67
|
it('for current directory', () => {
|
|
68
68
|
validateProjectConfig({ name: 'hello', srcDir: '.', platformVersion: '' }, projectDir);
|
|
69
69
|
expect(exitMock).not.toHaveBeenCalled();
|
|
70
|
-
expect(
|
|
70
|
+
expect(uiLogger.error).not.toHaveBeenCalled();
|
|
71
71
|
});
|
|
72
72
|
it('for relative directory', () => {
|
|
73
73
|
validateProjectConfig({ name: 'hello', srcDir: './src', platformVersion: '' }, projectDir);
|
|
74
74
|
expect(exitMock).not.toHaveBeenCalled();
|
|
75
|
-
expect(
|
|
75
|
+
expect(uiLogger.error).not.toHaveBeenCalled();
|
|
76
76
|
});
|
|
77
77
|
it('for implied relative directory', () => {
|
|
78
78
|
validateProjectConfig({ name: 'hello', srcDir: 'src', platformVersion: '' }, projectDir);
|
|
79
79
|
expect(exitMock).not.toHaveBeenCalled();
|
|
80
|
-
expect(
|
|
80
|
+
expect(uiLogger.error).not.toHaveBeenCalled();
|
|
81
81
|
});
|
|
82
82
|
});
|
|
83
83
|
});
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
2
|
import * as HSfs from '@hubspot/local-dev-lib/fs';
|
|
3
|
-
import {
|
|
3
|
+
import { uiLogger } from '../../ui/logger.js';
|
|
4
4
|
import { getComponentTypeFromConfigFile, loadConfigFile, getAppCardConfigs, getIsLegacyApp, componentIsApp, findProjectComponents, getProjectComponentTypes, getComponentUid, componentIsPublicApp, } from '../structure.js';
|
|
5
5
|
import { ComponentTypes } from '../../../types/Projects.js';
|
|
6
6
|
vi.mock('fs');
|
|
7
7
|
vi.mock('@hubspot/local-dev-lib/fs');
|
|
8
|
-
vi.mock('
|
|
8
|
+
vi.mock('../../ui/logger.js');
|
|
9
9
|
const mockedReadFileSync = fs.readFileSync;
|
|
10
10
|
const mockedWalk = HSfs.walk;
|
|
11
11
|
const getMockPrivateAppConfig = (cards = []) => ({
|
|
@@ -46,7 +46,7 @@ describe('lib/projects/structure', () => {
|
|
|
46
46
|
throw new Error('File not found');
|
|
47
47
|
});
|
|
48
48
|
expect(loadConfigFile('nonexistent/path/app.json')).toBeNull();
|
|
49
|
-
expect(
|
|
49
|
+
expect(uiLogger.debug).toHaveBeenCalled();
|
|
50
50
|
});
|
|
51
51
|
});
|
|
52
52
|
describe('getAppCardConfigs()', () => {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import fs from 'fs-extra';
|
|
2
|
+
import os from 'os';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import { vi } from 'vitest';
|
|
5
|
+
import { validateSourceDirectory } from '../upload.js';
|
|
6
|
+
import { uiLogger } from '../../ui/logger.js';
|
|
7
|
+
import { lib } from '../../../lang/en.js';
|
|
8
|
+
import { isV2Project } from '../platformVersion.js';
|
|
9
|
+
import ProjectValidationError from '../../errors/ProjectValidationError.js';
|
|
10
|
+
import { walk } from '@hubspot/local-dev-lib/fs';
|
|
11
|
+
// Mock dependencies
|
|
12
|
+
vi.mock('../../ui/logger.js');
|
|
13
|
+
vi.mock('../platformVersion.js');
|
|
14
|
+
vi.mock('@hubspot/local-dev-lib/fs');
|
|
15
|
+
describe('lib/projects/upload', () => {
|
|
16
|
+
describe('validateSourceDirectory', () => {
|
|
17
|
+
let tempDir;
|
|
18
|
+
let srcDir;
|
|
19
|
+
let projectConfig;
|
|
20
|
+
beforeEach(() => {
|
|
21
|
+
tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'upload-test-'));
|
|
22
|
+
srcDir = path.join(tempDir, 'src');
|
|
23
|
+
fs.mkdirSync(srcDir, { recursive: true });
|
|
24
|
+
projectConfig = {
|
|
25
|
+
name: 'test-project',
|
|
26
|
+
srcDir: 'src',
|
|
27
|
+
platformVersion: '2025.2',
|
|
28
|
+
};
|
|
29
|
+
vi.clearAllMocks();
|
|
30
|
+
});
|
|
31
|
+
afterEach(() => {
|
|
32
|
+
fs.removeSync(tempDir);
|
|
33
|
+
});
|
|
34
|
+
it('should throw ProjectValidationError when source directory is empty', async () => {
|
|
35
|
+
vi.mocked(walk).mockResolvedValue([]);
|
|
36
|
+
await expect(validateSourceDirectory(srcDir, projectConfig, tempDir)).rejects.toThrow(ProjectValidationError);
|
|
37
|
+
expect(walk).toHaveBeenCalledWith(srcDir, ['node_modules']);
|
|
38
|
+
});
|
|
39
|
+
it('should warn about legacy files in V3 projects', async () => {
|
|
40
|
+
vi.mocked(isV2Project).mockReturnValue(true);
|
|
41
|
+
const legacyFilePath = path.join(srcDir, 'app', 'serverless.json');
|
|
42
|
+
vi.mocked(walk).mockResolvedValue([legacyFilePath]);
|
|
43
|
+
await validateSourceDirectory(srcDir, projectConfig, tempDir);
|
|
44
|
+
expect(uiLogger.warn).toHaveBeenCalledWith(lib.projectUpload.handleProjectUpload.legacyFileDetected('src/app/serverless.json', '2025.2'));
|
|
45
|
+
});
|
|
46
|
+
it('should warn about multiple legacy files', async () => {
|
|
47
|
+
vi.mocked(isV2Project).mockReturnValue(true);
|
|
48
|
+
const filePaths = [
|
|
49
|
+
path.join(srcDir, 'app1', 'serverless.json'),
|
|
50
|
+
path.join(srcDir, 'app2', 'app.json'),
|
|
51
|
+
path.join(srcDir, 'app3', 'public-app.json'),
|
|
52
|
+
];
|
|
53
|
+
vi.mocked(walk).mockResolvedValue(filePaths);
|
|
54
|
+
await validateSourceDirectory(srcDir, projectConfig, tempDir);
|
|
55
|
+
expect(uiLogger.warn).toHaveBeenCalledTimes(3);
|
|
56
|
+
expect(uiLogger.warn).toHaveBeenCalledWith(lib.projectUpload.handleProjectUpload.legacyFileDetected('src/app1/serverless.json', '2025.2'));
|
|
57
|
+
expect(uiLogger.warn).toHaveBeenCalledWith(lib.projectUpload.handleProjectUpload.legacyFileDetected('src/app2/app.json', '2025.2'));
|
|
58
|
+
expect(uiLogger.warn).toHaveBeenCalledWith(lib.projectUpload.handleProjectUpload.legacyFileDetected('src/app3/public-app.json', '2025.2'));
|
|
59
|
+
});
|
|
60
|
+
it('should not warn about non-legacy files', async () => {
|
|
61
|
+
vi.mocked(isV2Project).mockReturnValue(true);
|
|
62
|
+
const filePaths = [
|
|
63
|
+
path.join(srcDir, 'component.js'),
|
|
64
|
+
path.join(srcDir, 'config.json'),
|
|
65
|
+
];
|
|
66
|
+
vi.mocked(walk).mockResolvedValue(filePaths);
|
|
67
|
+
await validateSourceDirectory(srcDir, projectConfig, tempDir);
|
|
68
|
+
expect(uiLogger.warn).not.toHaveBeenCalled();
|
|
69
|
+
});
|
|
70
|
+
it('should not warn about legacy files in non-V3 projects', async () => {
|
|
71
|
+
vi.mocked(isV2Project).mockReturnValue(false);
|
|
72
|
+
projectConfig.platformVersion = '2025.1';
|
|
73
|
+
const filePaths = [
|
|
74
|
+
path.join(srcDir, 'app', 'serverless.json'),
|
|
75
|
+
path.join(srcDir, 'app', 'app.json'),
|
|
76
|
+
];
|
|
77
|
+
vi.mocked(walk).mockResolvedValue(filePaths);
|
|
78
|
+
await validateSourceDirectory(srcDir, projectConfig, tempDir);
|
|
79
|
+
expect(uiLogger.warn).not.toHaveBeenCalled();
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
});
|
|
@@ -2,7 +2,7 @@ import { legacyAddComponent } from '../legacyAddComponent.js';
|
|
|
2
2
|
import { findProjectComponents } from '../../structure.js';
|
|
3
3
|
import { getProjectComponentListFromRepo } from '../../create/legacy.js';
|
|
4
4
|
import { projectAddPrompt } from '../../../prompts/projectAddPrompt.js';
|
|
5
|
-
import {
|
|
5
|
+
import { uiLogger } from '../../../ui/logger.js';
|
|
6
6
|
import { cloneGithubRepo } from '@hubspot/local-dev-lib/github';
|
|
7
7
|
import { trackCommandUsage } from '../../../usageTracking.js';
|
|
8
8
|
import { ComponentTypes, } from '../../../../types/Projects.js';
|
|
@@ -10,13 +10,13 @@ import { commands } from '../../../../lang/en.js';
|
|
|
10
10
|
vi.mock('../../structure');
|
|
11
11
|
vi.mock('../../create/legacy');
|
|
12
12
|
vi.mock('../../../prompts/projectAddPrompt');
|
|
13
|
-
vi.mock('
|
|
13
|
+
vi.mock('../../../ui/logger.js');
|
|
14
14
|
vi.mock('@hubspot/local-dev-lib/github');
|
|
15
15
|
vi.mock('../../../usageTracking.js');
|
|
16
16
|
const mockedFindProjectComponents = vi.mocked(findProjectComponents);
|
|
17
17
|
const mockedGetProjectComponentListFromRepo = vi.mocked(getProjectComponentListFromRepo);
|
|
18
18
|
const mockedProjectAddPrompt = vi.mocked(projectAddPrompt);
|
|
19
|
-
const
|
|
19
|
+
const mockedUiLogger = vi.mocked(uiLogger);
|
|
20
20
|
const mockedCloneGithubRepo = vi.mocked(cloneGithubRepo);
|
|
21
21
|
const mockedTrackCommandUsage = vi.mocked(trackCommandUsage);
|
|
22
22
|
describe('lib/projects/add/legacyAddComponent', () => {
|
|
@@ -75,8 +75,8 @@ describe('lib/projects/add/legacyAddComponent', () => {
|
|
|
75
75
|
expect(mockedTrackCommandUsage).toHaveBeenCalledWith('project-add', {
|
|
76
76
|
type: 'module',
|
|
77
77
|
}, accountId);
|
|
78
|
-
expect(
|
|
79
|
-
expect(
|
|
78
|
+
expect(mockedUiLogger.log).toHaveBeenCalledWith(commands.project.add.creatingComponent('test-project'));
|
|
79
|
+
expect(mockedUiLogger.success).toHaveBeenCalledWith(commands.project.add.success('new-component'));
|
|
80
80
|
});
|
|
81
81
|
it('throws an error when project contains a public app', async () => {
|
|
82
82
|
const mockComponents = [
|
|
@@ -206,7 +206,7 @@ describe('lib/projects/add/legacyAddComponent', () => {
|
|
|
206
206
|
mockedCloneGithubRepo.mockRejectedValue(new Error('Clone failed'));
|
|
207
207
|
await expect(legacyAddComponent(mockArgs, projectDir, mockProjectConfig, accountId)).rejects.toThrow(commands.project.add.error.failedToDownloadComponent);
|
|
208
208
|
expect(mockedCloneGithubRepo).toHaveBeenCalled();
|
|
209
|
-
expect(
|
|
209
|
+
expect(mockedUiLogger.success).not.toHaveBeenCalled();
|
|
210
210
|
});
|
|
211
211
|
it('calls trackCommandUsage with correct component type', async () => {
|
|
212
212
|
const mockComponents = [
|
|
@@ -5,7 +5,7 @@ import { createV3App } from '../../create/v3.js';
|
|
|
5
5
|
import { confirmPrompt } from '../../../prompts/promptUtils.js';
|
|
6
6
|
import { projectAddPromptV3 } from '../../../prompts/projectAddPrompt.js';
|
|
7
7
|
import { cloneGithubRepo } from '@hubspot/local-dev-lib/github';
|
|
8
|
-
import {
|
|
8
|
+
import { uiLogger } from '../../../ui/logger.js';
|
|
9
9
|
import { getProjectMetadata } from '@hubspot/project-parsing-lib/src/lib/project.js';
|
|
10
10
|
import { trackCommandUsage } from '../../../usageTracking.js';
|
|
11
11
|
import { commands } from '../../../../lang/en.js';
|
|
@@ -15,7 +15,7 @@ vi.mock('../../create/legacy');
|
|
|
15
15
|
vi.mock('../../create/v3');
|
|
16
16
|
vi.mock('../../../prompts/projectAddPrompt');
|
|
17
17
|
vi.mock('@hubspot/local-dev-lib/github');
|
|
18
|
-
vi.mock('
|
|
18
|
+
vi.mock('../../../ui/logger.js');
|
|
19
19
|
vi.mock('@hubspot/project-parsing-lib/src/lib/project');
|
|
20
20
|
vi.mock('../../../usageTracking');
|
|
21
21
|
const mockedFs = vi.mocked(fs);
|
|
@@ -24,7 +24,7 @@ const mockedConfirmPrompt = vi.mocked(confirmPrompt);
|
|
|
24
24
|
const mockedCreateV3App = vi.mocked(createV3App);
|
|
25
25
|
const mockedProjectAddPromptV3 = vi.mocked(projectAddPromptV3);
|
|
26
26
|
const mockedCloneGithubRepo = vi.mocked(cloneGithubRepo);
|
|
27
|
-
const
|
|
27
|
+
const mockedUiLogger = vi.mocked(uiLogger);
|
|
28
28
|
const mockedGetProjectMetadata = vi.mocked(getProjectMetadata);
|
|
29
29
|
const mockedTrackCommandUsage = vi.mocked(trackCommandUsage);
|
|
30
30
|
describe('lib/projects/add/v3AddComponent', () => {
|
|
@@ -100,7 +100,7 @@ describe('lib/projects/add/v3AddComponent', () => {
|
|
|
100
100
|
hideLogs: true,
|
|
101
101
|
branch: 'main',
|
|
102
102
|
}));
|
|
103
|
-
expect(
|
|
103
|
+
expect(mockedUiLogger.success).toHaveBeenCalled();
|
|
104
104
|
});
|
|
105
105
|
it('creates an app when no app exists and user confirms', async () => {
|
|
106
106
|
const mockProjectMetadataNoApps = {
|