@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 +0 -9
- package/ahmed_test_cases_test/Authentication.mdx +1 -0
- package/ahmed_test_cases_test/Documentation.mdx +1 -0
- package/ahmed_test_cases_test/schemas/authentication.json +45 -0
- package/ahmed_test_cases_test/schemas/base.json +56 -0
- package/ahmed_test_cases_test/schemas/resources/resource1.json +134 -0
- package/ahmed_test_cases_test/spec.json +17 -0
- package/commands/integration.js +77 -272
- package/helper/validation.js +19 -1
- package/package.json +1 -1
- package/templates/component-schemas.js +39 -0
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
|
+
}
|
package/commands/integration.js
CHANGED
|
@@ -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: "
|
|
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
|
-
|
|
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
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
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
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
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
|
-
|
|
1256
|
-
|
|
1114
|
+
try {
|
|
1115
|
+
console.log(chalk.cyan("Running Jest tests...\n"));
|
|
1257
1116
|
|
|
1258
|
-
|
|
1259
|
-
|
|
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
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
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 {
|
package/helper/validation.js
CHANGED
|
@@ -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
|
@@ -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,
|