@cuppet/core 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,290 +1,290 @@
1
- const axios = require('axios');
2
- const config = require('config');
3
- const storage = require('./dataStorage');
4
- const xml2js = require('xml2js');
5
- const assert = require('chai').assert;
6
-
7
- module.exports = {
8
- /** @type {object} */
9
- response: null,
10
- /** @type {object} */
11
- request: null,
12
-
13
- /**
14
- * Prepare path for API test usage
15
- * @param url - It can be absolute/relative path or even placeholder for saved variable
16
- * @returns {Promise<*>} - Returns a working path
17
- */
18
- prepareUrl: async function (url) {
19
- const path = await storage.checkForMultipleVariables(url);
20
- if (!path.startsWith('http') && config.has('api.baseApiUrl')) {
21
- return config.get('api.baseApiUrl') + path;
22
- }
23
- return path;
24
- },
25
-
26
- /**
27
- * Function used to generate the needed headers for each request
28
- * @async
29
- * @function setHeaders
30
- * @param headers
31
- * @param {boolean} defaultHeadersFlag
32
- * @returns {Promise<Object>} - Returns an object with the headers
33
- */
34
- setHeaders: async function (headers = {}, defaultHeadersFlag = false) {
35
- if (!defaultHeadersFlag) {
36
- return headers;
37
- }
38
-
39
- let defaultHeaders = {
40
- 'Content-Type': 'application/json',
41
- Accept: 'application/json',
42
- };
43
- if (config.has('api.x-api-key')) {
44
- defaultHeaders['X-Api-Key'] = config.get('api.x-api-key');
45
- }
46
- if (config.has('api.Authorization')) {
47
- defaultHeaders['X-Api-Key'] = config.get('api.Authorization');
48
- }
49
- if (headers && defaultHeaders) {
50
- defaultHeaders = {
51
- ...defaultHeaders,
52
- ...headers,
53
- };
54
- }
55
- return defaultHeaders;
56
- },
57
-
58
- /**
59
- * Prepare and set the basic auth (if needed).
60
- * This method supports if the API and the website have different basic auth.
61
- * @async
62
- * @function setHeaders
63
- * @returns {Promise<{Object}>}
64
- */
65
- setBasicAuth: async function () {
66
- let basicAuth = {};
67
- if (config.has('api.authUser')) {
68
- basicAuth = {
69
- username: config.get('api.authUser'),
70
- password: config.get('api.authPass'),
71
- };
72
- } else if (config.has('basicAuth.authUser')) {
73
- basicAuth = {
74
- username: config.get('basicAuth.authUser'),
75
- password: config.get('basicAuth.authPass'),
76
- };
77
- }
78
- return basicAuth;
79
- },
80
-
81
- /**
82
- * Sends an HTTP request using axios.
83
- *
84
- * @async
85
- * @function sendRequest
86
- * @param {string} method - The HTTP method to use for the request.
87
- * @param {string} [url="/"] - The URL to send the request to. Defaults to "/".
88
- * @param {Object} [headers={}] - An object containing HTTP headers to include with the request. Defaults to an empty object.
89
- * @param {Object} [data={}] - An object containing data to send in the body of the request. Defaults to an empty object.
90
- * @returns {Promise<Object>} Returns a Promise that resolves to the response from the server.
91
- * @throws {Error} Throws an error if the request fails.
92
- */
93
- sendRequest: async function (method, url = '/', headers = {}, data = {}) {
94
- const apiUrl = await this.prepareUrl(url);
95
- const requestHeaders = await this.setHeaders(headers, true);
96
- const auth = await this.setBasicAuth();
97
- if (this.request) {
98
- data = this.request;
99
- }
100
- try {
101
- this.response = await axios.request({
102
- url: apiUrl,
103
- method: method.toLowerCase(),
104
- ...(Object.keys(auth).length && { auth }),
105
- // The data is conditionally added to the request, because it's not used with GET requests and creates conflict.
106
- // The following checks if data object is not empty, returns data object if not empty or skip if empty.
107
- ...(Object.keys(data).length && { data }),
108
- headers: requestHeaders,
109
- });
110
- return this.response;
111
- } catch (error) {
112
- throw new Error(`Request failed with: ${error}`);
113
- }
114
- },
115
-
116
- /**
117
- * Replace placeholders of type %var% and prepare request body
118
- * @async
119
- * @function prepareRequestBody
120
- * @param body - the request body needs to be passed in string format
121
- * @returns {Promise<Object>} - returns the request body object
122
- */
123
- prepareRequestBody: async function (body) {
124
- const preparedBody = await storage.checkForMultipleVariables(body);
125
- this.request = JSON.parse(preparedBody);
126
- return this.request;
127
- },
128
-
129
- /**
130
- * Put values in request 1 by 1
131
- * Example object: {
132
- * property: value
133
- * }
134
- * @async
135
- * @function prepareRequestBody
136
- * @param value - the value of the new property
137
- * @param property - the name of the property
138
- * @param object - parent object name
139
- * @returns {Promise<Object>} - returns the request body object
140
- */
141
- iPutValuesInRequestBody: async function (value, property, object) {
142
- const preparedValue = await storage.checkForVariable(value);
143
- if (!this.request) {
144
- this.request = {};
145
- }
146
- this.request[object][property] = preparedValue;
147
- return this.request;
148
- },
149
-
150
- /**
151
- * This step is used to validate the status code of the response
152
- * @param code
153
- * @returns {Promise<void>}
154
- */
155
- validateResponseCode: async function (code) {
156
- if (this.response.status !== Number(code)) {
157
- throw new Error(`Response code is different than expected, code: ${this.response.status}`);
158
- }
159
- },
160
-
161
- /**
162
- * Use this step whether the response is of type array or object
163
- * @param type
164
- * @returns {Promise<void>}
165
- */
166
- validateResponseType: async function (type) {
167
- await assert.typeOf(this.response.data, type, `Response is not an ${type}`);
168
- },
169
-
170
- /**
171
- * Asynchronously checks if a property of the response data is of a specified type.
172
- *
173
- * @async
174
- * @function propertyIs
175
- * @param {string} property - The property of the response data to check.
176
- * @param {string} type - The type that the property should be.
177
- * @throws {Error} - Will throw an error if the property is not of the specified type.
178
- */
179
- propertyIs: async function (property, type) {
180
- const value = this.response.data[property];
181
- await assert.typeOf(value, type, `The property is not an ${type}`);
182
- },
183
-
184
- /**
185
- * Validate value of property from the http response.
186
- * @param property
187
- * @param expectedValue
188
- * @returns {Promise<void>}
189
- */
190
- propertyHasValue: async function (property, expectedValue) {
191
- const actualValue = await this.getPropertyValue(property);
192
- assert.strictEqual(actualValue, expectedValue, `Property "${property}" does not have the expected value`);
193
- },
194
-
195
- /**
196
- * @async
197
- * @function iRememberVariable
198
- * @param property - the name of the JSON property, written in root.parent.child syntax
199
- * @param variable - the name of the variable to which it will be stored
200
- * @throws {Error} - if no property is found in the response data
201
- * @returns {Promise<void>}
202
- */
203
- iRememberVariable: async function (property, variable) {
204
- const propValue = await this.getPropertyValue(property);
205
- await storage.iStoreVariableWithValueToTheJsonFile(propValue, variable);
206
- },
207
-
208
- /**
209
- * Go through the response object and return the value of specific property
210
- * @param property - name of the property. For nested structure use -> parent.child1.child2 etc.
211
- * @returns {Promise<*>}
212
- */
213
- getPropertyValue: async function (property) {
214
- const response = this.response.data;
215
- const keys = property.split('.');
216
- let value = response;
217
- for (let key of keys) {
218
- value = value[key];
219
- }
220
- if (!value) {
221
- throw new Error(`Value with property: ${property} is not found!`);
222
- }
223
- return value;
224
- },
225
-
226
- /**
227
- * Load custom json file and make a request body from it
228
- * @param path
229
- * @returns {Promise<Object>}
230
- */
231
- createRequestBodyFromFile: async function (path) {
232
- this.request = storage.getJsonFile(path);
233
- return this.request;
234
- },
235
-
236
- /**
237
- * Send request to an endpoint and validate whether the response is valid xml.
238
- * @param url
239
- * @returns {Promise<void>}
240
- */
241
- validateXMLEndpoint: async function (url) {
242
- const xmlUrl = await this.prepareUrl(url);
243
- let response;
244
- try {
245
- const auth = await this.setBasicAuth();
246
- response = await axios.request({
247
- url: xmlUrl,
248
- method: 'get',
249
- ...(Object.keys(auth).length && { auth }),
250
- });
251
- } catch (error) {
252
- throw new Error(`Request failed with: ${error}`);
253
- }
254
-
255
- const isValid = await xml2js.parseStringPromise(response.data);
256
- if (!isValid) {
257
- throw new Error('XML is not valid!');
258
- }
259
- },
260
-
261
- /**
262
- *
263
- * @param {string} method - method - GET,POST, PUT etc.
264
- * @param {string} currentUrl - url of the page/endpoint
265
- * @param {object} reqHeaders - request headers
266
- * @param {string} resHeaders - response headers
267
- * @param {boolean} flag - direction of presence (true/false)
268
- * @returns {Promise<void>}
269
- */
270
- validateResponseHeader: async function (method, currentUrl, reqHeaders, resHeaders, flag) {
271
- const prepareUrl = await this.prepareUrl(currentUrl);
272
- const requestHeaders = await this.setHeaders(reqHeaders);
273
- const auth = await this.setBasicAuth();
274
- let response;
275
- try {
276
- response = await axios.request({
277
- url: prepareUrl,
278
- method: method,
279
- ...(Object.keys(auth).length && { auth }),
280
- headers: requestHeaders,
281
- });
282
- } catch (error) {
283
- throw new Error(`Request failed with: ${error}`);
284
- }
285
- const hasProperty = Object.prototype.hasOwnProperty.call(response.headers, resHeaders.toLowerCase());
286
- if (hasProperty !== flag) {
287
- throw new Error('The response headers are different than expected!');
288
- }
289
- },
290
- };
1
+ const axios = require('axios');
2
+ const config = require('config');
3
+ const storage = require('./dataStorage');
4
+ const xml2js = require('xml2js');
5
+ const assert = require('chai').assert;
6
+
7
+ module.exports = {
8
+ /** @type {object} */
9
+ response: null,
10
+ /** @type {object} */
11
+ request: null,
12
+
13
+ /**
14
+ * Prepare path for API test usage
15
+ * @param url - It can be absolute/relative path or even placeholder for saved variable
16
+ * @returns {Promise<*>} - Returns a working path
17
+ */
18
+ prepareUrl: async function (url) {
19
+ const path = await storage.checkForMultipleVariables(url);
20
+ if (!path.startsWith('http') && config.has('api.baseApiUrl')) {
21
+ return config.get('api.baseApiUrl') + path;
22
+ }
23
+ return path;
24
+ },
25
+
26
+ /**
27
+ * Function used to generate the needed headers for each request
28
+ * @async
29
+ * @function setHeaders
30
+ * @param headers
31
+ * @param {boolean} defaultHeadersFlag
32
+ * @returns {Promise<Object>} - Returns an object with the headers
33
+ */
34
+ setHeaders: async function (headers = {}, defaultHeadersFlag = false) {
35
+ if (!defaultHeadersFlag) {
36
+ return headers;
37
+ }
38
+
39
+ let defaultHeaders = {
40
+ 'Content-Type': 'application/json',
41
+ Accept: 'application/json',
42
+ };
43
+ if (config.has('api.x-api-key')) {
44
+ defaultHeaders['X-Api-Key'] = config.get('api.x-api-key');
45
+ }
46
+ if (config.has('api.Authorization')) {
47
+ defaultHeaders['X-Api-Key'] = config.get('api.Authorization');
48
+ }
49
+ if (headers && defaultHeaders) {
50
+ defaultHeaders = {
51
+ ...defaultHeaders,
52
+ ...headers,
53
+ };
54
+ }
55
+ return defaultHeaders;
56
+ },
57
+
58
+ /**
59
+ * Prepare and set the basic auth (if needed).
60
+ * This method supports if the API and the website have different basic auth.
61
+ * @async
62
+ * @function setHeaders
63
+ * @returns {Promise<{Object}>}
64
+ */
65
+ setBasicAuth: async function () {
66
+ let basicAuth = {};
67
+ if (config.has('api.authUser')) {
68
+ basicAuth = {
69
+ username: config.get('api.authUser'),
70
+ password: config.get('api.authPass'),
71
+ };
72
+ } else if (config.has('basicAuth.authUser')) {
73
+ basicAuth = {
74
+ username: config.get('basicAuth.authUser'),
75
+ password: config.get('basicAuth.authPass'),
76
+ };
77
+ }
78
+ return basicAuth;
79
+ },
80
+
81
+ /**
82
+ * Sends an HTTP request using axios.
83
+ *
84
+ * @async
85
+ * @function sendRequest
86
+ * @param {string} method - The HTTP method to use for the request.
87
+ * @param {string} [url="/"] - The URL to send the request to. Defaults to "/".
88
+ * @param {Object} [headers={}] - An object containing HTTP headers to include with the request. Defaults to an empty object.
89
+ * @param {Object} [data={}] - An object containing data to send in the body of the request. Defaults to an empty object.
90
+ * @returns {Promise<Object>} Returns a Promise that resolves to the response from the server.
91
+ * @throws {Error} Throws an error if the request fails.
92
+ */
93
+ sendRequest: async function (method, url = '/', headers = {}, data = {}) {
94
+ const apiUrl = await this.prepareUrl(url);
95
+ const requestHeaders = await this.setHeaders(headers, true);
96
+ const auth = await this.setBasicAuth();
97
+ if (this.request) {
98
+ data = this.request;
99
+ }
100
+ try {
101
+ this.response = await axios.request({
102
+ url: apiUrl,
103
+ method: method.toLowerCase(),
104
+ ...(Object.keys(auth).length && { auth }),
105
+ // The data is conditionally added to the request, because it's not used with GET requests and creates conflict.
106
+ // The following checks if data object is not empty, returns data object if not empty or skip if empty.
107
+ ...(Object.keys(data).length && { data }),
108
+ headers: requestHeaders,
109
+ });
110
+ return this.response;
111
+ } catch (error) {
112
+ throw new Error(`Request failed with: ${error}`);
113
+ }
114
+ },
115
+
116
+ /**
117
+ * Replace placeholders of type %var% and prepare request body
118
+ * @async
119
+ * @function prepareRequestBody
120
+ * @param body - the request body needs to be passed in string format
121
+ * @returns {Promise<Object>} - returns the request body object
122
+ */
123
+ prepareRequestBody: async function (body) {
124
+ const preparedBody = await storage.checkForMultipleVariables(body);
125
+ this.request = JSON.parse(preparedBody);
126
+ return this.request;
127
+ },
128
+
129
+ /**
130
+ * Put values in request 1 by 1
131
+ * Example object: {
132
+ * property: value
133
+ * }
134
+ * @async
135
+ * @function prepareRequestBody
136
+ * @param value - the value of the new property
137
+ * @param property - the name of the property
138
+ * @param object - parent object name
139
+ * @returns {Promise<Object>} - returns the request body object
140
+ */
141
+ iPutValuesInRequestBody: async function (value, property, object) {
142
+ const preparedValue = await storage.checkForVariable(value);
143
+ if (!this.request) {
144
+ this.request = {};
145
+ }
146
+ this.request[object][property] = preparedValue;
147
+ return this.request;
148
+ },
149
+
150
+ /**
151
+ * This step is used to validate the status code of the response
152
+ * @param code
153
+ * @returns {Promise<void>}
154
+ */
155
+ validateResponseCode: async function (code) {
156
+ if (this.response.status !== Number(code)) {
157
+ throw new Error(`Response code is different than expected, code: ${this.response.status}`);
158
+ }
159
+ },
160
+
161
+ /**
162
+ * Use this step whether the response is of type array or object
163
+ * @param type
164
+ * @returns {Promise<void>}
165
+ */
166
+ validateResponseType: async function (type) {
167
+ await assert.typeOf(this.response.data, type, `Response is not an ${type}`);
168
+ },
169
+
170
+ /**
171
+ * Asynchronously checks if a property of the response data is of a specified type.
172
+ *
173
+ * @async
174
+ * @function propertyIs
175
+ * @param {string} property - The property of the response data to check.
176
+ * @param {string} type - The type that the property should be.
177
+ * @throws {Error} - Will throw an error if the property is not of the specified type.
178
+ */
179
+ propertyIs: async function (property, type) {
180
+ const value = this.response.data[property];
181
+ await assert.typeOf(value, type, `The property is not an ${type}`);
182
+ },
183
+
184
+ /**
185
+ * Validate value of property from the http response.
186
+ * @param property
187
+ * @param expectedValue
188
+ * @returns {Promise<void>}
189
+ */
190
+ propertyHasValue: async function (property, expectedValue) {
191
+ const actualValue = await this.getPropertyValue(property);
192
+ assert.strictEqual(actualValue, expectedValue, `Property "${property}" does not have the expected value`);
193
+ },
194
+
195
+ /**
196
+ * @async
197
+ * @function iRememberVariable
198
+ * @param property - the name of the JSON property, written in root.parent.child syntax
199
+ * @param variable - the name of the variable to which it will be stored
200
+ * @throws {Error} - if no property is found in the response data
201
+ * @returns {Promise<void>}
202
+ */
203
+ iRememberVariable: async function (property, variable) {
204
+ const propValue = await this.getPropertyValue(property);
205
+ await storage.iStoreVariableWithValueToTheJsonFile(propValue, variable);
206
+ },
207
+
208
+ /**
209
+ * Go through the response object and return the value of specific property
210
+ * @param property - name of the property. For nested structure use -> parent.child1.child2 etc.
211
+ * @returns {Promise<*>}
212
+ */
213
+ getPropertyValue: async function (property) {
214
+ const response = this.response.data;
215
+ const keys = property.split('.');
216
+ let value = response;
217
+ for (let key of keys) {
218
+ value = value[key];
219
+ }
220
+ if (!value) {
221
+ throw new Error(`Value with property: ${property} is not found!`);
222
+ }
223
+ return value;
224
+ },
225
+
226
+ /**
227
+ * Load custom json file and make a request body from it
228
+ * @param path
229
+ * @returns {Promise<Object>}
230
+ */
231
+ createRequestBodyFromFile: async function (path) {
232
+ this.request = storage.getJsonFile(path);
233
+ return this.request;
234
+ },
235
+
236
+ /**
237
+ * Send request to an endpoint and validate whether the response is valid xml.
238
+ * @param url
239
+ * @returns {Promise<void>}
240
+ */
241
+ validateXMLEndpoint: async function (url) {
242
+ const xmlUrl = await this.prepareUrl(url);
243
+ let response;
244
+ try {
245
+ const auth = await this.setBasicAuth();
246
+ response = await axios.request({
247
+ url: xmlUrl,
248
+ method: 'get',
249
+ ...(Object.keys(auth).length && { auth }),
250
+ });
251
+ } catch (error) {
252
+ throw new Error(`Request failed with: ${error}`);
253
+ }
254
+
255
+ const isValid = await xml2js.parseStringPromise(response.data);
256
+ if (!isValid) {
257
+ throw new Error('XML is not valid!');
258
+ }
259
+ },
260
+
261
+ /**
262
+ *
263
+ * @param {string} method - method - GET,POST, PUT etc.
264
+ * @param {string} currentUrl - url of the page/endpoint
265
+ * @param {object} reqHeaders - request headers
266
+ * @param {string} resHeaders - response headers
267
+ * @param {boolean} flag - direction of presence (true/false)
268
+ * @returns {Promise<void>}
269
+ */
270
+ validateResponseHeader: async function (method, currentUrl, reqHeaders, resHeaders, flag) {
271
+ const prepareUrl = await this.prepareUrl(currentUrl);
272
+ const requestHeaders = await this.setHeaders(reqHeaders);
273
+ const auth = await this.setBasicAuth();
274
+ let response;
275
+ try {
276
+ response = await axios.request({
277
+ url: prepareUrl,
278
+ method: method,
279
+ ...(Object.keys(auth).length && { auth }),
280
+ headers: requestHeaders,
281
+ });
282
+ } catch (error) {
283
+ throw new Error(`Request failed with: ${error}`);
284
+ }
285
+ const hasProperty = Object.prototype.hasOwnProperty.call(response.headers, resHeaders.toLowerCase());
286
+ if (hasProperty !== flag) {
287
+ throw new Error('The response headers are different than expected!');
288
+ }
289
+ },
290
+ };