@cuppet/core 1.0.16 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -7,7 +7,7 @@ Given('that I send a {string} request to {string}', async function (method, path
7
7
  await apiSteps.sendRequest(method, path);
8
8
  });
9
9
  When(
10
- 'I send a {string} request to {string} with http header {string} and value {string}',
10
+ 'that I send a {string} request to {string} with http header {string} and value {string}',
11
11
  async function (method, path, headerName, headerValue) {
12
12
  const name = await dataStorage.checkForSavedVariable(headerName);
13
13
  const value = await dataStorage.checkForSavedVariable(headerValue);
@@ -35,6 +35,10 @@ Given('that I have request body', async function (docString) {
35
35
  const body = JSON.stringify(docString);
36
36
  await apiSteps.prepareRequestBody(body);
37
37
  });
38
+ Given('that I have a multipart request body', async function (docString) {
39
+ const body = JSON.parse(docString);
40
+ await apiSteps.buildMultipartFormData(body);
41
+ });
38
42
  Given(
39
43
  'I put {string} to {string} property of {string} element in the body',
40
44
  async function (value, property, parentObj) {
@@ -50,3 +54,6 @@ Given('I validate that the page is a valid XML', async function () {
50
54
  const currentPath = main.extractPath(this.page, true);
51
55
  await apiSteps.validateXMLEndpoint(currentPath);
52
56
  });
57
+ Then('the response header {string} should be {string}', async function (header, value) {
58
+ await apiSteps.validateResponseHeader(header, value);
59
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cuppet/core",
3
- "version": "1.0.16",
3
+ "version": "1.1.0",
4
4
  "description": "Core testing framework components for Cuppet - BDD framework based on Cucumber and Puppeteer",
5
5
  "main": "index.js",
6
6
  "files": [
@@ -36,6 +36,7 @@
36
36
  "chai": "^4.3.7",
37
37
  "lighthouse": "^12.1.0",
38
38
  "mime": "^3.0.0",
39
+ "mime-types": "^3.0.1",
39
40
  "moment": "^2.30.1",
40
41
  "pa11y": "^8.0.0",
41
42
  "pa11y-reporter-html": "^2.0.0",
@@ -61,8 +62,10 @@
61
62
  "scripts": {
62
63
  "test": "cucumber-js features/tests",
63
64
  "postinstall": "node postinstall.js",
64
- "lint": "eslint .",
65
- "format": "prettier --write ."
65
+ "lint:check": "eslint .",
66
+ "format:check": "prettier --check .",
67
+ "format": "eslint . --fix && prettier --write .",
68
+ "verify": "yarn lint:check && yarn format:check"
66
69
  },
67
70
  "repository": {
68
71
  "type": "git",
@@ -3,12 +3,17 @@ const config = require('config');
3
3
  const storage = require('./dataStorage');
4
4
  const xml2js = require('xml2js');
5
5
  const assert = require('chai').assert;
6
+ const fs = require('fs');
7
+ const mime = require('mime-types');
8
+ const FormData = require('form-data');
6
9
 
7
10
  module.exports = {
8
11
  /** @type {object} */
9
12
  response: null,
10
13
  /** @type {object} */
11
14
  request: null,
15
+ /** @type {object} */
16
+ formData: null,
12
17
 
13
18
  /**
14
19
  * Prepare path for API test usage
@@ -40,11 +45,15 @@ module.exports = {
40
45
  'Content-Type': 'application/json',
41
46
  Accept: 'application/json',
42
47
  };
48
+ if (this.formData) {
49
+ defaultHeaders = {};
50
+ Object.assign(defaultHeaders, this.formData.getHeaders());
51
+ }
43
52
  if (config.has('api.x-api-key')) {
44
53
  defaultHeaders['X-Api-Key'] = config.get('api.x-api-key');
45
54
  }
46
55
  if (config.has('api.Authorization')) {
47
- defaultHeaders['X-Api-Key'] = config.get('api.Authorization');
56
+ defaultHeaders['Authorization'] = config.get('api.Authorization');
48
57
  }
49
58
  if (headers && defaultHeaders) {
50
59
  defaultHeaders = {
@@ -97,6 +106,9 @@ module.exports = {
97
106
  if (this.request) {
98
107
  data = this.request;
99
108
  }
109
+ if (this.formData) {
110
+ data = this.formData;
111
+ }
100
112
  try {
101
113
  this.response = await axios.request({
102
114
  url: apiUrl,
@@ -104,12 +116,14 @@ module.exports = {
104
116
  ...(Object.keys(auth).length && { auth }),
105
117
  // The data is conditionally added to the request, because it's not used with GET requests and creates conflict.
106
118
  // 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 }),
119
+ ...((data instanceof FormData || Object.keys(data).length) && { data }),
108
120
  headers: requestHeaders,
109
121
  });
122
+
110
123
  return this.response;
111
124
  } catch (error) {
112
- throw new Error(`Request failed with: ${error}. Response: ${JSON.stringify(this.response)}`);
125
+ console.log('Request has failed, use response code step definition to validate the response!');
126
+ return (this.response = error.response);
113
127
  }
114
128
  },
115
129
 
@@ -154,7 +168,9 @@ module.exports = {
154
168
  */
155
169
  validateResponseCode: async function (code) {
156
170
  if (this.response.status !== Number(code)) {
157
- throw new Error(`Response code is different than expected, code: ${this.response.status}`);
171
+ throw new Error(
172
+ `Unexpected response code, code: ${this.response.status}. Response: ${JSON.stringify(this.response.data)}`
173
+ );
158
174
  }
159
175
  },
160
176
 
@@ -259,32 +275,48 @@ module.exports = {
259
275
  },
260
276
 
261
277
  /**
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)
278
+ * Validate response header
279
+ * @param {string} header - header name
280
+ * @param {string} value - header value
268
281
  * @returns {Promise<void>}
269
282
  */
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!');
283
+ validateResponseHeader: async function (header, value) {
284
+ // Resolve header and value from variables or user input.
285
+ // The header is checked directly for faster execution as it is less likely to contain variables.
286
+ const resolveHeader = await storage.checkForVariable(header);
287
+ const resolveValue = await storage.checkForSavedVariable(value);
288
+ const actualValue = this.response.headers[resolveHeader.toLowerCase()];
289
+ assert.isDefined(actualValue, `The response header "${resolveHeader}" is not found!`);
290
+ assert.strictEqual(
291
+ actualValue,
292
+ resolveValue,
293
+ `The response header "${resolveHeader}" does not have the expected value`
294
+ );
295
+ },
296
+
297
+ /**
298
+ * Build multipart/form-data request body
299
+ * If you want to send a file, you need to pass the file name (not the path) as a string.
300
+ * Please use the files from the files folder.
301
+ * @param {object} data - the data to be sent in the request body
302
+ * @returns {Promise<Object>} - returns the request body object
303
+ */
304
+ buildMultipartFormData: async function (data) {
305
+ const filePath = config.get('filePath');
306
+ const formData = new FormData();
307
+ for (const [key, value] of Object.entries(data)) {
308
+ if (key === 'file') {
309
+ const mimeType = mime.contentType(value) || 'application/octet-stream';
310
+ formData.append('file', fs.createReadStream(filePath + value), {
311
+ filename: value,
312
+ contentType: mimeType,
313
+ });
314
+ formData.append('type', mimeType);
315
+ } else {
316
+ formData.append(key, await storage.checkForSavedVariable(value));
317
+ }
288
318
  }
319
+ this.formData = formData;
320
+ return this.formData;
289
321
  },
290
322
  };