@boltic/cli 1.0.7 → 1.0.9

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/README.md CHANGED
@@ -519,15 +519,6 @@ npm install -g @boltic/cli@latest
519
519
  boltic --version
520
520
  ```
521
521
 
522
- **Development mode troubleshooting**:
523
-
524
- ```bash
525
- # For contributors using development installation
526
- npm install # Update dependencies
527
- npm link # Re-link CLI
528
- npm test # Run test suite
529
- ```
530
-
531
522
  #### 9. Emergency Recovery
532
523
 
533
524
  **If all else fails**:
@@ -0,0 +1 @@
1
+ # Ahmed_Test_Cases_Test Authentication
@@ -0,0 +1 @@
1
+ # Ahmed_Test_Cases_Test Documentation
@@ -0,0 +1,45 @@
1
+ {
2
+ "parameters": [
3
+ {
4
+ "name": "type",
5
+ "meta": {
6
+ "displayName": "Authentication Type",
7
+ "displayType": "select",
8
+ "placeholder": "Select an authentication type",
9
+ "description": "Choose the type of authentication you want to use.",
10
+ "options": [
11
+ {
12
+ "label": "API Key",
13
+ "value": "api_key"
14
+ }
15
+ ],
16
+ "value": "api_key",
17
+ "validation": {
18
+ "required": true,
19
+ "requiredDetail": {
20
+ "errorMsg": "Authentication type is required"
21
+ }
22
+ }
23
+ }
24
+ }
25
+ ],
26
+ "api_key": {
27
+ "parameters": [
28
+ {
29
+ "name": "api_key",
30
+ "meta": {
31
+ "displayName": "API Key",
32
+ "displayType": "password",
33
+ "placeholder": "Enter API Key",
34
+ "description": "Your API key for authentication",
35
+ "validation": {
36
+ "required": true,
37
+ "requiredDetail": {
38
+ "errorMsg": "API key is required"
39
+ }
40
+ }
41
+ }
42
+ }
43
+ ]
44
+ }
45
+ }
@@ -0,0 +1,56 @@
1
+ {
2
+ "parameters": [
3
+ {
4
+ "name": "secret",
5
+ "meta": {
6
+ "displayName": "Service Account",
7
+ "displayType": "autocomplete",
8
+ "placeholder": "Select Service Account",
9
+ "description": "Your service account credentials are encrypted & can be removed at any time.",
10
+ "options": [],
11
+ "config": {
12
+ "urlType": "secret",
13
+ "method": "get",
14
+ "url": "/AHMED_TEST_CASES_TEST?current_page=1&page_size=999",
15
+ "labelKey": "name",
16
+ "valueKey": "_id"
17
+ },
18
+ "htmlProps": {
19
+ "showAddNew": true
20
+ },
21
+ "value": "",
22
+ "validation": {
23
+ "required": true
24
+ }
25
+ }
26
+ },
27
+ {
28
+ "name": "resource",
29
+ "meta": {
30
+ "displayName": "Resource",
31
+ "displayType": "select",
32
+ "placeholder": "Select a resource",
33
+ "description": "Select the resource you want to work with.",
34
+ "options": [
35
+ {
36
+ "label": "Resource 1",
37
+ "value": "resource1",
38
+ "description": "Description for Resource 1"
39
+ }
40
+ ],
41
+ "value": "",
42
+ "validation": {
43
+ "required": true
44
+ },
45
+ "dependencies": {
46
+ "conditions": [
47
+ {
48
+ "field": "secret",
49
+ "operator": "NOT_EMPTY"
50
+ }
51
+ ]
52
+ }
53
+ }
54
+ }
55
+ ]
56
+ }
@@ -0,0 +1,134 @@
1
+ {
2
+ "parameters": [
3
+ {
4
+ "name": "operation",
5
+ "meta": {
6
+ "displayName": "Operation",
7
+ "displayType": "select",
8
+ "placeholder": "Select an operation",
9
+ "description": "Select the operation you want to perform.",
10
+ "options": [
11
+ {
12
+ "label": "Create Account",
13
+ "value": "resource1.create",
14
+ "description": "Create a new account."
15
+ },
16
+ {
17
+ "label": "Delete Account",
18
+ "value": "resource1.delete",
19
+ "description": "Delete an existing account."
20
+ }
21
+ ],
22
+ "validation": {
23
+ "required": true
24
+ },
25
+ "dependencies": {
26
+ "conditions": [
27
+ {
28
+ "field": "resource",
29
+ "operator": "EQUALS",
30
+ "value": "resource1"
31
+ }
32
+ ]
33
+ }
34
+ }
35
+ }
36
+ ],
37
+ "create": {
38
+ "definition": {
39
+ "method": "post",
40
+ "url": "https://dummyjson.com/products",
41
+ "headers": {
42
+ "ContentType": "application/json"
43
+ },
44
+ "body": "{{parameters}}",
45
+ "response": {
46
+ "output": "{{response.data}}",
47
+ "error": {
48
+ "message": "{{response.data.errors.message}}",
49
+ "code": "{{response.data.errors.code}}"
50
+ }
51
+ }
52
+ },
53
+ "parameters": [
54
+ {
55
+ "name": "name",
56
+ "meta": {
57
+ "displayName": "Product Name",
58
+ "displayType": "text",
59
+ "placeholder": "Enter the name of the product",
60
+ "description": "Enter the name of the product you want to create.",
61
+ "validation": {
62
+ "required": true
63
+ }
64
+ }
65
+ },
66
+ {
67
+ "name": "description",
68
+ "meta": {
69
+ "displayName": "Product Description",
70
+ "displayType": "text",
71
+ "placeholder": "Enter the description of the product",
72
+ "description": "Enter the description of the product you want to create.",
73
+ "validation": {
74
+ "required": true
75
+ }
76
+ }
77
+ },
78
+ {
79
+ "name": "price",
80
+ "meta": {
81
+ "displayName": "Product Price",
82
+ "displayType": "number",
83
+ "placeholder": "Enter the price of the product",
84
+ "description": "Enter the price of the product you want to create.",
85
+ "validation": {
86
+ "required": true
87
+ }
88
+ }
89
+ },
90
+ {
91
+ "name": "discountPercentage",
92
+ "meta": {
93
+ "displayName": "Discount Percentage",
94
+ "displayType": "number",
95
+ "placeholder": "Enter the discount percentage",
96
+ "description": "Enter the discount percentage for the product you want to create.",
97
+ "validation": {
98
+ "required": true
99
+ }
100
+ }
101
+ }
102
+ ]
103
+ },
104
+ "delete": {
105
+ "parameters": [
106
+ {
107
+ "name": "id",
108
+ "meta": {
109
+ "displayName": "Account ID",
110
+ "displayType": "text",
111
+ "placeholder": "Enter the Account ID",
112
+ "description": "Enter the ID of the account you want to delete.",
113
+ "validation": {
114
+ "required": true
115
+ }
116
+ }
117
+ }
118
+ ],
119
+ "definition": {
120
+ "method": "delete",
121
+ "url": "https://dummyjson.com/products/{{parameters.id}}",
122
+ "headers": {
123
+ "ContentType": "application/json"
124
+ },
125
+ "response": {
126
+ "output": "{{response.data}}",
127
+ "error": {
128
+ "message": "{{response.data.errors.message}}",
129
+ "code": "{{response.data.errors.code}}"
130
+ }
131
+ }
132
+ }
133
+ }
134
+ }
@@ -0,0 +1,17 @@
1
+ {
2
+ "id": "766689c4-e6c9-4adf-8b21-f69c3a281307",
3
+ "name": "Ahmed_Test_Cases_Test",
4
+ "description": {
5
+ "trigger": "",
6
+ "integration": "Sample Test Case Integration"
7
+ },
8
+ "icon": "https://cdn.pixelbin.io/v2/fyndcloud/original/Temporal/Uploads/bolt/e8b51f71-6062-4c30-958e-f87351ed13bf/images/Paddle_1752734761014.svg",
9
+ "activity_type": "customActivity",
10
+ "trigger_type": null,
11
+ "meta": {
12
+ "ai_description": {
13
+ "trigger": "",
14
+ "integration": "Sample AI Test Case Integration"
15
+ }
16
+ }
17
+ }
@@ -2,6 +2,7 @@ import { confirm, input, search } from "@inquirer/prompts";
2
2
  import chalk from "chalk";
3
3
  import fs from "fs";
4
4
  import path from "path";
5
+ import { execSync } from "child_process";
5
6
 
6
7
  import {
7
8
  editIntegration,
@@ -55,7 +56,7 @@ const commands = {
55
56
  action: handleStatus,
56
57
  },
57
58
  test: {
58
- description: "Run tests for the integration with coverage",
59
+ description: "Test an integration using Jest",
59
60
  action: handleTest,
60
61
  },
61
62
  help: {
@@ -133,6 +134,7 @@ async function handleSync(args) {
133
134
  // Parse command line arguments
134
135
  let currentDir = process.cwd();
135
136
  const pathIndex = args.indexOf("--path");
137
+ const skipValidation = args.includes("--no-verify");
136
138
 
137
139
  if (pathIndex !== -1 && args[pathIndex + 1]) {
138
140
  currentDir = args[pathIndex + 1];
@@ -193,27 +195,34 @@ async function handleSync(args) {
193
195
 
194
196
  console.log(chalk.cyan(`\nSyncing integration: ${specContent.name}`));
195
197
 
196
- console.log("Validating schemas...");
198
+ if (skipValidation) {
199
+ console.log(
200
+ chalk.yellow(
201
+ "āš ļø Skipping validation (--no-verify flag detected)"
202
+ )
203
+ );
204
+ } else {
205
+ console.log("Validating schemas...");
197
206
 
198
- // Validate resources
199
- const { validateIntegrationSchemas } = await import(
200
- "../helper/validation.js"
201
- );
202
- const validationResult = validateIntegrationSchemas(currentDir);
203
- if (!validationResult.success) {
204
- if (Array.isArray(validationResult.errors)) {
205
- validationResult.errors.forEach((error) => {
206
- console.error(chalk.red(`\nāŒ ${error}`));
207
- });
207
+ // Validate resources
208
+ const { validateIntegrationSchemas } = await import(
209
+ "../helper/validation.js"
210
+ );
211
+ const validationResult = validateIntegrationSchemas(currentDir);
212
+ if (!validationResult.success) {
213
+ if (Array.isArray(validationResult.errors)) {
214
+ validationResult.errors.forEach((error) => {
215
+ console.error(chalk.red(`\nāŒ ${error}`));
216
+ });
217
+ }
218
+ return;
208
219
  }
209
- return;
220
+ console.log(chalk.green("Schemas validated successfully"));
210
221
  }
211
222
 
212
223
  const schemas = await readSchemaFiles(currentDir);
213
224
  schemas.status = "draft";
214
225
 
215
- console.log(chalk.green("Schemas validated successfully"));
216
-
217
226
  const data = await syncIntegration(apiUrl, token, accountId, session, {
218
227
  integration_id: specContent.id,
219
228
  ...schemas,
@@ -245,6 +254,7 @@ async function handleSubmit(args) {
245
254
  // Parse command line arguments
246
255
  let currentDir = process.cwd();
247
256
  const pathIndex = args.indexOf("--path");
257
+ const skipValidation = args.includes("--no-verify");
248
258
 
249
259
  if (pathIndex !== -1 && args[pathIndex + 1]) {
250
260
  currentDir = args[pathIndex + 1];
@@ -304,28 +314,35 @@ async function handleSubmit(args) {
304
314
 
305
315
  console.log(chalk.cyan(`\nSyncing integration: ${specContent.name}`));
306
316
 
307
- console.log("Validating schemas...");
317
+ if (skipValidation) {
318
+ console.log(
319
+ chalk.yellow(
320
+ "āš ļø Skipping validation (--no-verify flag detected)"
321
+ )
322
+ );
323
+ } else {
324
+ console.log("Validating schemas...");
308
325
 
309
- // Validate resources
310
- const { validateIntegrationSchemas } = await import(
311
- "../helper/validation.js"
312
- );
313
- const validationResult = validateIntegrationSchemas(currentDir);
314
- if (!validationResult.success) {
315
- if (Array.isArray(validationResult.errors)) {
316
- validationResult.errors.forEach((error) => {
317
- console.error(chalk.red(`\nāŒ ${error}`));
318
- });
319
- }
326
+ // Validate resources
327
+ const { validateIntegrationSchemas } = await import(
328
+ "../helper/validation.js"
329
+ );
330
+ const validationResult = validateIntegrationSchemas(currentDir);
331
+ if (!validationResult.success) {
332
+ if (Array.isArray(validationResult.errors)) {
333
+ validationResult.errors.forEach((error) => {
334
+ console.error(chalk.red(`\nāŒ ${error}`));
335
+ });
336
+ }
320
337
 
321
- return;
338
+ return;
339
+ }
340
+ console.log(chalk.green("Schemas validated successfully"));
322
341
  }
323
342
 
324
343
  const schemas = await readSchemaFiles(currentDir);
325
344
  schemas.status = "draft";
326
345
 
327
- console.log(chalk.green("Schemas validated successfully"));
328
-
329
346
  const data = await syncIntegration(apiUrl, token, accountId, session, {
330
347
  integration_id: specContent.id,
331
348
  ...schemas,
@@ -921,35 +938,13 @@ async function handlePull(args) {
921
938
  }
922
939
  }
923
940
 
924
- // Show help for integration commands
925
941
  function showHelp() {
926
942
  console.log(chalk.cyan("\nIntegration Commands:\n"));
927
943
  Object.entries(commands).forEach(([cmd, details]) => {
928
944
  console.log(chalk.bold(`${cmd}`) + ` - ${details.description}`);
929
945
  });
930
-
931
- console.log(chalk.cyan("\nTest Command Usage:"));
932
- console.log(chalk.dim(" boltic integration test"));
933
- console.log(chalk.dim(" boltic integration test --path /path/to/project"));
934
- console.log(chalk.dim(" boltic integration test --config jest.config.js"));
935
- console.log(chalk.dim(" boltic integration test --watchAll"));
936
- console.log(chalk.dim(" boltic integration test --updateSnapshot"));
937
-
938
- console.log(chalk.cyan("\nSupported Flags:"));
939
- console.log(
940
- chalk.dim(" --path <directory> Run tests in specific directory")
941
- );
942
- console.log(
943
- chalk.dim(" --config <file> Use specific Jest config file")
944
- );
945
- console.log(
946
- chalk.dim(" --watchAll Watch all files for changes")
947
- );
948
- console.log(chalk.dim(" --updateSnapshot Update snapshots"));
949
- console.log(chalk.dim(" All other Jest CLI flags are supported"));
950
946
  }
951
947
 
952
- // Show detailed information about an integration
953
948
  async function handleStatus() {
954
949
  console.log(chalk.green("Fetching integration information...\n"));
955
950
 
@@ -1064,6 +1059,13 @@ async function handleStatus() {
1064
1059
  console.log(integration.documentation);
1065
1060
  }
1066
1061
  } catch (error) {
1062
+ if (
1063
+ error.message &&
1064
+ error.message.includes("User force closed the prompt")
1065
+ ) {
1066
+ console.log(chalk.yellow("\nāš ļø Operation cancelled by user"));
1067
+ return;
1068
+ }
1067
1069
  console.error(
1068
1070
  chalk.red("\nāŒ Error fetching integration status:"),
1069
1071
  error.message || "Unknown error"
@@ -1072,15 +1074,13 @@ async function handleStatus() {
1072
1074
  }
1073
1075
 
1074
1076
  async function handleTest(args) {
1075
- // Parse command line arguments
1077
+ console.log(chalk.green("Running integration tests...\n"));
1078
+
1076
1079
  let currentDir = process.cwd();
1077
- let jestConfigFile = null;
1078
1080
  const pathIndex = args.indexOf("--path");
1079
- const configIndex = args.indexOf("--config");
1080
1081
 
1081
1082
  if (pathIndex !== -1 && args[pathIndex + 1]) {
1082
1083
  currentDir = args[pathIndex + 1];
1083
- // Validate the provided path
1084
1084
  if (!fs.existsSync(currentDir)) {
1085
1085
  console.error(
1086
1086
  chalk.red(
@@ -1091,236 +1091,41 @@ async function handleTest(args) {
1091
1091
  }
1092
1092
  }
1093
1093
 
1094
- if (configIndex !== -1 && args[configIndex + 1]) {
1095
- jestConfigFile = args[configIndex + 1];
1096
- // Validate the config file path
1097
- const configPath = path.isAbsolute(jestConfigFile)
1098
- ? jestConfigFile
1099
- : path.join(currentDir, jestConfigFile);
1100
-
1101
- if (!fs.existsSync(configPath)) {
1102
- console.error(
1103
- chalk.red(
1104
- `Error: Jest config file does not exist: ${configPath}`
1105
- )
1106
- );
1107
- return;
1108
- }
1109
- }
1110
-
1111
- const { spawn } = await import("child_process");
1112
-
1113
- console.log(chalk.cyan.bold("\n🧪 Running integration tests...\n"));
1114
-
1115
- // Look for test directory and test files
1116
- const testDirs = ["test", "tests", "__tests__"];
1117
- let testDir = null;
1118
- let testFiles = [];
1119
-
1120
- // Check for test directories
1121
- for (const dir of testDirs) {
1122
- const testPath = path.join(currentDir, dir);
1123
- if (fs.existsSync(testPath)) {
1124
- testDir = dir;
1125
- // Find all test files in the directory
1126
- const files = fs.readdirSync(testPath);
1127
- testFiles = files.filter(
1128
- (file) =>
1129
- file.endsWith(".test.js") ||
1130
- file.endsWith(".spec.js") ||
1131
- file.endsWith(".test.ts") ||
1132
- file.endsWith(".spec.ts")
1133
- );
1134
- break;
1135
- }
1136
- }
1137
-
1138
- // If no test directory found, look for test files in current directory
1139
- if (!testDir) {
1140
- const currentDirFiles = fs.readdirSync(currentDir);
1141
- testFiles = currentDirFiles.filter(
1142
- (file) =>
1143
- file.endsWith(".test.js") ||
1144
- file.endsWith(".spec.js") ||
1145
- file.endsWith(".test.ts") ||
1146
- file.endsWith(".spec.ts")
1147
- );
1148
-
1149
- if (testFiles.length === 0) {
1150
- console.log(
1151
- chalk.yellow(
1152
- "āš ļø No test files found. Looked for: test, tests, __tests__ directories and *.test.js, *.spec.js, *.test.ts, *.spec.ts files"
1153
- )
1154
- );
1155
- return;
1156
- }
1157
- }
1158
-
1159
- if (testFiles.length === 0 && testDir) {
1160
- console.log(
1161
- chalk.yellow(
1162
- `āš ļø No test files found in ${testDir} directory. Looking for: *.test.js, *.spec.js, *.test.ts, *.spec.ts files`
1094
+ const specPath = path.join(currentDir, "spec.json");
1095
+ if (!fs.existsSync(specPath)) {
1096
+ console.error(
1097
+ chalk.red(
1098
+ "Error: No spec.json file found in the current directory. Please ensure you're in an integration directory."
1163
1099
  )
1164
1100
  );
1165
1101
  return;
1166
1102
  }
1167
1103
 
1168
- console.log(chalk.dim(`šŸ“ Found test directory: ${testDir || currentDir}`));
1169
- console.log(
1170
- chalk.dim(
1171
- `šŸ“‹ Found ${testFiles.length} test file(s): ${testFiles.join(", ")}`
1172
- )
1173
- );
1174
-
1175
- // Check for Jest configuration
1176
- let jestConfigPath;
1177
- if (jestConfigFile) {
1178
- jestConfigPath = path.isAbsolute(jestConfigFile)
1179
- ? jestConfigFile
1180
- : path.join(currentDir, jestConfigFile);
1181
- } else {
1182
- // Look for default config files
1183
- const defaultConfigs = [
1184
- "jest.config.cjs",
1185
- "jest.config.js",
1186
- "jest.config.json",
1187
- ];
1188
- for (const configFile of defaultConfigs) {
1189
- const configPath = path.join(currentDir, configFile);
1190
- if (fs.existsSync(configPath)) {
1191
- jestConfigPath = configPath;
1192
- break;
1193
- }
1194
- }
1195
- }
1196
-
1197
- const jestConfigExists = !!jestConfigPath;
1198
- const configFileName = jestConfigPath
1199
- ? path.basename(jestConfigPath)
1200
- : null;
1201
-
1202
- console.log(
1203
- chalk.dim(
1204
- `āš™ļø Jest configuration: ${jestConfigExists ? `Found ${configFileName}` : "Using default configuration"}`
1205
- )
1206
- );
1207
-
1208
- // Prepare Jest arguments
1209
- const jestArgs = ["jest"];
1210
-
1211
- // Add basic Jest flags
1212
- jestArgs.push("--coverage");
1213
- jestArgs.push("--verbose");
1214
- jestArgs.push("--colors");
1215
- jestArgs.push("--passWithNoTests");
1216
-
1217
- // Add config file if exists, otherwise use simple patterns
1218
- if (jestConfigExists) {
1219
- jestArgs.push("--config", jestConfigPath);
1220
- } else {
1221
- // Use simple test matching patterns
1222
- if (testDir) {
1223
- jestArgs.push(
1224
- "--testMatch",
1225
- `**/${testDir}/**/*.{test,spec}.{js,ts}`
1226
- );
1227
- } else {
1228
- jestArgs.push("--testMatch", "**/*.{test,spec}.{js,ts}");
1229
- }
1230
- jestArgs.push("--collectCoverageFrom", "lib/**/*.{js,ts}");
1231
- jestArgs.push("--collectCoverageFrom", "src/**/*.{js,ts}");
1232
- jestArgs.push("--collectCoverageFrom", "*.{js,ts}");
1233
- jestArgs.push("--coveragePathIgnorePatterns", "/node_modules/");
1234
- jestArgs.push("--coveragePathIgnorePatterns", "/tests/");
1235
- }
1236
-
1237
- // Add any additional Jest arguments passed by user
1238
- const additionalArgs = args.filter((arg, index) => {
1239
- // Skip our custom flags and their values
1240
- if (arg === "--path" || arg === "--config") return false;
1241
- if (args[index - 1] === "--path" || args[index - 1] === "--config")
1242
- return false;
1243
- return true;
1244
- });
1245
-
1246
- if (additionalArgs.length > 0) {
1247
- jestArgs.push(...additionalArgs);
1248
- console.log(
1249
- chalk.dim(
1250
- `šŸ”§ Additional Jest arguments: ${additionalArgs.join(" ")}`
1104
+ const testsDir = path.join(currentDir, "__tests__");
1105
+ if (!fs.existsSync(testsDir)) {
1106
+ console.error(
1107
+ chalk.red(
1108
+ "Error: No __tests__ directory found. Please create test files in a __tests__ directory."
1251
1109
  )
1252
1110
  );
1111
+ return;
1253
1112
  }
1254
1113
 
1255
- console.log(chalk.dim(`šŸš€ Running command: npx ${jestArgs.join(" ")}`));
1256
- console.log(chalk.cyan("─".repeat(50)));
1114
+ try {
1115
+ console.log(chalk.cyan("Running Jest tests...\n"));
1257
1116
 
1258
- // Run Jest with coverage
1259
- return new Promise((resolve, reject) => {
1260
- const jestProcess = spawn("npx", jestArgs, {
1117
+ const testCommand = `npx jest "${testsDir}" --verbose`;
1118
+ execSync(testCommand, {
1261
1119
  stdio: "inherit",
1262
- shell: true,
1263
1120
  cwd: currentDir,
1264
1121
  });
1265
1122
 
1266
- jestProcess.on("close", (code) => {
1267
- console.log(chalk.cyan("─".repeat(50)));
1268
-
1269
- if (code === 0) {
1270
- console.log(chalk.green.bold("\nāœ… All tests passed!"));
1271
-
1272
- // Check for coverage directory
1273
- const coverageDir = path.join(currentDir, "coverage");
1274
- if (fs.existsSync(coverageDir)) {
1275
- console.log(chalk.cyan("\nšŸ“Š Coverage Report Generated:"));
1276
- console.log(chalk.dim(` Directory: ${coverageDir}`));
1277
-
1278
- // Check for HTML report
1279
- const htmlReportPath = path.join(
1280
- coverageDir,
1281
- "lcov-report",
1282
- "index.html"
1283
- );
1284
- if (fs.existsSync(htmlReportPath)) {
1285
- console.log(
1286
- chalk.dim(` HTML Report: ${htmlReportPath}`)
1287
- );
1288
- }
1289
-
1290
- // Check for text report
1291
- const textReportPath = path.join(coverageDir, "lcov.info");
1292
- if (fs.existsSync(textReportPath)) {
1293
- console.log(
1294
- chalk.dim(` LCOV Report: ${textReportPath}`)
1295
- );
1296
- }
1297
- }
1298
-
1299
- // Show test summary
1300
- console.log(chalk.cyan("\nšŸ“‹ Test Summary:"));
1301
- console.log(chalk.dim(` Test files: ${testFiles.length}`));
1302
- console.log(
1303
- chalk.dim(` Test directory: ${testDir || currentDir}`)
1304
- );
1305
- console.log(chalk.green(" Status: PASSED"));
1306
- } else {
1307
- console.log(chalk.red.bold("\nāŒ Some tests failed."));
1308
- console.log(chalk.red(` Exit code: ${code}`));
1309
- }
1310
-
1311
- console.log(
1312
- chalk.cyan(
1313
- "\nšŸ’” Tip: Check the coverage directory for detailed coverage reports"
1314
- )
1315
- );
1316
- resolve(code);
1317
- });
1318
-
1319
- jestProcess.on("error", (error) => {
1320
- console.error(chalk.red("āŒ Error running tests:"), error.message);
1321
- reject(error);
1322
- });
1323
- });
1123
+ console.log(chalk.green("\nāœ“ All tests completed successfully!"));
1124
+ } catch (error) {
1125
+ console.error(chalk.red("\nāœ— Tests failed with errors:"));
1126
+ console.error(chalk.red(error.message));
1127
+ process.exit(1);
1128
+ }
1324
1129
  }
1325
1130
 
1326
1131
  export default {
@@ -150,6 +150,17 @@ const validateSchemaKeys = (
150
150
  Object.keys(schemaObj).forEach((key) => {
151
151
  const fullKey = prefix ? `${prefix}.${key}` : key;
152
152
 
153
+ // Special handling for config.body - skip validation for select, autocomplete, and multiselect
154
+ if (
155
+ fullKey === "config.body" &&
156
+ (displayType === "select" ||
157
+ displayType === "autocomplete" ||
158
+ displayType === "multiselect")
159
+ ) {
160
+ // For these display types, config.body can contain any keys, so we skip validation
161
+ return;
162
+ }
163
+
153
164
  if (!allowedKeys.has(fullKey)) {
154
165
  errors.add(
155
166
  `"${schemaName}" has an invalid key "${fullKey}" for displayType "${displayType}"${fileLabel}.`
@@ -159,7 +170,14 @@ const validateSchemaKeys = (
159
170
  if (
160
171
  typeof schemaObj[key] === "object" &&
161
172
  schemaObj[key] !== null &&
162
- !Array.isArray(schemaObj[key])
173
+ !Array.isArray(schemaObj[key]) &&
174
+ // Skip recursion for config.body of select/autocomplete/multiselect
175
+ !(
176
+ fullKey === "config.body" &&
177
+ (displayType === "select" ||
178
+ displayType === "autocomplete" ||
179
+ displayType === "multiselect")
180
+ )
163
181
  ) {
164
182
  validateSchemaKeys(
165
183
  schemaObj[key],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@boltic/cli",
3
- "version": "1.0.7",
3
+ "version": "1.0.9",
4
4
  "description": "A powerful CLI tool for managing Boltic Workflow integrations",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -679,6 +679,21 @@ const multiselect = {
679
679
  requiredDetail: {
680
680
  errorMsg: "Selection is required",
681
681
  },
682
+ min: 1,
683
+ minDetail: {
684
+ errorMsg: "At least one option is required",
685
+ },
686
+ max: 10,
687
+ maxDetail: {
688
+ errorMsg: "Too many options",
689
+ },
690
+ pattern: "^[a-zA-Z]+$",
691
+ patternDetail: {
692
+ errorMsg: "Value must be a valid name",
693
+ },
694
+ },
695
+ htmlProps: {
696
+ allowDynamic: false,
682
697
  },
683
698
  dependencies: {
684
699
  logic: "AND",
@@ -914,6 +929,29 @@ const button = {
914
929
  },
915
930
  };
916
931
 
932
+ const datetime = {
933
+ name: "datetime-picker",
934
+ meta: {
935
+ displayName: "Enter Date with Start Time",
936
+ description: "Please enter date and start time",
937
+ displayType: "datetime",
938
+ value: "2024-02-14",
939
+ validation: {
940
+ required: false,
941
+ },
942
+ readOnly: false,
943
+ htmlProps: {
944
+ format: "YYYY-MM-DD HH:mm:ss",
945
+ disabled: false,
946
+ timeSteps: {
947
+ hours: 1,
948
+ minutes: 5,
949
+ seconds: 5,
950
+ },
951
+ },
952
+ },
953
+ };
954
+
917
955
  export {
918
956
  accordion,
919
957
  array,
@@ -922,6 +960,7 @@ export {
922
960
  checkbox,
923
961
  code,
924
962
  date,
963
+ datetime,
925
964
  divider,
926
965
  email,
927
966
  file,