@hubspot/cli 7.9.0 → 7.9.1-experimental.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/cli.js +5 -4
- package/commands/__tests__/getStarted.test.js +10 -0
- package/commands/__tests__/project.test.js +2 -0
- package/commands/account/__tests__/rename.test.js +42 -0
- package/commands/account/auth.js +10 -14
- package/commands/account/clean.js +11 -19
- package/commands/account/createOverride.js +17 -23
- package/commands/account/info.js +8 -5
- package/commands/account/list.js +13 -18
- package/commands/account/remove.js +23 -22
- package/commands/account/removeOverride.js +8 -16
- package/commands/account/rename.d.ts +1 -1
- package/commands/account/rename.js +6 -3
- package/commands/account/use.js +19 -8
- package/commands/app/__tests__/migrate.test.js +8 -4
- package/commands/app/migrate.js +2 -2
- package/commands/auth.js +18 -14
- package/commands/cms/theme/preview.js +1 -4
- package/commands/config/migrate.js +5 -5
- package/commands/config/set.js +1 -2
- package/commands/customObject/createSchema.js +2 -3
- package/commands/customObject/updateSchema.js +2 -3
- package/commands/getStarted.js +15 -22
- package/commands/hubdb/__tests__/list.test.js +1 -0
- package/commands/hubdb/list.js +2 -2
- package/commands/hubdb.d.ts +1 -1
- package/commands/init.js +36 -32
- package/commands/project/__tests__/deploy.test.js +10 -5
- package/commands/project/__tests__/devUnifiedFlow.test.js +6 -4
- package/commands/project/__tests__/logs.test.js +4 -0
- package/commands/project/__tests__/updateDeps.test.js +142 -0
- package/commands/project/__tests__/validate.test.js +2 -2
- package/commands/project/cloneApp.js +2 -2
- package/commands/project/create.js +0 -1
- package/commands/project/deploy.js +2 -2
- package/commands/project/dev/deprecatedFlow.js +4 -5
- package/commands/project/dev/index.js +14 -4
- package/commands/project/dev/unifiedFlow.js +4 -5
- package/commands/project/listBuilds.js +7 -1
- package/commands/project/logs.js +2 -3
- package/commands/project/profile/add.js +6 -7
- package/commands/project/profile/delete.js +2 -2
- package/commands/project/updateDeps.d.ts +6 -0
- package/commands/project/updateDeps.js +80 -0
- package/commands/project/upload.js +9 -3
- package/commands/project/validate.js +9 -3
- package/commands/project/watch.js +7 -2
- package/commands/project.js +2 -0
- package/commands/sandbox/__tests__/create.test.js +14 -5
- package/commands/sandbox/create.js +4 -5
- package/commands/sandbox/delete.js +23 -20
- package/commands/testAccount/__tests__/create.test.js +68 -0
- package/commands/testAccount/create.d.ts +8 -0
- package/commands/testAccount/create.js +135 -45
- package/commands/testAccount/delete.js +9 -8
- package/commands/testAccount/importData.d.ts +1 -1
- package/lang/en.d.ts +3199 -3185
- package/lang/en.js +52 -14
- package/lib/__tests__/buildAccount.test.js +22 -30
- package/lib/__tests__/commonOpts.test.js +9 -13
- package/lib/__tests__/dependencyManagement.test.js +273 -1
- package/lib/__tests__/developerTestAccounts.test.js +29 -17
- package/lib/__tests__/importData.test.js +20 -10
- package/lib/__tests__/oauth.test.js +19 -8
- package/lib/__tests__/sandboxSync.test.js +33 -11
- package/lib/__tests__/sandboxes.test.js +30 -19
- package/lib/__tests__/usageTracking.test.js +10 -10
- package/lib/__tests__/validation.test.js +32 -32
- package/lib/accountTypes.d.ts +9 -9
- package/lib/accountTypes.js +2 -4
- package/lib/app/__tests__/migrate.test.js +15 -0
- package/lib/app/__tests__/migrate_legacy.test.js +9 -0
- package/lib/app/migrate_legacy.d.ts +2 -2
- package/lib/buildAccount.d.ts +4 -4
- package/lib/buildAccount.js +7 -14
- package/lib/commonOpts.js +5 -8
- package/lib/configMigrate.d.ts +2 -2
- package/lib/configMigrate.js +42 -18
- package/lib/configOptions.js +3 -2
- package/lib/constants.d.ts +1 -0
- package/lib/constants.js +6 -0
- package/lib/dependencyManagement.d.ts +8 -2
- package/lib/dependencyManagement.js +75 -12
- package/lib/developerTestAccounts.d.ts +3 -3
- package/lib/developerTestAccounts.js +4 -7
- package/lib/doctor/DiagnosticInfoBuilder.d.ts +1 -1
- package/lib/doctor/DiagnosticInfoBuilder.js +9 -6
- package/lib/doctor/Doctor.js +4 -3
- package/lib/doctor/__tests__/Diagnosis.test.js +4 -3
- package/lib/doctor/__tests__/DiagnosticInfoBuilder.test.js +17 -9
- package/lib/doctor/__tests__/Doctor.test.js +14 -0
- package/lib/importData.js +8 -7
- package/lib/links.js +5 -5
- package/lib/mcp/__tests__/setup.test.d.ts +1 -0
- package/lib/mcp/__tests__/setup.test.js +127 -0
- package/lib/mcp/setup.d.ts +4 -12
- package/lib/mcp/setup.js +34 -1
- package/lib/middleware/__test__/commandTargetingUtils.test.js +3 -3
- package/lib/middleware/__test__/configMiddleware.test.js +23 -22
- package/lib/middleware/__test__/gitMiddleware.test.js +9 -7
- package/lib/middleware/autoUpdateMiddleware.d.ts +3 -1
- package/lib/middleware/autoUpdateMiddleware.js +10 -2
- package/lib/middleware/commandTargetingUtils.js +2 -2
- package/lib/middleware/configMiddleware.d.ts +6 -1
- package/lib/middleware/configMiddleware.js +36 -15
- package/lib/middleware/gitMiddleware.js +8 -4
- package/lib/npm.d.ts +3 -0
- package/lib/npm.js +6 -0
- package/lib/oauth.d.ts +2 -2
- package/lib/oauth.js +8 -10
- package/lib/projects/__tests__/AppDevModeInterface.test.js +17 -6
- package/lib/projects/__tests__/DevServerManager.test.js +1 -0
- package/lib/projects/__tests__/LocalDevProcess.test.js +1 -0
- package/lib/projects/__tests__/components.test.js +148 -24
- package/lib/projects/__tests__/deploy.test.js +1 -0
- package/lib/projects/__tests__/platformVersion.test.js +5 -1
- package/lib/projects/__tests__/projects.test.js +13 -42
- package/lib/projects/components.js +76 -20
- package/lib/projects/config.js +5 -9
- package/lib/projects/create/__tests__/v2.test.js +11 -0
- package/lib/projects/localDev/AppDevModeInterface.js +2 -2
- package/lib/projects/localDev/DevServerManager_DEPRECATED.js +2 -2
- package/lib/projects/localDev/LocalDevLogger.js +4 -4
- package/lib/projects/localDev/LocalDevManager_DEPRECATED.js +3 -3
- package/lib/projects/localDev/helpers/account.d.ts +10 -10
- package/lib/projects/localDev/helpers/account.js +6 -11
- package/lib/projects/platformVersion.js +1 -1
- package/lib/projects/urls.js +5 -6
- package/lib/prompts/__tests__/createDeveloperTestAccountConfigPrompt.test.d.ts +1 -0
- package/lib/prompts/__tests__/createDeveloperTestAccountConfigPrompt.test.js +153 -0
- package/lib/prompts/__tests__/downloadProjectPrompt.test.js +7 -5
- package/lib/prompts/accountNamePrompt.js +3 -3
- package/lib/prompts/accountsPrompt.d.ts +1 -1
- package/lib/prompts/accountsPrompt.js +6 -7
- package/lib/prompts/confirmImportDataPrompt.js +2 -2
- package/lib/prompts/createDeveloperTestAccountConfigPrompt.d.ts +5 -0
- package/lib/prompts/createDeveloperTestAccountConfigPrompt.js +76 -66
- package/lib/prompts/downloadProjectPrompt.d.ts +1 -0
- package/lib/prompts/downloadProjectPrompt.js +5 -2
- package/lib/prompts/importDataTestAccountSelectPrompt.js +4 -5
- package/lib/prompts/personalAccessKeyPrompt.js +2 -2
- package/lib/prompts/projectDevTargetAccountPrompt.d.ts +3 -3
- package/lib/prompts/projectDevTargetAccountPrompt.js +5 -7
- package/lib/prompts/sandboxesPrompt.js +7 -8
- package/lib/prompts/setAsDefaultAccountPrompt.js +7 -6
- package/lib/sandboxSync.d.ts +2 -2
- package/lib/sandboxSync.js +3 -9
- package/lib/sandboxes.d.ts +4 -4
- package/lib/sandboxes.js +6 -11
- package/lib/serverlessLogs.js +2 -2
- package/lib/theme/__tests__/migrate.test.js +15 -0
- package/lib/ui/index.js +6 -3
- package/lib/usageTracking.js +15 -8
- package/lib/validation.js +13 -11
- package/mcp-server/tools/cms/HsCreateFunctionTool.js +8 -2
- package/mcp-server/tools/cms/HsCreateModuleTool.d.ts +4 -4
- package/mcp-server/tools/cms/HsCreateModuleTool.js +8 -2
- package/mcp-server/tools/cms/HsCreateTemplateTool.js +8 -2
- package/mcp-server/tools/cms/HsFunctionLogsTool.d.ts +4 -4
- package/mcp-server/tools/cms/HsFunctionLogsTool.js +6 -2
- package/mcp-server/tools/cms/HsListFunctionsTool.js +5 -1
- package/mcp-server/tools/cms/HsListTool.js +5 -1
- package/mcp-server/tools/cms/__tests__/HsCreateFunctionTool.test.js +1 -0
- package/mcp-server/tools/index.js +4 -0
- package/mcp-server/tools/project/AddFeatureToProjectTool.d.ts +1 -1
- package/mcp-server/tools/project/AddFeatureToProjectTool.js +9 -3
- package/mcp-server/tools/project/CreateProjectTool.js +8 -2
- package/mcp-server/tools/project/CreateTestAccountTool.d.ts +41 -0
- package/mcp-server/tools/project/CreateTestAccountTool.js +150 -0
- package/mcp-server/tools/project/DeployProjectTool.d.ts +1 -1
- package/mcp-server/tools/project/DeployProjectTool.js +8 -2
- package/mcp-server/tools/project/DocFetchTool.d.ts +1 -1
- package/mcp-server/tools/project/DocFetchTool.js +9 -5
- package/mcp-server/tools/project/DocsSearchTool.d.ts +1 -1
- package/mcp-server/tools/project/DocsSearchTool.js +12 -8
- package/mcp-server/tools/project/GetApiUsagePatternsByAppIdTool.d.ts +1 -1
- package/mcp-server/tools/project/GetApiUsagePatternsByAppIdTool.js +11 -7
- package/mcp-server/tools/project/GetApplicationInfoTool.d.ts +1 -1
- package/mcp-server/tools/project/GetApplicationInfoTool.js +11 -7
- package/mcp-server/tools/project/GetBuildStatusTool.d.ts +26 -0
- package/mcp-server/tools/project/GetBuildStatusTool.js +164 -0
- package/mcp-server/tools/project/GetConfigValuesTool.d.ts +1 -1
- package/mcp-server/tools/project/GetConfigValuesTool.js +11 -7
- package/mcp-server/tools/project/GuidedWalkthroughTool.d.ts +1 -1
- package/mcp-server/tools/project/GuidedWalkthroughTool.js +7 -3
- package/mcp-server/tools/project/UploadProjectTools.d.ts +9 -3
- package/mcp-server/tools/project/UploadProjectTools.js +51 -5
- package/mcp-server/tools/project/ValidateProjectTool.d.ts +1 -1
- package/mcp-server/tools/project/ValidateProjectTool.js +7 -3
- package/mcp-server/tools/project/__tests__/CreateTestAccountTool.test.d.ts +1 -0
- package/mcp-server/tools/project/__tests__/CreateTestAccountTool.test.js +454 -0
- package/mcp-server/tools/project/__tests__/DocFetchTool.test.js +5 -1
- package/mcp-server/tools/project/__tests__/DocsSearchTool.test.js +25 -13
- package/mcp-server/tools/project/__tests__/GetApiUsagePatternsByAppIdTool.test.js +7 -5
- package/mcp-server/tools/project/__tests__/GetApplicationInfoTool.test.js +7 -5
- package/mcp-server/tools/project/__tests__/GetBuildStatusTool.test.d.ts +1 -0
- package/mcp-server/tools/project/__tests__/GetBuildStatusTool.test.js +240 -0
- package/mcp-server/tools/project/__tests__/GetConfigValuesTool.test.js +8 -6
- package/mcp-server/tools/project/__tests__/UploadProjectTools.test.js +56 -4
- package/mcp-server/utils/__tests__/content.test.js +21 -20
- package/mcp-server/utils/__tests__/feedbackTracking.test.js +33 -28
- package/mcp-server/utils/content.d.ts +1 -1
- package/mcp-server/utils/content.js +2 -2
- package/mcp-server/utils/feedbackTracking.d.ts +1 -1
- package/mcp-server/utils/feedbackTracking.js +3 -3
- package/mcp-server/utils/toolUsageTracking.js +4 -3
- package/package.json +8 -7
- package/lang/en.lyaml +0 -1508
- package/lib/lang.d.ts +0 -8
- package/lib/lang.js +0 -72
- package/mcp-server/utils/__tests__/cliConfig.test.js +0 -110
- package/mcp-server/utils/cliConfig.d.ts +0 -1
- package/mcp-server/utils/cliConfig.js +0 -12
- /package/{mcp-server/utils/__tests__/cliConfig.test.d.ts → commands/project/__tests__/updateDeps.test.d.ts} +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import util from 'util';
|
|
2
|
-
import { installPackages, getProjectPackageJsonLocations, } from '../dependencyManagement.js';
|
|
2
|
+
import { installPackages, updatePackages, getProjectPackageJsonLocations, isPackageInstalled, } from '../dependencyManagement.js';
|
|
3
3
|
import { walk } from '@hubspot/local-dev-lib/fs';
|
|
4
4
|
import path from 'path';
|
|
5
5
|
import { getProjectConfig } from '../projects/config.js';
|
|
@@ -105,6 +105,54 @@ describe('lib/dependencyManagement', () => {
|
|
|
105
105
|
cwd: extensionsDir,
|
|
106
106
|
});
|
|
107
107
|
});
|
|
108
|
+
it('should install packages as dev dependencies when dev flag is true', async () => {
|
|
109
|
+
const packages = ['eslint', 'prettier'];
|
|
110
|
+
await installPackages({ packages, installLocations, dev: true });
|
|
111
|
+
expect(execMock).toHaveBeenCalledTimes(installLocations.length);
|
|
112
|
+
for (const location of installLocations) {
|
|
113
|
+
expect(execMock).toHaveBeenCalledWith(`npm install --save-dev eslint prettier`, {
|
|
114
|
+
cwd: location,
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
it('should install packages as regular dependencies when dev flag is false', async () => {
|
|
119
|
+
const packages = ['react', 'react-dom'];
|
|
120
|
+
await installPackages({ packages, installLocations, dev: false });
|
|
121
|
+
expect(execMock).toHaveBeenCalledTimes(installLocations.length);
|
|
122
|
+
for (const location of installLocations) {
|
|
123
|
+
expect(execMock).toHaveBeenCalledWith(`npm install react react-dom`, {
|
|
124
|
+
cwd: location,
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
it('should install packages as regular dependencies when dev flag is not provided', async () => {
|
|
129
|
+
const packages = ['axios'];
|
|
130
|
+
await installPackages({ packages, installLocations });
|
|
131
|
+
expect(execMock).toHaveBeenCalledTimes(installLocations.length);
|
|
132
|
+
for (const location of installLocations) {
|
|
133
|
+
expect(execMock).toHaveBeenCalledWith(`npm install axios`, {
|
|
134
|
+
cwd: location,
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
it('should not use --save-dev flag when dev is true but no packages are provided', async () => {
|
|
139
|
+
await installPackages({ installLocations, dev: true });
|
|
140
|
+
expect(execMock).toHaveBeenCalledTimes(installLocations.length);
|
|
141
|
+
for (const location of installLocations) {
|
|
142
|
+
expect(execMock).toHaveBeenCalledWith(`npm install `, {
|
|
143
|
+
cwd: location,
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
it('should not use --save-dev flag when dev is true but packages array is empty', async () => {
|
|
148
|
+
await installPackages({ packages: [], installLocations, dev: true });
|
|
149
|
+
expect(execMock).toHaveBeenCalledTimes(installLocations.length);
|
|
150
|
+
for (const location of installLocations) {
|
|
151
|
+
expect(execMock).toHaveBeenCalledWith(`npm install `, {
|
|
152
|
+
cwd: location,
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
});
|
|
108
156
|
it('should throw an error when installing the dependencies fails', async () => {
|
|
109
157
|
execMock = vi.fn().mockImplementation(command => {
|
|
110
158
|
if (command === 'npm --version') {
|
|
@@ -133,6 +181,92 @@ describe('lib/dependencyManagement', () => {
|
|
|
133
181
|
});
|
|
134
182
|
});
|
|
135
183
|
});
|
|
184
|
+
describe('updatePackages()', () => {
|
|
185
|
+
it('should setup a loading spinner', async () => {
|
|
186
|
+
const packages = ['package1', 'package2'];
|
|
187
|
+
await updatePackages({ packages, installLocations });
|
|
188
|
+
expect(SpinniesManager.init).toHaveBeenCalledTimes(installLocations.length);
|
|
189
|
+
expect(SpinniesManager.add).toHaveBeenCalledTimes(installLocations.length);
|
|
190
|
+
expect(SpinniesManager.succeed).toHaveBeenCalledTimes(installLocations.length);
|
|
191
|
+
});
|
|
192
|
+
it('should update the provided packages in all the provided install locations', async () => {
|
|
193
|
+
const packages = ['package1', 'package2'];
|
|
194
|
+
await updatePackages({ packages, installLocations });
|
|
195
|
+
expect(execMock).toHaveBeenCalledTimes(installLocations.length);
|
|
196
|
+
expect(SpinniesManager.add).toHaveBeenCalledTimes(installLocations.length);
|
|
197
|
+
expect(SpinniesManager.succeed).toHaveBeenCalledTimes(installLocations.length);
|
|
198
|
+
for (const location of installLocations) {
|
|
199
|
+
expect(execMock).toHaveBeenCalledWith(`npm update package1 package2`, {
|
|
200
|
+
cwd: location,
|
|
201
|
+
});
|
|
202
|
+
expect(SpinniesManager.add).toHaveBeenCalledWith(`updatingDependencies-${location}`, {
|
|
203
|
+
text: `Updating [package1, package2] in ${location}`,
|
|
204
|
+
});
|
|
205
|
+
expect(SpinniesManager.succeed).toHaveBeenCalledWith(`updatingDependencies-${location}`, {
|
|
206
|
+
text: `Updated dependencies in ${location}`,
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
it('should use the provided install locations', async () => {
|
|
211
|
+
await updatePackages({ installLocations });
|
|
212
|
+
expect(execMock).toHaveBeenCalledTimes(installLocations.length);
|
|
213
|
+
expect(execMock).toHaveBeenCalledWith(`npm update `, {
|
|
214
|
+
cwd: appFunctionsDir,
|
|
215
|
+
});
|
|
216
|
+
expect(execMock).toHaveBeenCalledWith(`npm update `, {
|
|
217
|
+
cwd: extensionsDir,
|
|
218
|
+
});
|
|
219
|
+
});
|
|
220
|
+
it('should locate the projects package.json files when install locations is not provided', async () => {
|
|
221
|
+
const installLocations = [
|
|
222
|
+
path.join(appFunctionsDir, 'package.json'),
|
|
223
|
+
path.join(extensionsDir, 'package.json'),
|
|
224
|
+
];
|
|
225
|
+
mockedWalk.mockResolvedValue(installLocations);
|
|
226
|
+
mockedGetProjectConfig.mockResolvedValue({
|
|
227
|
+
projectDir,
|
|
228
|
+
projectConfig: {
|
|
229
|
+
srcDir,
|
|
230
|
+
},
|
|
231
|
+
});
|
|
232
|
+
await updatePackages({});
|
|
233
|
+
// It's called once per each install location, plus once to check if npm installed
|
|
234
|
+
expect(execMock).toHaveBeenCalledTimes(installLocations.length + 1);
|
|
235
|
+
expect(execMock).toHaveBeenCalledWith(`npm update `, {
|
|
236
|
+
cwd: appFunctionsDir,
|
|
237
|
+
});
|
|
238
|
+
expect(execMock).toHaveBeenCalledWith(`npm update `, {
|
|
239
|
+
cwd: extensionsDir,
|
|
240
|
+
});
|
|
241
|
+
});
|
|
242
|
+
it('should throw an error when updating the dependencies fails', async () => {
|
|
243
|
+
execMock = vi.fn().mockImplementation(command => {
|
|
244
|
+
if (command === 'npm --version') {
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
throw new Error('OH NO');
|
|
248
|
+
});
|
|
249
|
+
util.promisify = mockedPromisify(execMock);
|
|
250
|
+
// Mock walk to return the directory paths instead of package.json paths
|
|
251
|
+
mockedWalk.mockResolvedValue([appFunctionsDir, extensionsDir]);
|
|
252
|
+
mockedFs.existsSync.mockImplementation(filePath => {
|
|
253
|
+
const pathStr = filePath.toString();
|
|
254
|
+
if (pathStr === projectDir ||
|
|
255
|
+
pathStr === path.join(projectDir, srcDir)) {
|
|
256
|
+
return true;
|
|
257
|
+
}
|
|
258
|
+
return false;
|
|
259
|
+
});
|
|
260
|
+
await expect(() => updatePackages({ installLocations: [appFunctionsDir, extensionsDir] })).rejects.toThrowError(`Updating dependencies for ${appFunctionsDir} failed`);
|
|
261
|
+
expect(SpinniesManager.fail).toHaveBeenCalledTimes(installLocations.length);
|
|
262
|
+
expect(SpinniesManager.fail).toHaveBeenCalledWith(`updatingDependencies-${appFunctionsDir}`, {
|
|
263
|
+
text: `Updating dependencies for ${appFunctionsDir} failed`,
|
|
264
|
+
});
|
|
265
|
+
expect(SpinniesManager.fail).toHaveBeenCalledWith(`updatingDependencies-${extensionsDir}`, {
|
|
266
|
+
text: `Updating dependencies for ${extensionsDir} failed`,
|
|
267
|
+
});
|
|
268
|
+
});
|
|
269
|
+
});
|
|
136
270
|
describe('getProjectPackageJsonFiles()', () => {
|
|
137
271
|
it('should throw an error when ran outside the boundary of a project', async () => {
|
|
138
272
|
mockedGetProjectConfig.mockResolvedValue({});
|
|
@@ -149,6 +283,30 @@ describe('lib/dependencyManagement', () => {
|
|
|
149
283
|
mockedFs.existsSync.mockReturnValueOnce(false);
|
|
150
284
|
await expect(() => getProjectPackageJsonLocations()).rejects.toThrowError(new RegExp(`No dependencies to install. The project ${projectName} folder might be missing component or subcomponent files.`));
|
|
151
285
|
});
|
|
286
|
+
it('should throw "install" error message when isUpdate=false and no package.json files found', async () => {
|
|
287
|
+
mockedWalk.mockResolvedValue([]);
|
|
288
|
+
mockedFs.existsSync.mockImplementation(filePath => {
|
|
289
|
+
const pathStr = filePath.toString();
|
|
290
|
+
if (pathStr === projectDir ||
|
|
291
|
+
pathStr === path.join(projectDir, srcDir)) {
|
|
292
|
+
return true;
|
|
293
|
+
}
|
|
294
|
+
return false;
|
|
295
|
+
});
|
|
296
|
+
await expect(() => getProjectPackageJsonLocations(undefined, false)).rejects.toThrowError(new RegExp(`No dependencies to install. The project ${projectName} folder might be missing component or subcomponent files.`));
|
|
297
|
+
});
|
|
298
|
+
it('should throw "update" error message when isUpdate=true and no package.json files found', async () => {
|
|
299
|
+
mockedWalk.mockResolvedValue([]);
|
|
300
|
+
mockedFs.existsSync.mockImplementation(filePath => {
|
|
301
|
+
const pathStr = filePath.toString();
|
|
302
|
+
if (pathStr === projectDir ||
|
|
303
|
+
pathStr === path.join(projectDir, srcDir)) {
|
|
304
|
+
return true;
|
|
305
|
+
}
|
|
306
|
+
return false;
|
|
307
|
+
});
|
|
308
|
+
await expect(() => getProjectPackageJsonLocations(undefined, true)).rejects.toThrowError(new RegExp(`No dependencies to update. The project ${projectName} folder might be missing component or subcomponent files.`));
|
|
309
|
+
});
|
|
152
310
|
it('should ignore package.json files in certain directories', async () => {
|
|
153
311
|
const nodeModulesDir = path.join(appDir, 'node_modules');
|
|
154
312
|
const viteDir = path.join(appDir, '.vite');
|
|
@@ -172,4 +330,118 @@ describe('lib/dependencyManagement', () => {
|
|
|
172
330
|
expect(actual).toEqual([appFunctionsDir, extensionsDir]);
|
|
173
331
|
});
|
|
174
332
|
});
|
|
333
|
+
describe('isPackageInstalled()', () => {
|
|
334
|
+
const testDir = '/test/directory';
|
|
335
|
+
const readFileSyncSpy = vi.spyOn(fs, 'readFileSync');
|
|
336
|
+
const existsSyncSpy = vi.spyOn(fs, 'existsSync');
|
|
337
|
+
function mockNodeModulesExists(packageName, exists = true) {
|
|
338
|
+
existsSyncSpy.mockImplementation(filePath => {
|
|
339
|
+
const pathStr = filePath.toString();
|
|
340
|
+
return (exists && pathStr === path.join(testDir, 'node_modules', packageName));
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
beforeEach(() => {
|
|
344
|
+
vi.clearAllMocks();
|
|
345
|
+
readFileSyncSpy.mockReset();
|
|
346
|
+
existsSyncSpy.mockReset();
|
|
347
|
+
});
|
|
348
|
+
it('should return true if package is in dependencies and in node_modules', () => {
|
|
349
|
+
readFileSyncSpy.mockReturnValueOnce(JSON.stringify({
|
|
350
|
+
dependencies: {
|
|
351
|
+
eslint: '^9.0.0',
|
|
352
|
+
},
|
|
353
|
+
}));
|
|
354
|
+
mockNodeModulesExists('eslint', true);
|
|
355
|
+
const result = isPackageInstalled(testDir, 'eslint');
|
|
356
|
+
expect(result).toBe(true);
|
|
357
|
+
expect(readFileSyncSpy).toHaveBeenCalledWith(path.join(testDir, 'package.json'), 'utf-8');
|
|
358
|
+
expect(existsSyncSpy).toHaveBeenCalledWith(path.join(testDir, 'node_modules', 'eslint'));
|
|
359
|
+
});
|
|
360
|
+
it('should return true if package is in devDependencies and in node_modules', () => {
|
|
361
|
+
readFileSyncSpy.mockReturnValueOnce(JSON.stringify({
|
|
362
|
+
devDependencies: {
|
|
363
|
+
prettier: '^3.0.0',
|
|
364
|
+
},
|
|
365
|
+
}));
|
|
366
|
+
mockNodeModulesExists('prettier', true);
|
|
367
|
+
const result = isPackageInstalled(testDir, 'prettier');
|
|
368
|
+
expect(result).toBe(true);
|
|
369
|
+
});
|
|
370
|
+
it('should return false if package is in package.json but not in node_modules', () => {
|
|
371
|
+
readFileSyncSpy.mockReturnValueOnce(JSON.stringify({
|
|
372
|
+
dependencies: {
|
|
373
|
+
react: '^18.0.0',
|
|
374
|
+
},
|
|
375
|
+
}));
|
|
376
|
+
mockNodeModulesExists('react', false);
|
|
377
|
+
const result = isPackageInstalled(testDir, 'react');
|
|
378
|
+
expect(result).toBe(false);
|
|
379
|
+
});
|
|
380
|
+
it('should return false if package is not in package.json but is in node_modules', () => {
|
|
381
|
+
readFileSyncSpy.mockReturnValueOnce(JSON.stringify({
|
|
382
|
+
dependencies: {
|
|
383
|
+
typescript: '^5.0.0',
|
|
384
|
+
},
|
|
385
|
+
}));
|
|
386
|
+
mockNodeModulesExists('lodash', true);
|
|
387
|
+
const result = isPackageInstalled(testDir, 'lodash');
|
|
388
|
+
expect(result).toBe(false);
|
|
389
|
+
});
|
|
390
|
+
it('should return false if package is not in package.json and not in node_modules', () => {
|
|
391
|
+
readFileSyncSpy.mockReturnValueOnce(JSON.stringify({
|
|
392
|
+
dependencies: {},
|
|
393
|
+
}));
|
|
394
|
+
mockNodeModulesExists('nonexistent-package', false);
|
|
395
|
+
const result = isPackageInstalled(testDir, 'nonexistent-package');
|
|
396
|
+
expect(result).toBe(false);
|
|
397
|
+
});
|
|
398
|
+
it('should return false if package.json cannot be read', () => {
|
|
399
|
+
readFileSyncSpy.mockImplementationOnce(() => {
|
|
400
|
+
throw new Error('File not found');
|
|
401
|
+
});
|
|
402
|
+
const result = isPackageInstalled(testDir, 'eslint');
|
|
403
|
+
expect(result).toBe(false);
|
|
404
|
+
});
|
|
405
|
+
it('should return false if package.json has invalid JSON', () => {
|
|
406
|
+
readFileSyncSpy.mockReturnValueOnce('invalid json{');
|
|
407
|
+
const result = isPackageInstalled(testDir, 'eslint');
|
|
408
|
+
expect(result).toBe(false);
|
|
409
|
+
});
|
|
410
|
+
it('should return false if checking node_modules throws an error', () => {
|
|
411
|
+
readFileSyncSpy.mockReturnValueOnce(JSON.stringify({
|
|
412
|
+
dependencies: {
|
|
413
|
+
eslint: '^9.0.0',
|
|
414
|
+
},
|
|
415
|
+
}));
|
|
416
|
+
existsSyncSpy.mockImplementation(() => {
|
|
417
|
+
throw new Error('Permission denied');
|
|
418
|
+
});
|
|
419
|
+
const result = isPackageInstalled(testDir, 'eslint');
|
|
420
|
+
expect(result).toBe(false);
|
|
421
|
+
});
|
|
422
|
+
it('should handle scoped packages correctly', () => {
|
|
423
|
+
readFileSyncSpy.mockReturnValueOnce(JSON.stringify({
|
|
424
|
+
dependencies: {
|
|
425
|
+
'@typescript-eslint/parser': '^8.0.0',
|
|
426
|
+
},
|
|
427
|
+
}));
|
|
428
|
+
mockNodeModulesExists('@typescript-eslint/parser', true);
|
|
429
|
+
const result = isPackageInstalled(testDir, '@typescript-eslint/parser');
|
|
430
|
+
expect(result).toBe(true);
|
|
431
|
+
expect(existsSyncSpy).toHaveBeenCalledWith(path.join(testDir, 'node_modules', '@typescript-eslint/parser'));
|
|
432
|
+
});
|
|
433
|
+
it('should check both dependencies and devDependencies', () => {
|
|
434
|
+
readFileSyncSpy.mockReturnValueOnce(JSON.stringify({
|
|
435
|
+
dependencies: {
|
|
436
|
+
react: '^18.0.0',
|
|
437
|
+
},
|
|
438
|
+
devDependencies: {
|
|
439
|
+
eslint: '^9.0.0',
|
|
440
|
+
},
|
|
441
|
+
}));
|
|
442
|
+
mockNodeModulesExists('eslint', true);
|
|
443
|
+
const result = isPackageInstalled(testDir, 'eslint');
|
|
444
|
+
expect(result).toBe(true);
|
|
445
|
+
});
|
|
446
|
+
});
|
|
175
447
|
});
|
|
@@ -1,16 +1,18 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getAllConfigAccounts, getConfigAccountIfExists, getConfigAccountById, } from '@hubspot/local-dev-lib/config';
|
|
2
2
|
import { uiLogger } from '../ui/logger.js';
|
|
3
3
|
import { HUBSPOT_ACCOUNT_TYPES } from '@hubspot/local-dev-lib/constants/config';
|
|
4
4
|
import { fetchDeveloperTestAccounts } from '@hubspot/local-dev-lib/api/developerTestAccounts';
|
|
5
5
|
import { mockHubSpotHttpError } from '../testUtils.js';
|
|
6
6
|
import * as errorHandlers from '../errorHandlers/index.js';
|
|
7
7
|
import { getHasDevTestAccounts, handleDeveloperTestAccountCreateError, validateDevTestAccountUsageLimits, } from '../developerTestAccounts.js';
|
|
8
|
+
import { logError } from '../errorHandlers/index.js';
|
|
8
9
|
vi.mock('@hubspot/local-dev-lib/config');
|
|
9
10
|
vi.mock('../ui/logger.js');
|
|
10
11
|
vi.mock('@hubspot/local-dev-lib/api/developerTestAccounts');
|
|
11
12
|
vi.mock('../errorHandlers');
|
|
12
|
-
const
|
|
13
|
-
const
|
|
13
|
+
const mockedGetConfigAccountIfExists = getConfigAccountIfExists;
|
|
14
|
+
const mockedGetAllConfigAccounts = getAllConfigAccounts;
|
|
15
|
+
const mockedGetConfigAccountById = getConfigAccountById;
|
|
14
16
|
const mockedFetchDeveloperTestAccounts = fetchDeveloperTestAccounts;
|
|
15
17
|
const APP_DEVELOPER_ACCOUNT_1 = {
|
|
16
18
|
name: 'app-developer-1',
|
|
@@ -33,41 +35,43 @@ const accounts = [
|
|
|
33
35
|
parentAccountId: APP_DEVELOPER_ACCOUNT_1.accountId,
|
|
34
36
|
accountType: HUBSPOT_ACCOUNT_TYPES.DEVELOPER_TEST,
|
|
35
37
|
env: 'prod',
|
|
38
|
+
authType: 'personalaccesskey',
|
|
36
39
|
},
|
|
37
40
|
];
|
|
38
41
|
describe('lib/developerTestAccounts', () => {
|
|
39
42
|
describe('getHasDevTestAccounts()', () => {
|
|
40
43
|
it('should return true if there are developer test accounts associated with the account', () => {
|
|
41
|
-
|
|
42
|
-
mockedGetConfigAccounts.mockReturnValueOnce(accounts);
|
|
44
|
+
mockedGetAllConfigAccounts.mockReturnValueOnce(accounts);
|
|
43
45
|
const result = getHasDevTestAccounts(APP_DEVELOPER_ACCOUNT_1);
|
|
44
46
|
expect(result).toBe(true);
|
|
45
47
|
});
|
|
46
48
|
it('should return false if there are no developer test accounts associated with the account', () => {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
+
mockedGetConfigAccountIfExists.mockReturnValueOnce(APP_DEVELOPER_ACCOUNT_2);
|
|
50
|
+
mockedGetAllConfigAccounts.mockReturnValueOnce(accounts);
|
|
49
51
|
const result = getHasDevTestAccounts(APP_DEVELOPER_ACCOUNT_2);
|
|
50
52
|
expect(result).toBe(false);
|
|
51
53
|
});
|
|
52
54
|
it('should return false if there are no accounts configured', () => {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
+
mockedGetConfigAccountIfExists.mockReturnValueOnce(APP_DEVELOPER_ACCOUNT_1);
|
|
56
|
+
mockedGetAllConfigAccounts.mockReturnValueOnce(undefined);
|
|
55
57
|
const result = getHasDevTestAccounts(APP_DEVELOPER_ACCOUNT_1);
|
|
56
58
|
expect(result).toBe(false);
|
|
57
59
|
});
|
|
58
60
|
});
|
|
59
61
|
describe('validateDevTestAccountUsageLimits()', () => {
|
|
60
62
|
afterEach(() => {
|
|
61
|
-
|
|
63
|
+
mockedGetConfigAccountIfExists.mockRestore();
|
|
62
64
|
mockedFetchDeveloperTestAccounts.mockRestore();
|
|
63
65
|
});
|
|
64
66
|
it('should return null if the account id is not found', async () => {
|
|
65
|
-
|
|
67
|
+
mockedFetchDeveloperTestAccounts.mockResolvedValueOnce({
|
|
68
|
+
data: null,
|
|
69
|
+
});
|
|
66
70
|
const result = await validateDevTestAccountUsageLimits(APP_DEVELOPER_ACCOUNT_1);
|
|
67
71
|
expect(result).toBe(null);
|
|
68
72
|
});
|
|
69
73
|
it('should return null if there is no developer test account data', async () => {
|
|
70
|
-
|
|
74
|
+
mockedGetConfigAccountIfExists.mockReturnValueOnce(APP_DEVELOPER_ACCOUNT_1);
|
|
71
75
|
mockedFetchDeveloperTestAccounts.mockResolvedValueOnce({
|
|
72
76
|
data: null,
|
|
73
77
|
});
|
|
@@ -75,7 +79,7 @@ describe('lib/developerTestAccounts', () => {
|
|
|
75
79
|
expect(result).toBe(null);
|
|
76
80
|
});
|
|
77
81
|
it('should return the test account data if the account has not reached the limit', async () => {
|
|
78
|
-
|
|
82
|
+
mockedGetConfigAccountIfExists.mockReturnValueOnce(APP_DEVELOPER_ACCOUNT_1);
|
|
79
83
|
const testAccountData = {
|
|
80
84
|
maxTestPortals: 10,
|
|
81
85
|
results: [],
|
|
@@ -87,7 +91,7 @@ describe('lib/developerTestAccounts', () => {
|
|
|
87
91
|
expect(result).toEqual(expect.objectContaining(testAccountData));
|
|
88
92
|
});
|
|
89
93
|
it('should throw an error if the account has reached the limit', async () => {
|
|
90
|
-
|
|
94
|
+
mockedGetConfigAccountIfExists.mockReturnValueOnce(APP_DEVELOPER_ACCOUNT_1);
|
|
91
95
|
mockedFetchDeveloperTestAccounts.mockResolvedValueOnce({
|
|
92
96
|
data: {
|
|
93
97
|
maxTestPortals: 0,
|
|
@@ -103,6 +107,14 @@ describe('lib/developerTestAccounts', () => {
|
|
|
103
107
|
beforeEach(() => {
|
|
104
108
|
loggerErrorSpy = vi.spyOn(uiLogger, 'error');
|
|
105
109
|
logErrorSpy = vi.spyOn(errorHandlers, 'logError');
|
|
110
|
+
// Mock account config for uiAccountDescription calls
|
|
111
|
+
mockedGetConfigAccountById.mockReturnValue({
|
|
112
|
+
accountId: APP_DEVELOPER_ACCOUNT_1.accountId,
|
|
113
|
+
name: 'Test Account',
|
|
114
|
+
authType: 'personalaccesskey',
|
|
115
|
+
personalAccessKey: 'test-key',
|
|
116
|
+
env: 'prod',
|
|
117
|
+
});
|
|
106
118
|
});
|
|
107
119
|
afterEach(() => {
|
|
108
120
|
loggerErrorSpy.mockRestore();
|
|
@@ -117,7 +129,7 @@ describe('lib/developerTestAccounts', () => {
|
|
|
117
129
|
},
|
|
118
130
|
});
|
|
119
131
|
expect(() => handleDeveloperTestAccountCreateError(missingScopesError, APP_DEVELOPER_ACCOUNT_1.accountId, 'prod', 10)).toThrow('Missing scopes error');
|
|
120
|
-
expect(
|
|
132
|
+
expect(uiLogger.error).toHaveBeenCalled();
|
|
121
133
|
});
|
|
122
134
|
it('should log and throw an error if the account is missing the required scopes', () => {
|
|
123
135
|
const portalLimitReachedError = mockHubSpotHttpError('Portal limit reached error', {
|
|
@@ -128,7 +140,7 @@ describe('lib/developerTestAccounts', () => {
|
|
|
128
140
|
},
|
|
129
141
|
});
|
|
130
142
|
expect(() => handleDeveloperTestAccountCreateError(portalLimitReachedError, APP_DEVELOPER_ACCOUNT_1.accountId, 'prod', 10)).toThrow('Portal limit reached error');
|
|
131
|
-
expect(
|
|
143
|
+
expect(uiLogger.error).toHaveBeenCalled();
|
|
132
144
|
});
|
|
133
145
|
it('should log a generic error message for an unknown error type', () => {
|
|
134
146
|
const someUnknownError = mockHubSpotHttpError('Some unknown error', {
|
|
@@ -139,7 +151,7 @@ describe('lib/developerTestAccounts', () => {
|
|
|
139
151
|
},
|
|
140
152
|
});
|
|
141
153
|
expect(() => handleDeveloperTestAccountCreateError(someUnknownError, APP_DEVELOPER_ACCOUNT_1.accountId, 'prod', 10)).toThrow('Some unknown error');
|
|
142
|
-
expect(
|
|
154
|
+
expect(logError).toHaveBeenCalled();
|
|
143
155
|
});
|
|
144
156
|
});
|
|
145
157
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { uiLogger } from '../ui/logger.js';
|
|
2
2
|
import { createImport } from '@hubspot/local-dev-lib/api/crm';
|
|
3
|
-
import {
|
|
3
|
+
import { getConfigAccountById, getConfigAccountIfExists, } from '@hubspot/local-dev-lib/config';
|
|
4
4
|
import { handleImportData, handleTargetTestAccountSelectionFlow, } from '../importData.js';
|
|
5
5
|
import { lib } from '../../lang/en.js';
|
|
6
6
|
import { isDeveloperTestAccount, isStandardAccount, isAppDeveloperAccount, } from '../accountTypes.js';
|
|
@@ -13,8 +13,8 @@ vi.mock('../prompts/importDataTestAccountSelectPrompt');
|
|
|
13
13
|
describe('lib/importData', () => {
|
|
14
14
|
const mockUiLogger = vi.mocked(uiLogger);
|
|
15
15
|
const mockCreateImport = vi.mocked(createImport);
|
|
16
|
-
const
|
|
17
|
-
const
|
|
16
|
+
const mockGetConfigAccountById = vi.mocked(getConfigAccountById);
|
|
17
|
+
const mockGetConfigAccountIfExists = vi.mocked(getConfigAccountIfExists);
|
|
18
18
|
const mockIsDeveloperTestAccount = vi.mocked(isDeveloperTestAccount);
|
|
19
19
|
const mockIsStandardAccount = vi.mocked(isStandardAccount);
|
|
20
20
|
const mockIsAppDeveloperAccount = vi.mocked(isAppDeveloperAccount);
|
|
@@ -24,8 +24,8 @@ describe('lib/importData', () => {
|
|
|
24
24
|
mockUiLogger.success.mockReset();
|
|
25
25
|
mockUiLogger.error.mockReset();
|
|
26
26
|
mockCreateImport.mockReset();
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
mockGetConfigAccountById.mockReset();
|
|
28
|
+
mockGetConfigAccountIfExists.mockReset();
|
|
29
29
|
mockIsDeveloperTestAccount.mockReset();
|
|
30
30
|
mockIsStandardAccount.mockReset();
|
|
31
31
|
mockIsAppDeveloperAccount.mockReset();
|
|
@@ -56,32 +56,42 @@ describe('lib/importData', () => {
|
|
|
56
56
|
const userProvidedAccountId = '1234';
|
|
57
57
|
const derivedAccountId = 123456789;
|
|
58
58
|
it('should error if the userProvidedAccountId is not the right account type', async () => {
|
|
59
|
-
|
|
60
|
-
|
|
59
|
+
mockGetConfigAccountIfExists.mockReturnValue({
|
|
60
|
+
accountId: 1234,
|
|
61
|
+
});
|
|
61
62
|
mockIsDeveloperTestAccount.mockReturnValue(false);
|
|
62
63
|
await expect(handleTargetTestAccountSelectionFlow(derivedAccountId, userProvidedAccountId)).rejects.toThrow(lib.importData.errors.notDeveloperTestAccount);
|
|
63
64
|
});
|
|
64
65
|
it('should error if the derivedAccountId belongs to the wrong account type', async () => {
|
|
65
|
-
|
|
66
|
+
mockGetConfigAccountIfExists.mockReturnValue({
|
|
67
|
+
accountId: derivedAccountId,
|
|
68
|
+
});
|
|
69
|
+
mockGetConfigAccountById.mockReturnValue({
|
|
70
|
+
accountId: derivedAccountId,
|
|
71
|
+
});
|
|
66
72
|
mockIsDeveloperTestAccount.mockReturnValue(false);
|
|
67
73
|
mockIsStandardAccount.mockReturnValue(false);
|
|
68
74
|
mockIsAppDeveloperAccount.mockReturnValue(false);
|
|
69
75
|
await expect(handleTargetTestAccountSelectionFlow(derivedAccountId, undefined)).rejects.toThrow(lib.importData.errors.incorrectAccountType(derivedAccountId));
|
|
70
76
|
});
|
|
71
77
|
it('should return the derivedAccountId if it is a developer test account', async () => {
|
|
72
|
-
mockGetAccountConfig.mockReturnValue({});
|
|
73
78
|
mockIsDeveloperTestAccount.mockReturnValue(true);
|
|
79
|
+
mockGetConfigAccountById.mockReturnValue({
|
|
80
|
+
accountId: derivedAccountId,
|
|
81
|
+
});
|
|
74
82
|
const result = await handleTargetTestAccountSelectionFlow(derivedAccountId, undefined);
|
|
75
83
|
expect(result).toBe(derivedAccountId);
|
|
76
84
|
});
|
|
77
85
|
it('should return the result of the importDataTestAccountSelectPrompt if the derivedAccountId is a standard or app developer account', async () => {
|
|
78
|
-
mockGetAccountConfig.mockReturnValue({});
|
|
79
86
|
mockIsDeveloperTestAccount.mockReturnValue(false);
|
|
80
87
|
mockIsStandardAccount.mockReturnValue(true);
|
|
81
88
|
mockIsAppDeveloperAccount.mockReturnValue(true);
|
|
82
89
|
mockImportDataTestAccountSelectPrompt.mockResolvedValue({
|
|
83
90
|
selectedAccountId: 890223,
|
|
84
91
|
});
|
|
92
|
+
mockGetConfigAccountById.mockReturnValue({
|
|
93
|
+
accountId: derivedAccountId,
|
|
94
|
+
});
|
|
85
95
|
const result = await handleTargetTestAccountSelectionFlow(derivedAccountId, undefined);
|
|
86
96
|
expect(result).toBe(890223);
|
|
87
97
|
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import express from 'express';
|
|
2
2
|
import open from 'open';
|
|
3
3
|
import { OAuth2Manager } from '@hubspot/local-dev-lib/models/OAuth2Manager';
|
|
4
|
-
import {
|
|
4
|
+
import { getConfigAccountById } from '@hubspot/local-dev-lib/config';
|
|
5
5
|
import { addOauthToAccountConfig } from '@hubspot/local-dev-lib/oauth';
|
|
6
6
|
import { uiLogger } from '../ui/logger.js';
|
|
7
7
|
import { ENVIRONMENTS } from '@hubspot/local-dev-lib/constants/environments';
|
|
@@ -15,18 +15,22 @@ vi.mock('@hubspot/local-dev-lib/oauth');
|
|
|
15
15
|
vi.mock('../ui/logger.js');
|
|
16
16
|
const mockedExpress = express;
|
|
17
17
|
const mockedOAuth2Manager = OAuth2Manager;
|
|
18
|
-
const
|
|
18
|
+
const mockedGetConfigAccountById = getConfigAccountById;
|
|
19
19
|
describe('lib/oauth', () => {
|
|
20
20
|
const mockExpressReq = {
|
|
21
21
|
query: { code: 'test-auth-code' },
|
|
22
22
|
};
|
|
23
23
|
const mockExpressResp = { send: vi.fn() };
|
|
24
24
|
const mockAccountConfig = {
|
|
25
|
+
name: 'test-account',
|
|
25
26
|
accountId: 123,
|
|
26
|
-
|
|
27
|
-
clientSecret: 'test-client-secret',
|
|
28
|
-
scopes: ['test-scope'],
|
|
27
|
+
authType: 'oauth2',
|
|
29
28
|
env: ENVIRONMENTS.PROD,
|
|
29
|
+
auth: {
|
|
30
|
+
clientId: 'test-client-id',
|
|
31
|
+
clientSecret: 'test-client-secret',
|
|
32
|
+
scopes: ['test-scope'],
|
|
33
|
+
},
|
|
30
34
|
};
|
|
31
35
|
beforeEach(() => {
|
|
32
36
|
mockedExpress.mockReturnValue({
|
|
@@ -49,7 +53,7 @@ describe('lib/oauth', () => {
|
|
|
49
53
|
exchangeForTokens: vi.fn().mockResolvedValue({}),
|
|
50
54
|
};
|
|
51
55
|
mockedOAuth2Manager.mockImplementation(() => mockOAuth2Manager);
|
|
52
|
-
|
|
56
|
+
mockedGetConfigAccountById.mockReturnValue({
|
|
53
57
|
env: ENVIRONMENTS.PROD,
|
|
54
58
|
});
|
|
55
59
|
await authenticateWithOauth(mockAccountConfig);
|
|
@@ -66,7 +70,10 @@ describe('lib/oauth', () => {
|
|
|
66
70
|
it('should handle missing clientId', async () => {
|
|
67
71
|
const invalidConfig = {
|
|
68
72
|
...mockAccountConfig,
|
|
69
|
-
|
|
73
|
+
auth: {
|
|
74
|
+
...mockAccountConfig.auth,
|
|
75
|
+
clientId: undefined,
|
|
76
|
+
},
|
|
70
77
|
};
|
|
71
78
|
mockedOAuth2Manager.mockImplementation(() => ({
|
|
72
79
|
account: invalidConfig,
|
|
@@ -74,6 +81,7 @@ describe('lib/oauth', () => {
|
|
|
74
81
|
const exitSpy = vi.spyOn(process, 'exit').mockImplementation(() => {
|
|
75
82
|
throw new Error('exit');
|
|
76
83
|
});
|
|
84
|
+
// @ts-expect-error Testing invalid config
|
|
77
85
|
await expect(authenticateWithOauth(invalidConfig)).rejects.toThrow('exit');
|
|
78
86
|
expect(uiLogger.error).toHaveBeenCalled();
|
|
79
87
|
expect(exitSpy).toHaveBeenCalled();
|
|
@@ -82,7 +90,10 @@ describe('lib/oauth', () => {
|
|
|
82
90
|
it('should use default scopes when none provided', async () => {
|
|
83
91
|
const configWithoutScopes = {
|
|
84
92
|
...mockAccountConfig,
|
|
85
|
-
|
|
93
|
+
auth: {
|
|
94
|
+
...mockAccountConfig.auth,
|
|
95
|
+
scopes: [],
|
|
96
|
+
},
|
|
86
97
|
};
|
|
87
98
|
const mockOAuth2Manager = {
|
|
88
99
|
account: configWithoutScopes,
|