@skyramp/skyramp 1.0.0-sha.b2dfe11 → 1.2.2

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.
Files changed (46) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +10 -17
  3. package/package.json +14 -5
  4. package/scripts/download-binary.js +189 -0
  5. package/src/classes/Asserts.d.ts +16 -0
  6. package/src/classes/Asserts.js +41 -0
  7. package/src/classes/AsyncScenario.d.ts +133 -0
  8. package/src/classes/AsyncScenario.js +324 -0
  9. package/src/classes/AsyncTestStatus.d.ts +172 -0
  10. package/src/classes/AsyncTestStatus.js +488 -0
  11. package/src/classes/DelayConfig.d.ts +4 -0
  12. package/src/classes/DelayConfig.js +25 -0
  13. package/src/classes/Endpoint.d.ts +2 -2
  14. package/src/classes/Endpoint.js +81 -43
  15. package/src/classes/GrpcEndpoint.d.ts +1 -1
  16. package/src/classes/GrpcEndpoint.js +24 -3
  17. package/src/classes/LoadTestConfig.d.ts +131 -0
  18. package/src/classes/LoadTestConfig.js +186 -0
  19. package/src/classes/Protocol.d.ts +5 -0
  20. package/src/classes/Protocol.js +8 -0
  21. package/src/classes/RequestV2.d.ts +30 -0
  22. package/src/classes/RequestV2.js +181 -0
  23. package/src/classes/RequestValue.d.ts +24 -0
  24. package/src/classes/RequestValue.js +113 -0
  25. package/src/classes/ResponseV2.d.ts +24 -0
  26. package/src/classes/ResponseV2.js +96 -0
  27. package/src/classes/ResponseValue.d.ts +21 -0
  28. package/src/classes/ResponseValue.js +93 -0
  29. package/src/classes/RestEndpoint.d.ts +11 -2
  30. package/src/classes/RestEndpoint.js +90 -5
  31. package/src/classes/RestParam.d.ts +4 -0
  32. package/src/classes/RestParam.js +32 -0
  33. package/src/classes/Scenario.d.ts +48 -0
  34. package/src/classes/Scenario.js +208 -0
  35. package/src/classes/SkyrampClient.d.ts +184 -4
  36. package/src/classes/SkyrampClient.js +774 -40
  37. package/src/classes/Step.d.ts +28 -0
  38. package/src/classes/Step.js +113 -0
  39. package/src/classes/TrafficConfig.d.ts +6 -0
  40. package/src/classes/TrafficConfig.js +28 -0
  41. package/src/function.js +46 -0
  42. package/src/index.d.ts +14 -1
  43. package/src/index.js +36 -3
  44. package/src/lib.js +6 -6
  45. package/src/utils.js +180 -20
  46. package/src/utils.d.ts +0 -5
