Skip to content

Commit

Permalink
feature: added support parameters from data files
Browse files Browse the repository at this point in the history
```javascript
// qase.parameters: userId, user.name
pm.test("Status code is 201", function() {
  pm.response.to.have.status(201);
});
```
  • Loading branch information
gibiw committed Oct 1, 2024
1 parent b2d37d8 commit 030ad7b
Show file tree
Hide file tree
Showing 5 changed files with 194 additions and 10 deletions.
2 changes: 2 additions & 0 deletions qase-newman/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ https://app.qase.io/run/QASE_PROJECT_CODE
<img src="./screenshots/demo.gif">
</p>

You can find more information about using the reporter [here](./docs/usage.md).

## Configuration

Qase Newman reporter can be configured in multiple ways:
Expand Down
7 changes: 7 additions & 0 deletions qase-newman/changelog.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
# [email protected]

## What's new

Added support parameters from data files in Newman.
How to use parameters from data files in Newman, see [here](./docs/usage.md).

# [email protected]

## What's new
Expand Down
59 changes: 59 additions & 0 deletions qase-newman/docs/usage.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# How to Use Parameters from Data Files in Newman

Newman allows you to leverage parameters from data files to make your API tests more dynamic and efficient. By utilizing
the `--data` or `-d` option when running a collection, you can feed your tests with various input sets. The data files
can be formatted as either JSON or CSV.

### Example Data File

Consider the following `data.json` file, which contains user data structured as complex objects:

```json
[
{
"userid": 1,
"user": {
"name": "John",
"age": 30
}
},
{
"userid": 2,
"user": {
"name": "Jane",
"age": 25
}
}
]
```

### Example Tests

Below are example tests that utilize the data parameters defined in the data file:

```javascript
// qase.parameters: userId, user.name
pm.test("Status code is 201", function() {
pm.response.to.have.status(201);
});

// qase.parameters: userId
pm.test("Response has correct userId", function() {
var jsonData = pm.response.json();
pm.expect(jsonData.userId).to.eql(pm.iterationData.get("userid"));
});

pm.test("Response has correct name", function() {
var jsonData = pm.response.json();
pm.expect(jsonData.user.name).to.eql(pm.iterationData.get("user.name"));
});
```

### Expected Behavior

When you run the tests, the following behavior is expected:

- In the **`Status code is 201`** test, both `userId` and `user.name` will be passed as parameters.
- In the **`Response has correct userId`** test, only the `userId` parameter will be passed.
- In the **`Response has correct name`** test, all relevant parameters from the data file will be passed, including
`userId`, `user.name`, and `user.age`.
4 changes: 2 additions & 2 deletions qase-newman/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "newman-reporter-qase",
"version": "2.0.1",
"version": "2.1.0",
"description": "Qase TMS Newman Reporter",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
Expand Down Expand Up @@ -45,7 +45,7 @@
"devDependencies": {
"@jest/globals": "^29.5.0",
"@types/jest": "^29.5.2",
"@types/newman": "^5.3.3",
"@types/newman": "^5.3.6",
"@types/postman-collection": "^3.5.7",
"jest": "^29.5.0",
"postman-collection": "^4.1.7",
Expand Down
132 changes: 124 additions & 8 deletions qase-newman/src/reporter.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import { EventEmitter } from 'events';

import semver from 'semver';
import { NewmanRunExecution } from 'newman';
import {
EventList, PropertyBase, PropertyBaseDefinition,
} from 'postman-collection';
import { NewmanRunExecution, NewmanRunOptions } from 'newman';
import { EventList, PropertyBase, PropertyBaseDefinition } from 'postman-collection';
import {
ConfigType,
QaseReporter,
Expand All @@ -13,7 +11,9 @@ import {
TestResultType,
getPackageVersion,
ConfigLoader,
composeOptions, Relation, SuiteData,
composeOptions,
Relation,
SuiteData,
} from 'qase-javascript-commons';

export type NewmanQaseOptionsType = ConfigType;
Expand All @@ -27,6 +27,11 @@ export class NewmanQaseReporter {
*/
static qaseIdRegExp = /\/\/\s*?[qQ]ase:\s?((?:[\d]+[\s,]{0,})+)/;

/**
* @type {RegExp}
*/
static qaseParamRegExp = /qase\.parameters:\s*([\w.]+(?:\s*,\s*[\w.]+)*)/i;

/**
* @param {EventList} eventList
* @returns {number[]}
Expand All @@ -50,9 +55,33 @@ export class NewmanQaseReporter {
return ids;
}

/**
* @param {EventList} eventList
* @returns {string[]}
* @private
*/
private static getParameters(eventList: EventList) {
const params: string[] = [];

eventList.each((event) => {
if (event.listen === 'test' && event.script.exec) {
event.script.exec.forEach((line) => {
const match = line.match(NewmanQaseReporter.qaseParamRegExp);

if (match) {
const parameters: string[] = match[1]?.split(/\s*,\s*/) ?? [];

params.push(...parameters);
}
});
}
});

return params;
}

/**
* @param {PropertyBase<PropertyBaseDefinition>} item
* @param {string[]} titles
* @returns {string[]}
* @private
*/
Expand Down Expand Up @@ -88,17 +117,22 @@ export class NewmanQaseReporter {
* @private
*/
private timerMap = new Map<string, number>();
/**
* @type {Record<string, string>[]}
* @private
*/
private parameters: Record<string, string>[] = [];

/**
* @param {EventEmitter} emitter
* @param {NewmanQaseOptionsType} options
* @param {unknown} _
* @param {NewmanRunOptions} collectionOptions
* @param {ConfigLoaderInterface} configLoader
*/
public constructor(
emitter: EventEmitter,
options: NewmanQaseOptionsType,
_: unknown,
collectionOptions: NewmanRunOptions,
configLoader = new ConfigLoader(),
) {
const config = configLoader.load();
Expand All @@ -110,6 +144,7 @@ export class NewmanQaseReporter {
reporterName: 'newman-reporter-qase',
});

this.parameters = this.getParameters(collectionOptions.iterationData);
this.addRunnerListeners(emitter);
}

Expand Down Expand Up @@ -199,6 +234,8 @@ export class NewmanQaseReporter {
pendingResult.execution.duration = now - timer;
}

pendingResult.params = this.prepareParameters(item.events, exec.cursor.iteration);

void this.reporter.addTestResult(pendingResult);
}
});
Expand Down Expand Up @@ -252,4 +289,83 @@ export class NewmanQaseReporter {

return signature;
}

