newman-reporter-qase 2.0.1 → 2.0.3

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
@@ -23,11 +23,13 @@ Example:
23
23
  //qase: 10
24
24
  // Qase: 1, 2, 3
25
25
  // qase: 4 5 6 14
26
- pm.test('expect response be 200', function () {
27
- pm.response.to.be.info
26
+ pm.test('expect response be 200', function() {
27
+ pm.response.to.be.info
28
28
  })
29
29
  ```
30
+
30
31
  ### Execute rom CLI:
32
+
31
33
  ```
32
34
  QASE_MODE=testops newman run ./sample-collection.json -r qase
33
35
  ```
@@ -46,55 +48,40 @@ https://app.qase.io/run/QASE_PROJECT_CODE
46
48
  <img src="./screenshots/demo.gif">
47
49
  </p>
48
50
 
51
+ You can find more information about using the reporter [here](./docs/usage.md).
52
+
49
53
  ## Configuration
50
54
 
51
- Qase reporter supports passing parameters using two ways:
52
- using `.qaserc`/`qase.config.json` file and using ENV variables.
53
-
54
- `.qaserc` parameters, (* - required):
55
- - `mode` - `testops`/`off` Enables reporter, default - `off`
56
- - `debug` - Enables debug logging, defaule - `false`
57
- - `environment` - To execute with the sending of the envinroment information
58
- - *`testops.api.token` - Token for API access, you can find more information
59
- [here](https://developers.qase.io/#authentication)
60
- - *`testops.project` - Code of your project (can be extracted from main
61
- page of your project: `https://app.qase.io/project/DEMOTR` -
62
- `DEMOTR` is project code here)
63
- - `testops.run.id` - Pass Run ID
64
- - `testops.run.title` - Set custom Run name, when new run is created
65
- - `testops.run.description` - Set custom Run description, when new run is created
66
- - `testops.run.complete` - Whether the run should be completed
67
-
68
- Example configuration file:
55
+ Qase Newman reporter can be configured in multiple ways:
56
+
57
+ - using a separate config file `qase.config.json`,
58
+ - using environment variables (they override the values from the configuration files).
59
+
60
+ For a full list of configuration options, see
61
+ the [Configuration reference](../qase-javascript-commons/README.md#configuration).
62
+
63
+ Example `qase.config.json` config:
69
64
 
70
65
  ```json
71
66
  {
72
67
  "mode": "testops",
73
68
  "debug": true,
74
- "environment": 1,
75
69
  "testops": {
76
70
  "api": {
77
71
  "token": "api_key"
78
72
  },
79
- "projectCode": "project_code"
73
+ "project": "project_code",
74
+ "run": {
75
+ "complete": true
76
+ }
80
77
  }
81
78
  }
82
79
  ```
83
80
 
84
- Supported ENV variables:
85
-
86
- - `QASE_MODE` - Same as `mode`
87
- - `QASE_DEBUG` - Same as `debug`
88
- - `QASE_ENVIRONMENT` - Same as `environment`
89
- - `QASE_TESTOPS_API_TOKEN` - Same as `testops.api.token`
90
- - `QASE_TESTOPS_PROJECT` - Same as `testops.project`
91
- - `QASE_TESTOPS_RUN_ID` - Pass Run ID from ENV and override reporter option `testops.run.id`
92
- - `QASE_TESTOPS_RUN_TITLE` - Same as `testops.run.title`
93
- - `QASE_TESTOPS_RUN_DESCRIPTION` - Same as `testops.run.description`
94
-
95
81
  ## Requirements
96
82
 
97
- We maintain the reporter on LTS versions of Node. You can find the current versions by following the [link](https://nodejs.org/en/about/releases/)
83
+ We maintain the reporter on LTS versions of Node. You can find the current versions by following
84
+ the [link](https://nodejs.org/en/about/releases/)
98
85
 
99
86
  `newman >= 5.3.0`
100
87
 
package/changelog.md CHANGED
@@ -1,3 +1,16 @@
1
+ # qase-newman@2.0.3
2
+
3
+ ## What's new
4
+
5
+ Added support parameters from data files in Newman on collection and folder levels.
6
+
7
+ # qase-newman@2.0.2
8
+
9
+ ## What's new
10
+
11
+ Added support parameters from data files in Newman.
12
+ How to use parameters from data files in Newman, see [here](./docs/usage.md).
13
+
1
14
  # qase-newman@2.0.0
2
15
 
3
16
  ## What's new
@@ -0,0 +1,4 @@
1
+ import { JSONSchemaType } from 'ajv';
2
+ import { FrameworkOptionsType } from 'qase-javascript-commons';
3
+ import { ReporterOptionsType } from './options';
4
+ export declare const configSchema: JSONSchemaType<FrameworkOptionsType<'newman', ReporterOptionsType>>;
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.configSchema = void 0;
4
+ exports.configSchema = {
5
+ type: 'object',
6
+ nullable: true,
7
+ properties: {
8
+ framework: {
9
+ type: 'object',
10
+ nullable: true,
11
+ properties: {
12
+ newman: {
13
+ type: 'object',
14
+ nullable: true,
15
+ properties: {
16
+ autoCollectParams: {
17
+ type: 'boolean',
18
+ nullable: true,
19
+ },
20
+ },
21
+ },
22
+ },
23
+ },
24
+ },
25
+ };
@@ -0,0 +1,3 @@
1
+ export interface ReporterOptionsType {
2
+ autoCollectParams?: boolean;
3
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -1,5 +1,6 @@
1
1
  /// <reference types="node" />
2
2
  import { EventEmitter } from 'events';
3
+ import { NewmanRunOptions } from 'newman';
3
4
  import { ConfigType, ConfigLoader } from 'qase-javascript-commons';
4
5
  export type NewmanQaseOptionsType = ConfigType;
5
6
  /**
@@ -10,15 +11,24 @@ export declare class NewmanQaseReporter {
10
11
  * @type {RegExp}
11
12
  */
12
13
  static qaseIdRegExp: RegExp;
14
+ /**
15
+ * @type {RegExp}
16
+ */
17
+ static qaseParamRegExp: RegExp;
13
18
  /**
14
19
  * @param {EventList} eventList
15
20
  * @returns {number[]}
16
21
  * @private
17
22
  */
18
23
  private static getCaseIds;
24
+ /**
25
+ * @param {Item} item
26
+ * @returns {string[]}
27
+ * @private
28
+ */
29
+ private static getParameters;
19
30
  /**
20
31
  * @param {PropertyBase<PropertyBaseDefinition>} item
21
- * @param {string[]} titles
22
32
  * @returns {string[]}
23
33
  * @private
24
34
  */
@@ -38,13 +48,23 @@ export declare class NewmanQaseReporter {
38
48
  * @private
39
49
  */
40
50
  private timerMap;
51
+ /**
52
+ * @type {Record<string, string>[]}
53
+ * @private
54
+ */
55
+ private readonly parameters;
56
+ /**
57
+ * @type {boolean}
58
+ * @private
59
+ */
60
+ private autoCollectParams;
41
61
  /**
42
62
  * @param {EventEmitter} emitter
43
63
  * @param {NewmanQaseOptionsType} options
44
- * @param {unknown} _
64
+ * @param {NewmanRunOptions} collectionOptions
45
65
  * @param {ConfigLoaderInterface} configLoader
46
66
  */
47
- constructor(emitter: EventEmitter, options: NewmanQaseOptionsType, _: unknown, configLoader?: ConfigLoader<Partial<ConfigType> & Record<string, unknown>>);
67
+ constructor(emitter: EventEmitter, options: NewmanQaseOptionsType, collectionOptions: NewmanRunOptions, configLoader?: ConfigLoader<import("qase-javascript-commons").FrameworkOptionsType<"newman", import("./options").ReporterOptionsType>>);
48
68
  /**
49
69
  * @param {EventEmitter} runner
50
70
  * @private
@@ -61,4 +81,28 @@ export declare class NewmanQaseReporter {
61
81
  * @private
62
82
  */
63
83
  private getSignature;
84
+ /**
85
+ * @param {Item} item
86
+ * @param {number} iteration
87
+ * @returns {Record<string, string>}
88
+ * @private
89
+ */
90
+ private prepareParameters;
91
+ /**
92
+ * @param {any} iterationData
93
+ * @private
94
+ */
95
+ private getParameters;
96
+ /**
97
+ * @param {unknown} obj
98
+ * @param parentKey
99
+ * @returns {Record<string, string>}
100
+ * @private
101
+ */
102
+ private convertToRecord;
103
+ /**
104
+ * @param {unknown} obj
105
+ * @private
106
+ */
107
+ private isRecord;
64
108
  }
package/dist/reporter.js CHANGED
@@ -4,6 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.NewmanQaseReporter = void 0;
7
+ const configSchema_1 = require("./configSchema");
7
8
  const semver_1 = __importDefault(require("semver"));
8
9
  const qase_javascript_commons_1 = require("qase-javascript-commons");
9
10
  /**
@@ -29,9 +30,32 @@ class NewmanQaseReporter {
29
30
  });
30
31
  return ids;
31
32
  }
33
+ /**
34
+ * @param {Item} item
35
+ * @returns {string[]}
36
+ * @private
37
+ */
38
+ static getParameters(item) {
39
+ const params = [];
40
+ item.events.each((event) => {
41
+ if (event.listen === 'test' && event.script.exec) {
42
+ event.script.exec.forEach((line) => {
43
+ const match = line.match(NewmanQaseReporter.qaseParamRegExp);
44
+ if (match) {
45
+ const parameters = match[1]?.split(/\s*,\s*/) ?? [];
46
+ params.push(...parameters);
47
+ }
48
+ });
49
+ }
50
+ });
51
+ const parent = item.parent();
52
+ if (parent && 'events' in parent) {
53
+ params.push(...NewmanQaseReporter.getParameters(parent));
54
+ }
55
+ return params;
56
+ }
32
57
  /**
33
58
  * @param {PropertyBase<PropertyBaseDefinition>} item
34
- * @param {string[]} titles
35
59
  * @returns {string[]}
36
60
  * @private
37
61
  */
@@ -49,10 +73,10 @@ class NewmanQaseReporter {
49
73
  /**
50
74
  * @param {EventEmitter} emitter
51
75
  * @param {NewmanQaseOptionsType} options
52
- * @param {unknown} _
76
+ * @param {NewmanRunOptions} collectionOptions
53
77
  * @param {ConfigLoaderInterface} configLoader
54
78
  */
55
- constructor(emitter, options, _, configLoader = new qase_javascript_commons_1.ConfigLoader()) {
79
+ constructor(emitter, options, collectionOptions, configLoader = new qase_javascript_commons_1.ConfigLoader(configSchema_1.configSchema)) {
56
80
  /**
57
81
  * @type {Map<string, TestResultType>}
58
82
  * @private
@@ -63,6 +87,11 @@ class NewmanQaseReporter {
63
87
  * @private
64
88
  */
65
89
  this.timerMap = new Map();
90
+ /**
91
+ * @type {Record<string, string>[]}
92
+ * @private
93
+ */
94
+ this.parameters = [];
66
95
  const config = configLoader.load();
67
96
  this.reporter = qase_javascript_commons_1.QaseReporter.getInstance({
68
97
  ...(0, qase_javascript_commons_1.composeOptions)(options, config),
@@ -70,6 +99,8 @@ class NewmanQaseReporter {
70
99
  frameworkName: 'newman',
71
100
  reporterName: 'newman-reporter-qase',
72
101
  });
102
+ this.autoCollectParams = config?.framework?.newman?.autoCollectParams ?? false;
103
+ this.parameters = this.getParameters(collectionOptions.iterationData);
73
104
  this.addRunnerListeners(emitter);
74
105
  }
75
106
  /**
@@ -143,6 +174,7 @@ class NewmanQaseReporter {
143
174
  const now = Date.now();
144
175
  pendingResult.execution.duration = now - timer;
145
176
  }
177
+ pendingResult.params = this.prepareParameters(item, exec.cursor.iteration);
146
178
  void this.reporter.addTestResult(pendingResult);
147
179
  }
148
180
  });
@@ -185,9 +217,83 @@ class NewmanQaseReporter {
185
217
  }
186
218
  return signature;
187
219
  }
220
+ /**
221
+ * @param {Item} item
222
+ * @param {number} iteration
223
+ * @returns {Record<string, string>}
224
+ * @private
225
+ */
226
+ prepareParameters(item, iteration) {
227
+ if (this.parameters.length === 0) {
228
+ return {};
229
+ }
230
+ const availableParameters = this.parameters[iteration] ?? {};
231
+ const params = NewmanQaseReporter.getParameters(item);
232
+ if (params.length === 0) {
233
+ if (this.autoCollectParams) {
234
+ return availableParameters;
235
+ }
236
+ return {};
237
+ }
238
+ return params.reduce((filteredParams, param) => {
239
+ const value = availableParameters[param.toLowerCase()];
240
+ if (value) {
241
+ filteredParams[param.toLowerCase()] = value;
242
+ }
243
+ return filteredParams;
244
+ }, {});
245
+ }
246
+ /**
247
+ * @param {any} iterationData
248
+ * @private
249
+ */
250
+ getParameters(iterationData) {
251
+ if (!iterationData) {
252
+ return [];
253
+ }
254
+ if (Array.isArray(iterationData) && iterationData.every(item => typeof item === 'object' && item !== null)) {
255
+ return iterationData.map((item) => this.convertToRecord(item));
256
+ }
257
+ return [];
258
+ }
259
+ /**
260
+ * @param {unknown} obj
261
+ * @param parentKey
262
+ * @returns {Record<string, string>}
263
+ * @private
264
+ */
265
+ convertToRecord(obj, parentKey = '') {
266
+ const record = {};
267
+ if (this.isRecord(obj)) {
268
+ for (const key in obj) {
269
+ if (Object.prototype.hasOwnProperty.call(obj, key)) {
270
+ const value = obj[key];
271
+ const newKey = parentKey ? `${parentKey}.${key}` : key;
272
+ if (this.isRecord(value)) {
273
+ Object.assign(record, this.convertToRecord(value, newKey));
274
+ }
275
+ else {
276
+ record[newKey.toLowerCase()] = String(value);
277
+ }
278
+ }
279
+ }
280
+ }
281
+ return record;
282
+ }
283
+ /**
284
+ * @param {unknown} obj
285
+ * @private
286
+ */
287
+ isRecord(obj) {
288
+ return typeof obj === 'object' && obj !== null;
289
+ }
188
290
  }
189
291
  exports.NewmanQaseReporter = NewmanQaseReporter;
190
292
  /**
191
293
  * @type {RegExp}
192
294
  */
193
295
  NewmanQaseReporter.qaseIdRegExp = /\/\/\s*?[qQ]ase:\s?((?:[\d]+[\s,]{0,})+)/;
296
+ /**
297
+ * @type {RegExp}
298
+ */
299
+ NewmanQaseReporter.qaseParamRegExp = /qase\.parameters:\s*([\w.]+(?:\s*,\s*[\w.]+)*)/i;
package/docs/usage.md ADDED
@@ -0,0 +1,140 @@
1
+ # How to Use Parameters from Data Files in Newman
2
+
3
+ Newman allows you to leverage parameters from data files to make your API tests more dynamic and efficient. By utilizing
4
+ the `--data` or `-d` option when running a collection, you can feed your tests with various input sets. The data files
5
+ can be formatted as either JSON or CSV.
6
+
7
+ ### Example Data File
8
+
9
+ Consider the following `data.json` file, which contains user data structured as complex objects:
10
+
11
+ ```json
12
+ [
13
+ {
14
+ "userid": 1,
15
+ "user": {
16
+ "name": "John",
17
+ "age": 30
18
+ }
19
+ },
20
+ {
21
+ "userid": 2,
22
+ "user": {
23
+ "name": "Jane",
24
+ "age": 25
25
+ }
26
+ }
27
+ ]
28
+ ```
29
+
30
+ ### Example Tests
31
+
32
+ Below are example tests that utilize the data parameters defined in the data file:
33
+
34
+ ```javascript
35
+ // qase.parameters: userId, user.name
36
+ pm.test("Status code is 201", function() {
37
+ pm.response.to.have.status(201);
38
+ });
39
+
40
+ // qase.parameters: userId
41
+ pm.test("Response has correct userId", function() {
42
+ var jsonData = pm.response.json();
43
+ pm.expect(jsonData.userId).to.eql(pm.iterationData.get("userid"));
44
+ });
45
+
46
+ pm.test("Response has correct name", function() {
47
+ var jsonData = pm.response.json();
48
+ pm.expect(jsonData.user.name).to.eql(pm.iterationData.get("user.name"));
49
+ });
50
+ ```
51
+
52
+ You also can specify parameters on collection or folder level. In this case, all tests in collection or folder will have
53
+ these parameters. If test has own parameters, they will be merged with collection or folder parameters.
54
+
55
+ ```json
56
+ {
57
+ "info": {
58
+ "_postman_id": "collection_id",
59
+ "name": "Collection Name",
60
+ "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
61
+ },
62
+ "item": [
63
+ {
64
+ "name": "Folder Name",
65
+ "item": [
66
+ {
67
+ "name": "Test Name",
68
+ "event": [
69
+ {
70
+ "listen": "test",
71
+ "script": {
72
+ "type": "text/javascript",
73
+ "exec": [
74
+ "pm.test('Status code is 200', function () {",
75
+ " pm.response.to.have.status(200);",
76
+ "})"
77
+ ]
78
+ }
79
+ }
80
+ ],
81
+ "request": {
82
+ "method": "GET",
83
+ "header": [],
84
+ "url": {
85
+ "raw": "https://api.example.com",
86
+ "host": [
87
+ "api",
88
+ "example",
89
+ "com"
90
+ ]
91
+ }
92
+ },
93
+ "response": []
94
+ }
95
+ ],
96
+ "event": [
97
+ {
98
+ "listen": "test",
99
+ "script": {
100
+ "exec": [
101
+ "// qase.parameters: userId, user.name"
102
+ ],
103
+ "type": "text/javascript"
104
+ }
105
+ }
106
+ ]
107
+ }
108
+ ]
109
+ }
110
+ ```
111
+
112
+ ### Expected Behavior
113
+
114
+ When you run the tests, the following behavior is expected:
115
+
116
+ - In the **`Status code is 201`** test, both `userId` and `user.name` will be passed as parameters.
117
+ - In the **`Response has correct userId`** test, only the `userId` parameter will be passed.
118
+ - In the **`Response has correct name`** test, by default, test will not have any parameters passed. But you can enable
119
+ specific option in config file to pass all parameters from data file if test have not commented `qase.parameters`
120
+ line.
121
+
122
+ ```json
123
+ {
124
+ "debug": true,
125
+ "testops": {
126
+ "api": {
127
+ "token": "api_key"
128
+ },
129
+ "project": "project_code",
130
+ "run": {
131
+ "complete": true
132
+ }
133
+ },
134
+ "framework": {
135
+ "newman": {
136
+ "autoCollectParams": true
137
+ }
138
+ }
139
+ }
140
+ ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "newman-reporter-qase",
3
- "version": "2.0.1",
3
+ "version": "2.0.3",
4
4
  "description": "Qase TMS Newman Reporter",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -45,8 +45,9 @@
45
45
  "devDependencies": {
46
46
  "@jest/globals": "^29.5.0",
47
47
  "@types/jest": "^29.5.2",
48
- "@types/newman": "^5.3.3",
48
+ "@types/newman": "^5.3.6",
49
49
  "@types/postman-collection": "^3.5.7",
50
+ "ajv": "^8.17.1",
50
51
  "jest": "^29.5.0",
51
52
  "postman-collection": "^4.1.7",
52
53
  "ts-jest": "^29.1.0"