@@ -0,0 +1,113 @@
1
+ /**
2
+ * @typedef {Object} RequestValueOptions
3
+ * @property {string} name - The name of the request.
4
+ * @property {Object} endpoint - The descriptor for the endpoint of the request.
5
+ * @property {string} methodType - The type of HTTP method for the request.
6
+ * @property {string} methodName - The name of the method for the request.
7
+ * @property {Object} params - The parameters for the request.
8
+ * @property {Object} headers - The headers for the request.
9
+ * @property {Object} vars - The variables for the request.
10
+ * @property {Object} blob - The blob data for the request.
11
+ * @property {string} javascriptPath - The path to the JavaScript file for the request.
12
+ * @property {string} javascriptFunction - The JavaScript function for the request.
13
+ */
14
+
15
+ /**
16
+ * The `RequestValue` class represents a request value to use for testing API endpoint methods.
17
+ * @class
18
+ */
19
+ class RequestValue {
20
+ /**
21
+ * Initialize a new instance of a RequestValue.
22
+ * @constructor
23
+ * @param {RequestValueOptions} options - The options for initializing the RequestValue object.
24
+ */
25
+ constructor(options) {
26
+ this.name = options.name;
27
+ this.endpointDescriptor = options.endpoint;
28
+ this.methodType = options.methodType;
29
+ this.methodName = options.methodName
30
+ this.params = options.params;
31
+ this.headers = options.headers;
32
+ this.vars = options.vars;
33
+ this.blob = options.blob ? JSON.stringify(options.blob) : undefined;
34
+ this.graphqlParam = options.graphqlParam;
35
+ this.javascriptPath = options.javascriptPath;
36
+ this.javascript = options.javascriptFunction;
37
+ }
38
+
39
+ setCookieValue(cookieValue) {
40
+ this.cookieValue = cookieValue
41
+ }
42
+
43
+ setResponse(responseValue) {
44
+ this.responseValue = responseValue
45
+ }
46
+
47
+ toJson() {
48
+ return this.name
49
+ }
50
+
51
+ asRequestDict(globalHeaders=undefined) {
52
+ if (this.endpointDescriptor === undefined || this.endpointDescriptor === null) {
53
+ throw new Error(`endpoint descriptor not found. Request descriptor: ${this}`)
54
+ }
55
+ const descriptor = this.endpointDescriptor;
56
+ const endpoint = descriptor.endpoint;
57
+ const endpointName = endpoint.name;
58
+ if (endpointName === undefined || endpointName === null) {
59
+ throw new Error(`endpoint name not found. Endpoint descriptor: ${descriptor}`)
60
+ }
61
+ let methodName = this.methodName;
62
+ if (this.methodName === undefined || this.methodName === null) {
63
+ methodName = descriptor.getMethodNameForMethodType(this.methodType)
64
+ }
65
+ const requestDict = {
66
+ name: this.name,
67
+ endpointName: endpointName,
68
+ methodName: methodName,
69
+ }
70
+ if (globalHeaders !== undefined && globalHeaders !== null) {
71
+ requestDict.headers = {};
72
+ }
73
+ if (globalHeaders !== undefined && globalHeaders !== null) {
74
+ requestDict.headers = globalHeaders;
75
+ }
76
+ if (this.headers !== undefined && this.headers !== null) {
77
+ // Merge requestDict.headers and this.headers
78
+ requestDict.headers = {...requestDict.headers, ...this.headers};
79
+ }
80
+ if (this.params !== undefined && this.params !== null) {
81
+ requestDict.params = this.params;
82
+ }
83
+ if (this.blob !== undefined && this.blob !== null) {
84
+ requestDict.blob = this.blob;
85
+ }
86
+ if (this.graphqlParam!== undefined && this.graphqlParam!== null) {
87
+ requestDict.graphqlParam = this.graphqlParam;
88
+ }
89
+ if (this.vars !== undefined && this.vars !== null) {
90
+ requestDict.vars = this.vars;
91
+ }
92
+ if (this.javascriptPath !== undefined && this.javascriptPath !== null) {
93
+ requestDict.javascriptPath = this.javascriptPath;
94
+ }
95
+ if (this.javascript !== undefined && this.javascript !== null) {
96
+ requestDict.javascript = this.javascript;
97
+ }
98
+ return requestDict;
99
+ }
100
+
101
+ setOverrides(requestDict) {
102
+ // Sets the override value for this step
103
+ if (this.cookieValue !== undefined && this.cookieValue !== null) {
104
+ requestDict["cookies"] = this.cookieValue;
105
+ }
106
+
107
+ if (this.responseValue !== undefined && this.responseValue !== null) {
108
+ requestDict["override"] = this.responseValue;
109
+ }
110
+ }
111
+ }
112
+
113
+ module.exports = RequestValue;
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Represents a REST response.
3
+ */
4
+ interface ResponseV2Options {
5
+ description?: string;
6
+ error?: string;
7
+ path?: string;
8
+ method?: string;
9
+ statusCode?: string;
10
+ responseHeaders?: {[headerName: string]: string};
11
+ responseBody?: string;
12
+ requestHeaders?: {[headerName: string]: string};
13
+ requestBody?: string;
14
+ duration?: string;
15
+ }
16
+
17
+ export declare class ResponseV2 {
18
+ /**
19
+ * Creates a new instance of ResponseV2.
20
+ * @param options - The options for creating the response.
21
+ */
22
+ constructor(options?: ResponseV2Options);
23
+ toYaml(): string;
24
+ }
@@ -0,0 +1,96 @@
1
+ const yaml = require('js-yaml');
2
+ /**
3
+ * Represents a REST response.
4
+ */
5
+ class ResponseV2 {
6
+
7
+ /**
8
+ * Creates a new ResponseV2 instance
9
+ * @param {Object} options - The options for creating the response
10
+ * @param {string} [options.path=''] - The request path
11
+ * @param {string} [options.method=''] - The HTTP method used
12
+ * @param {string} [options.status_code=''] - The HTTP status code of the response
13
+ * @param {Object} [options.response_headers={}] - Headers included in the response
14
+ * @param {string} [options.response_body=''] - Body of the response
15
+ * @param {Object} [options.request_headers={}] - Headers included in the request
16
+ * @param {string} [options.request_body=''] - Body of the request
17
+ * @param {string} [options.duration=''] - Duration of the request/response cycle
18
+ */
19
+ constructor(options = {}) {
20
+ this.path = options.path || '';
21
+ this.method = options.method || '';
22
+ this.statusCode = options.status_code || '';
23
+ this.responseHeaders = options.response_headers || {};
24
+ this.responseBody = options.response_body || '';
25
+ this.requestHeaders = options.request_headers || {};
26
+ this.requestBody = options.request_body || '';
27
+ this.duration = options.duration || '';
28
+ this.error = options.error || '';
29
+ this.description = options.description || '';
30
+ }
31
+
32
+ toYaml() {
33
+ // Map of camelCase to snake_case field names
34
+ const fieldMappings = {
35
+ path: 'path',
36
+ method: 'method',
37
+ statusCode: 'status_code',
38
+ responseHeaders: 'response_headers',
39
+ responseBody: 'response_body',
40
+ requestHeaders: 'request_headers',
41
+ requestBody: 'request_body',
42
+ duration: 'duration',
43
+ error: 'error',
44
+ description: 'description'
45
+ };
46
+
47
+ const { body, ...rest } = this;
48
+ // Create object with non-empty values and convert to snake_case
49
+ const yamlObject = Object.entries(rest).reduce((acc, [key, value]) => {
50
+ // Include field only if it's not empty (empty string, empty object, or empty array)
51
+ if (value && (typeof value !== 'object' || Object.keys(value).length > 0)) {
52
+ // Use snake_case key if mapping exists, otherwise use original key
53
+ const snakeKey = fieldMappings[key] || key;
54
+ acc[snakeKey] = value;
55
+ }
56
+ return acc;
57
+ }, {});
58
+
59
+ // Add body if it exists
60
+ if (body) {
61
+ yamlObject.body = JSON.stringify(body, null, 2);
62
+ }
63
+
64
+ return yaml.dump(yamlObject);
65
+ }
66
+
67
+ toJson() {
68
+ // Use the same field mappings as toYaml for consistency
69
+ const fieldMappings = {
70
+ path: 'path',
71
+ method: 'method',
72
+ statusCode: 'status_code',
73
+ responseHeaders: 'response_headers',
74
+ responseBody: 'response_body',
75
+ requestHeaders: 'request_headers',
76
+ requestBody: 'request_body',
77
+ duration: 'duration',
78
+ error: 'error',
79
+ description: 'description'
80
+ };
81
+
82
+ const { ...rest } = this;
83
+ // Create object with non-empty values and convert to snake_case
84
+ const jsonObject = Object.entries(rest).reduce((acc, [key, value]) => {
85
+ if (value && (typeof value !== 'object' || Object.keys(value).length > 0)) {
86
+ const snakeKey = fieldMappings[key] || key;
87
+ acc[snakeKey] = value;
88
+ }
89
+ return acc;
90
+ }, {});
91
+ return JSON.stringify(jsonObject, null, 2);
92
+ }
93
+ }
94
+
95
+
96
+ module.exports = ResponseV2;
@@ -0,0 +1,21 @@
1
+ import { Endpoint } from './Endpoint';
2
+ import { RestParam } from './RestParam';
3
+ interface ResponseValueOptions {
4
+ name: string;
5
+ endpoint: Endpoint;
6
+ methodType?: string;
7
+ methodName?: string;
8
+ params?: RestParam[];
9
+ headers?: Map<string, string>;
10
+ vars?: Map<string, string | number>;
11
+ blob?: string;
12
+ javascriptPath?: string;
13
+ javascriptFunction?: string;
14
+ }
15
+
16
+ export declare class ResponseValue {
17
+ constructor(options: ResponseValueOptions)
18
+ toJson() : ResponseValue
19
+ setCookieValue(cookieValue: string) : void
20
+ setResponse(responseValue: ResponseValue) : void
21
+ }
@@ -0,0 +1,93 @@
1
+ /**
2
+ * @typedef {Object} ResponseValueOptions
3
+ * @property {string} name - The name of the response value.
4
+ * @property {Object} endpoint - The descriptor of the endpoint associated with the response.
5
+ * @property {string} methodType - The type of the HTTP method used for the response.
6
+ * @property {string} methodName - The name of the method used for the response.
7
+ * @property {Object} params - The parameters of the response.
8
+ * @property {Object} headers - The headers of the response.
9
+ * @property {Object} vars - The variables of the response.
10
+ * @property {string} blob - The blob data of the response.
11
+ * @property {string} javascriptPath - The path to the JavaScript file associated with the response.
12
+ * @property {string} javascriptFunction - The JavaScript function associated with the response.
13
+ */
14
+
15
+ /**
16
+ * The `ResponseValue` class represents a response value to use for mocking API endpoint methods.
17
+ * @class
18
+ */
19
+ class ResponseValue {
20
+ /**
21
+ * Initialize a new instance of a ResponseValue.
22
+ * @constructor
23
+ * @param {ResponseValueOptions} options - The options for initializing the ResponseValue object.
24
+ */
25
+ constructor(options) {
26
+ this.name = options.name;
27
+ this.endpointDescriptor = options.endpoint;
28
+ this.methodType = options.methodType;
29
+ this.methodName = options.methodName
30
+ this.params = options.params;
31
+ this.headers = options.headers;
32
+ this.vars = options.vars;
33
+ this.blob = options.blob ? JSON.stringify(options.blob) : undefined;
34
+ this.javascriptPath = options.javascriptPath;
35
+ this.javascript = options.javascriptFunction;
36
+
37
+ this.trafficConfig = null;
38
+ }
39
+
40
+ setTrafficConfig(trafficConfig) {
41
+ this.trafficConfig = trafficConfig;
42
+ }
43
+
44
+ setCookieValue(cookieValue) {
45
+ this.cookieValue = cookieValue
46
+ }
47
+
48
+ setResponse(responseValue) {
49
+ this.responseValue = responseValue
50
+ }
51
+
52
+ toJson() {
53
+ if (this.endpointDescriptor === undefined || this.endpointDescriptor === null) {
54
+ throw new Error(`endpoint descriptor not found. Endpoint descriptor: ${this}`)
55
+ }
56
+ const descriptor = this.endpointDescriptor;
57
+ const endpoint = descriptor.endpoint;
58
+ const endpointName = endpoint.name;
59
+ if (endpointName === undefined || endpointName === null) {
60
+ throw new Error(`endpoint name not found. Endpoint descriptor: ${descriptor}`)
61
+ }
62
+ let methodName = this.methodName;
63
+ if (this.methodName === undefined || this.methodName === null) {
64
+ methodName = descriptor.getMethodNameForMethodType(this.methodType)
65
+ }
66
+ const response = {
67
+ name: this.name,
68
+ endpointName: endpointName,
69
+ methodName: methodName,
70
+ }
71
+ if (this.headers !== undefined && this.headers !== null) {
72
+ response.headers = this.headers;
73
+ }
74
+ if (this.params !== undefined && this.params !== null) {
75
+ response.params = this.params;
76
+ }
77
+ if (this.blob !== undefined && this.blob !== null) {
78
+ response.blob = this.blob;
79
+ }
80
+ if (this.vars !== undefined && this.vars !== null) {
81
+ response.vars = this.vars;
82
+ }
83
+ if (this.javascriptPath !== undefined && this.javascriptPath !== null) {
84
+ response.javascriptPath = this.javascriptPath;
85
+ }
86
+ if (this.javascript !== undefined && this.javascript !== null) {
87
+ response.javascript = this.javascript;
88
+ }
89
+ return response;
90
+ }
91
+ }
92
+
93
+ module.exports = ResponseValue;
@@ -1,4 +1,13 @@
1
1
  import { Endpoint } from './Endpoint';
