Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EPMRPP-89455 || Add dynamic data support for scenarios #166

Merged
merged 2 commits into from
May 30, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
### Added
- New API methods for scenario
### Fixed
- Reporting of feature (suite) for parallel execution [#142](https://github.com/reportportal/agent-js-cucumber/issues/142).

Expand Down
67 changes: 61 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,20 +168,23 @@ this.attach(
```
To send attachment to the launch just specify `entity: 'launch'` property.

Also `this.screenshot` and `this.launchScreenshot` methods can be used to take screenshots.
Also `this.screenshot`, `this.scenarioScreenshot` and `this.launchScreenshot` methods can be used to take screenshots.

```javascript
Then(/^I should see my new task in the list$/, function(callback) {
this.screenshot('This screenshot')
.then(() => callback())
.catch((err) => callback(err));
this.scenarioScreenshot('This is screenshot for scenario')
.then(() => callback())
.catch((err) => callback(err));
this.launchScreenshot('This is screenshot for launch')
.then(() => callback())
.catch((err) => callback(err));
});
```

`screenshot`/`launchScreenshot` function return promise fulfilled after `screenshot` is taken and image added to attachments.
`screenshot`/`scenarioScreenshot`/`launchScreenshot` function return promise fulfilled after `screenshot` is taken and image added to attachments.
Handler will parse attachments and send corresponding log to the step item.

### Logs
Expand All @@ -199,6 +202,19 @@ Then(/^I should see my new task in the list$/, function() {
});
```

To report logs to the **scenario** you can use the next methods:

```javascript
Then(/^I should see my new task in the list$/, function() {
this.scenarioInfo('This is Info Level log');
this.scenarioDebug('This is Debug Level log');
this.scenarioError('This is Error Level log');
this.scenarioWarn('This is Warn Level log');
this.scenarioTrace('This is Trace Level log');
this.scenarioFatal('This is Fatal Level log');
});
```

To report logs to the **launch** you can use the next methods:

```javascript
Expand All @@ -216,40 +232,64 @@ Then(/^I should see my new task in the list$/, function() {

Attributes for features and scenarios are parsed from @tags as `@key:value` pair.

To add attributes to the step items you can use the next method:
To add attributes to the **step items** you can use the next method:

```javascript
Then(/^I should see my new task in the list$/, function() {
this.addAttributes([{ key: 'agent', value: 'cucumber' }]);
});
```

To add attributes to the **scenario** you can use the next method:

```javascript
Then(/^I should see my new task in the list$/, function() {
this.addScenarioAttributes([{ key: 'agent', value: 'cucumber' }]);
});
```

The attributes will be concatenated.

### Description

Description for features and scenarios are parsed from their definition.

To add description to the items you can use the following method:
To add description to the **items** you can use the following method:

```javascript
Then(/^I should see my new task in the list$/, function() {
this.addDescription('Test item description.');
});
```

To add description to the **scenario** you can use the following method:

```javascript
Then(/^I should see my new task in the list$/, function() {
this.addScenarioDescription('Scenario description.');
});
```

The description will be concatenated.

### TestCaseId

To set test case id to the items you can use the following method:
To set test case id to the **items** you can use the following method:

```javascript
Then(/^I should see my new task in the list$/, function() {
this.setTestCaseId('itemTestCaseId');
});
```

To set test case id to the **scenario** you can use the following method:

```javascript
Then(/^I should see my new task in the list$/, function() {
this.setScenarioTestCaseId('scenarioTestCaseId');
});
```

### Statuses

The user can set the status of the item/launch directly depending on some conditions or behavior.
Expand All @@ -268,7 +308,22 @@ Then(/^I should see my new task in the list$/, function() {
});
```

To set status to the **item** you can use the next methods:
To set status to the **scenario** you can use the next methods:

```javascript
Then(/^I should see my new task in the list$/, function() {
this.setScenarioStatusPassed();
this.setScenarioStatusFailed();
this.setScenarioStatusSkipped();
this.setScenarioStatusStopped();
this.setScenarioStatusInterrupted();
this.setScenarioStatusCancelled();
this.setScenarioStatusInfo();
this.setScenarioStatusWarn();
});
```

To set status to the **launch** you can use the next methods:

```javascript
Then(/^I should see my new task in the list$/, function() {
Expand Down
20 changes: 14 additions & 6 deletions modules/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,10 @@ const LOG_LEVELS = {
WARN: 'WARN',
};

const RP_ENTITY_LAUNCH = 'launch';
const RP_ENTITIES = {
LAUNCH: 'LAUNCH',
SCENARIO: 'SCENARIO',
};

const CUCUMBER_EVENTS = {
GHERKIN_DOCUMENT: 'gherkin-document',
Expand Down Expand Up @@ -77,10 +80,15 @@ const TEST_ITEM_TYPES = {
};

const RP_EVENTS = {
TEST_CASE_ID: 'rp/testCaseId',
ATTRIBUTES: 'rp/attributes',
DESCRIPTION: 'rp/description',
STATUS: 'rp/status',
STEP_TEST_CASE_ID: 'rp/step/testCaseId',
STEP_ATTRIBUTES: 'rp/step/attributes',
STEP_DESCRIPTION: 'rp/step/description',
STEP_STATUS: 'rp/step/status',
SCENARIO_TEST_CASE_ID: 'rp/scenario/testCaseId',
SCENARIO_ATTRIBUTES: 'rp/scenario/attributes',
SCENARIO_DESCRIPTION: 'rp/scenario/description',
SCENARIO_STATUS: 'rp/scenario/status',
LAUNCH_STATUS: 'rp/launch/status',
};

const TEST_STEP_FINISHED_RP_MESSAGES = {
Expand All @@ -90,7 +98,7 @@ const TEST_STEP_FINISHED_RP_MESSAGES = {
};

module.exports = {
RP_ENTITY_LAUNCH,
RP_ENTITIES,
STATUSES,
LOG_LEVELS,
CUCUMBER_EVENTS,
Expand Down
85 changes: 64 additions & 21 deletions modules/cucumber-reportportal-formatter.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const utils = require('./utils');
const pjson = require('../package.json');
const {
RP_EVENTS,
RP_ENTITY_LAUNCH,
RP_ENTITIES,
LOG_LEVELS,
STATUSES,
CUCUMBER_MESSAGES,
Expand Down Expand Up @@ -255,13 +255,13 @@ const createRPFormatterClass = (config) =>
scenarioCodeRefIndexValue && !isRetry
? `${currentNodeCodeRef} [${scenarioCodeRefIndexValue}]`
: currentNodeCodeRef;

const scenarioAttributes = utils.createAttributes(scenario.tags);
const testData = {
startTime: this.reportportal.helpers.now(),
type: this.isScenarioBasedStatistics ? TEST_ITEM_TYPES.STEP : TEST_ITEM_TYPES.TEST,
name: `${keyword}: ${name}`,
description: scenario.description,
attributes: utils.createAttributes(scenario.tags),
attributes: scenarioAttributes,
codeRef: scenarioCodeRef,
retry: this.isScenarioBasedStatistics && attempt > 0,
};
Expand All @@ -276,7 +276,11 @@ const createRPFormatterClass = (config) =>
}
const parentId = ruleTempId || this.storage.getFeatureTempId(pickleFeatureUri);
const { tempId } = this.reportportal.startTestItem(testData, launchTempId, parentId);
this.storage.setScenarioTempId(testCaseId, tempId);
this.storage.setScenario(testCaseId, {
tempId,
description: scenario.description,
attributes: scenarioAttributes,
});
this.storage.updateTestCase(testCaseId, {
codeRef: scenarioCodeRef,
});
Expand Down Expand Up @@ -336,22 +340,24 @@ const createRPFormatterClass = (config) =>
if (data) {
const { testStepId, testCaseStartedId } = data;
const testCaseId = this.storage.getTestCaseId(testCaseStartedId);
const scenario = this.storage.getScenario(testCaseId) || {};
const step = this.storage.getStep(testCaseId, testStepId);
const dataObj = utils.getJSON(data.body);

switch (data.mediaType) {
case RP_EVENTS.TEST_CASE_ID: {
case RP_EVENTS.STEP_TEST_CASE_ID:
case RP_EVENTS.STEP_STATUS: {
this.storage.updateStep(testCaseId, testStepId, dataObj);
break;
}
case RP_EVENTS.ATTRIBUTES: {
case RP_EVENTS.STEP_ATTRIBUTES: {
const savedAttributes = step.attributes || [];
this.storage.updateStep(testCaseId, testStepId, {
attributes: savedAttributes.concat(dataObj.attributes),
});
break;
}
case RP_EVENTS.DESCRIPTION: {
case RP_EVENTS.STEP_DESCRIPTION: {
const savedDescription = step.description || '';
this.storage.updateStep(testCaseId, testStepId, {
description: savedDescription
Expand All @@ -360,14 +366,34 @@ const createRPFormatterClass = (config) =>
});
break;
}
case RP_EVENTS.STATUS: {
if (dataObj.entity !== RP_ENTITY_LAUNCH) {
this.storage.updateStep(testCaseId, testStepId, dataObj);
} else {
this.customLaunchStatus = dataObj.status;
}

case RP_EVENTS.SCENARIO_TEST_CASE_ID:
case RP_EVENTS.SCENARIO_STATUS: {
this.storage.updateScenario(testCaseId, dataObj);
break;
}
case RP_EVENTS.SCENARIO_ATTRIBUTES: {
const savedAttributes = scenario.attributes || [];
this.storage.updateScenario(testCaseId, {
attributes: savedAttributes.concat(dataObj.attributes),
});
break;
}
case RP_EVENTS.SCENARIO_DESCRIPTION: {
const savedDescription = scenario.description || '';
this.storage.updateScenario(testCaseId, {
description: savedDescription
? `${savedDescription}<br/>${dataObj.description}`
: dataObj.description,
});
break;
}

case RP_EVENTS.LAUNCH_STATUS: {
this.customLaunchStatus = dataObj.status;
break;
}

case 'text/plain': {
const request = {
time: this.reportportal.helpers.now(),
Expand All @@ -377,8 +403,11 @@ const createRPFormatterClass = (config) =>
if (dataObj) {
request.level = dataObj.level;
request.message = dataObj.message;
if (dataObj.entity === RP_ENTITY_LAUNCH) {

if (dataObj.entity === RP_ENTITIES.LAUNCH) {
tempStepId = this.storage.getLaunchTempId();
} else if (dataObj.entity === RP_ENTITIES.SCENARIO) {
tempStepId = this.storage.getScenarioTempId(testCaseId);
AliakseiLiasnitski marked this conversation as resolved.
Show resolved Hide resolved
}
} else {
request.level = LOG_LEVELS.DEBUG;
Expand All @@ -397,24 +426,27 @@ const createRPFormatterClass = (config) =>
name: fileName,
},
};
let tempStepId = this.storage.getStepTempId(testStepId);
let tempId = this.storage.getStepTempId(testStepId);

if (dataObj) {
if (dataObj.level) {
request.level = dataObj.level;
}
request.message = dataObj.message;
request.file.name = dataObj.message;
if (dataObj.entity === RP_ENTITY_LAUNCH) {
tempStepId = this.storage.getLaunchTempId();

if (dataObj.entity === RP_ENTITIES.LAUNCH) {
tempId = this.storage.getLaunchTempId();
} else if (dataObj.entity === RP_ENTITIES.SCENARIO) {
tempId = this.storage.getScenarioTempId(testCaseId);
}
}
const fileObj = {
name: fileName,
type: data.mediaType,
content: (dataObj && dataObj.data) || data.body,
};
this.reportportal.sendLog(tempStepId, request, fileObj);
this.reportportal.sendLog(tempId, request, fileObj);
break;
}
}
Expand Down Expand Up @@ -544,11 +576,22 @@ const createRPFormatterClass = (config) =>

const testCaseId = this.storage.getTestCaseId(testCaseStartedId);
const testCase = this.storage.getTestCase(testCaseId);
const scenarioTempId = this.storage.getScenarioTempId(testCaseId);
const {
tempId: scenarioTempId,
status: scenarioStatus,
testCaseId: customTestCaseId,
attributes,
description,
} = this.storage.getScenario(testCaseId);

this.reportportal.finishTestItem(scenarioTempId, {
endTime: this.reportportal.helpers.now(),
...(this.isScenarioBasedStatistics && { status: testCase.status || STATUSES.PASSED }),
...(this.isScenarioBasedStatistics && {
status: scenarioStatus || testCase.status || STATUSES.PASSED,
}),
...(this.isScenarioBasedStatistics && customTestCaseId && { testCaseId: customTestCaseId }),
...(attributes && { attributes }),
...(description && { description }),
});

// finish RULE if it's exist and if it's last scenario
Expand All @@ -575,7 +618,7 @@ const createRPFormatterClass = (config) =>
this.storage.removeTestCaseStartedId(testCaseStartedId);
this.storage.removeSteps(testCaseId);
this.storage.removeTestCase(testCaseId);
this.storage.removeScenarioTempId(testCaseStartedId);
this.storage.removeScenario(testCaseStartedId);
}

const { uri: pickleFeatureUri } = this.storage.getPickle(testCase.pickleId);
Expand Down
Loading