/**
* @param {EventList} events
* @param {number} iteration
* @returns {Record<string, string>}
* @private
*/
private prepareParameters(events: EventList, iteration: number): Record<string, string> {
if (this.parameters.length === 0) {
return {};
}

const availableParameters = this.parameters[iteration] ?? {};
const params = NewmanQaseReporter.getParameters(events);

if (params.length === 0) {
return availableParameters;
}

return params.reduce<Record<string, string>>((filteredParams, param) => {
const value = availableParameters[param];
if (value) {
filteredParams[param] = value;
}
return filteredParams;
}, {});
}


/**
* @param {any} iterationData
* @private
*/
private getParameters(iterationData: any): Record<string, string>[] {

Check warning on line 325 in qase-newman/src/reporter.ts

View workflow job for this annotation

GitHub Actions / Project qase-newman - Node 16

Unexpected any. Specify a different type

Check warning on line 325 in qase-newman/src/reporter.ts

View workflow job for this annotation

GitHub Actions / Project qase-newman - Node 16

Unexpected any. Specify a different type

Check warning on line 325 in qase-newman/src/reporter.ts

View workflow job for this annotation

GitHub Actions / Project qase-newman - Node 18

Unexpected any. Specify a different type

Check warning on line 325 in qase-newman/src/reporter.ts

View workflow job for this annotation

GitHub Actions / Project qase-newman - Node 18

Unexpected any. Specify a different type
if (!iterationData) {
return [];
}

if (Array.isArray(iterationData) && iterationData.every(item => typeof item === 'object' && item !== null)) {
return iterationData.map((item: Record<string, any>) => this.convertToRecord(item));

Check warning on line 331 in qase-newman/src/reporter.ts

View workflow job for this annotation

GitHub Actions / Project qase-newman - Node 16

Unexpected any. Specify a different type

Check warning on line 331 in qase-newman/src/reporter.ts

View workflow job for this annotation

GitHub Actions / Project qase-newman - Node 16

Unexpected any. Specify a different type

Check warning on line 331 in qase-newman/src/reporter.ts

View workflow job for this annotation

GitHub Actions / Project qase-newman - Node 18

Unexpected any. Specify a different type

Check warning on line 331 in qase-newman/src/reporter.ts

View workflow job for this annotation

GitHub Actions / Project qase-newman - Node 18

Unexpected any. Specify a different type
}

return [];
}

/**
* @param {unknown} obj
* @param parentKey
* @returns {Record<string, string>}
* @private
*/
private convertToRecord(obj: unknown, parentKey = ''): Record<string, string> {
const record: Record<string, string> = {};

if (this.isRecord(obj)) {
for (const key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
const value = obj[key];
const newKey = parentKey ? `${parentKey}.${key}` : key;

if (this.isRecord(value)) {
Object.assign(record, this.convertToRecord(value, newKey));
} else {
record[newKey] = String(value);
}
}
}
}

return record;
}

/**
* @param {unknown} obj
* @private
*/
private isRecord(obj: unknown): obj is Record<string, unknown> {
return typeof obj === 'object' && obj !== null;
}
}

0 comments on commit 030ad7b

Please sign in to comment.