2
+ interface RestEndpointOptions {
3
+ serviceName: string,
4
+ port: number,
5
+ restPath?: string,
6
+ methodType?: string[], // GET, POST, PUT, DELETE, PATCH
7
+ endpointAddress?: string,
8
+ subProtocol?: string,
9
+ }
2
10
  export declare class RestEndpoint extends Endpoint {
3
- constructor(name: string, openApiTag: string, port: number, openapiFile: string);
4
- }
11
+ constructor(name: string, openApiTag: string, port: number, openapiFile: string, endpointAddress: string);
12
+ constructor(options: RestEndpointOptions);
13
+ }
@@ -1,12 +1,97 @@
1
1
  const Endpoint = require('./Endpoint');
2
2
  const lib = require('../lib');
3
- const newRestEndpointWrapper = lib.func('newRestEndpointWrapper', 'string', ['string', 'string', 'int', 'string']);
3
+ const newRestEndpointWrapper = lib.func('newRestEndpointWrapper', 'string', ['string', 'string', 'int', 'string', 'string']);
4
4
 
5
+ /**
6
+ * The `RestEndpoint` class represents a REST API Endpoint.
7
+ * @class
8
+ */
5
9
  class RestEndpoint extends Endpoint {
6
- constructor(name, openApiTag, port, openapiFile) {
7
- const response = newRestEndpointWrapper(name, openApiTag, port, openapiFile);
8
- super(response);
10
+ /**
11
+ * Intialize a new instance of a REST endpoint.
12
+ * @extends Endpoint
13
+ * @constructor
14
+ * @param {...*} args - The arguments to create the REST endpoint.
15
+ * @throws {Error} If the arguments are invalid.
16
+ */
17
+ constructor(...args) {
18
+ let restEndPointData;
19
+ let endpointAddress;
20
+ if (args.length === 1 && typeof args[0] === 'object') {
21
+ restEndPointData = createEndpoint(args[0]);
22
+ endpointAddress = args[0].endpointAddress;
23
+ } else if (args.length >= 4) {
24
+ // eslint-disable-next-line no-unused-vars
25
+ const [name, openApiTag, port, openapiFile, endpointAddress] = args;
26
+
27
+ // TODO: Add restPath support
28
+ restEndPointData = newRestEndpointWrapper(name, openApiTag, port, openapiFile, "");
29
+ }
30
+ super(restEndPointData, endpointAddress);
31
+ }
32
+ }
33
+
34
+ function createEndpoint({ serviceName, port, restPath, methodTypes, subProtocol }) {
35
+ // Validate required arguments
36
+ if (typeof serviceName !== 'string' || serviceName.length === 0) {
37
+ throw new Error('serviceName must be a non-empty string');
38
+ }
39
+ if (typeof port !== 'number' || isNaN(port) || port <= 0) {
40
+ throw new Error('port must be a positive number');
41
+ }
42
+ if (!Array.isArray(methodTypes) || methodTypes.length === 0) {
43
+ throw new Error('methodTypes must be a non-empty array');
9
44
  }
45
+ if (restPath !== undefined && typeof restPath !== 'string') {
46
+ throw new Error('restPath must be a string');
47
+ }
48
+
49
+ // Validate subProtocol
50
+ const allowedProtocols = ['graphql', 'jsonrpc-http', 'jsonrpc-ws'];
51
+ let protocol = 'rest';
52
+ if (subProtocol !== undefined) {
53
+ if (typeof subProtocol !== 'string' || !allowedProtocols.includes(subProtocol.toLowerCase())) {
54
+ throw new Error('Invalid subProtocol. It must not be "graphql" or "jsonrpc".');
55
+ }
56
+ protocol = subProtocol;
57
+ }
58
+
59
+ // allowed HTTP methods
60
+ const allowedMethods = ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'];
61
+
62
+ let endpoint = {
63
+ services: [{
64
+ name: serviceName,
65
+ port: port,
66
+ alias: serviceName,
67
+ protocol: protocol,
68
+ }],
69
+ endpoints: [{
70
+ name: serviceName + '-endpoint',
71
+ methods: [],
72
+ path: restPath,
73
+ serviceName: serviceName,
74
+ }],
75
+ responses: [],
76
+ mocks: []
77
+ };
78
+
79
+ methodTypes.forEach(methodType => {
80
+ // Check if methodType is allowed
81
+ if (!allowedMethods.includes(methodType)) {
82
+ throw new Error(`Invalid method type: ${methodType}. Allowed methods are: ${allowedMethods.join(', ')}`);
83
+ }
84
+ endpoint.endpoints[0].methods.push({
85
+ type: methodType,
86
+ name: methodType,
87
+ });
88
+ endpoint.responses.push({
89
+ name: serviceName + "-" + methodType + "-response",
90
+ endpointName: serviceName + '-endpoint',
91
+ methodName: methodType + '-method',
92
+ });
93
+ });
94
+ return JSON.stringify(endpoint);
10
95
  }
11
96
 
12
- module.exports = RestEndpoint;
97
+ module.exports = RestEndpoint;
@@ -0,0 +1,4 @@
1
+ export declare class RestParam {
2
+ constructor(name: string, in_: string, type_: string, value: string)
3
+ }
4
+
@@ -0,0 +1,32 @@
1
+
2
+ /**
3
+ * The `RestParam` class represents a REST (query, path, etc) param.
4
+ * @class
5
+ */
6
+ class RestParam {
7
+ /**
8
+ * Initializes a new instance of the RestParam class.
9
+ * @constructor
10
+ * @param {string} name - The name of the parameter.
11
+ * @param {string} in_ - The location of the parameter (e.g., 'query', 'header', 'path').
12
+ * @param {string} type_ - The data type of the parameter.
13
+ * @param {*} value - The value of the parameter.
14
+ */
15
+ constructor(name, in_, type_, value) {
16
+ this.name = name
17
+ this.in = in_
18
+ this.type = type_
19
+ this.value = value
20
+ }
21
+
22
+ toJson() {
23
+ return {
24
+ name: this.name,
25
+ in: this.in,
26
+ type: this.type,
27
+ value: this.value
28
+ }
29
+ }
30
+ }
31
+
32
+ module.exports = RestParam;
@@ -0,0 +1,48 @@
1
+ import { Asserts } from './Asserts';
2
+ import { RequestValue } from './RequestValue';
3
+ import { Endpoint } from './Endpoint';
4
+ import { StepConfig } from './Step';
5
+
6
+ interface ScenarioOptions {
7
+ name: string,
8
+ startAt?: string,
9
+ headers?: {[headerName: string]: string},
10
+ vars?: {[ var_: string]: string | number},
11
+ ignore?: boolean,
12
+ }
13
+
14
+ interface RequestOption {
15
+ request: RequestValue
16
+ }
17
+
18
+ interface AssertOption {
19
+ assert: Asserts
20
+ }
21
+
22
+ interface ScenarioOption {
23
+ scenario: Scenario
24
+ }
25
+
26
+
27
+ interface AddRequestOption extends RequestOption, StepConfig {
28
+ }
29
+
30
+ export interface AddAssertOption extends AssertOption, StepConfig {
31
+ }
32
+
33
+ export interface AddScenarioOption extends ScenarioOption, StepConfig {
34
+ }
35
+
36
+ export declare class Scenario {
37
+ constructor(name: string);
38
+ constructor(options: ScenarioOptions);
39
+ addRequest(endpoint: Endpoint, methodName: string, requestObject?: string, dynamic?: boolean): string;
40
+ addRequestFromFile(endpoint: Endpoint, methodName: string, requestFile: string): string;
41
+ buildRequestsFromEndpoint(endpoint: Endpoint): void;
42
+ addAssertEqual(value1: string, value2: string): string;
43
+ writeTestConfigurationToFile(): Promise<void>;
44
+ addRequestV1(request: RequestValue): string;
45
+ addRequestV2(options: AddRequestOption): string;
46
+ addScenarioV2(options: AddScenarioOption): string;
47
+ addAssertV2(options: AddAssertOption): string;
48
+ }