diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index cb9f290..faac8e6 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -52,7 +52,7 @@ jobs: java-version: '11' - name: Setup git credentials - uses: oleksiyrudenko/gha-git-credentials@v2.1.1 + uses: oleksiyrudenko/gha-git-credentials@v2-latest with: name: 'reportportal.io' email: 'support@reportportal.io' diff --git a/CHANGELOG.md b/CHANGELOG.md index f601fb8..5fdc089 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,12 @@ # Changelog ## [Unreleased] +### Added +- Common Stack Trace frames skip in description and logs, by @HardNorth +- Reporting of Last Error Log in Item description, by @HardNorth and @ArtemOAS +### Changed +- Client version updated on [5.2.21](https://github.com/reportportal/client-java/releases/tag/5.2.21), by @HardNorth +- Cucumber version updated on 7.20.1, by @HardNorth ## [5.3.2] ### Changed diff --git a/build.gradle b/build.gradle index 181f0c8..ddb1d74 100644 --- a/build.gradle +++ b/build.gradle @@ -39,7 +39,7 @@ repositories { } dependencies { - api 'com.epam.reportportal:client-java:5.2.13' + api 'com.epam.reportportal:client-java:5.2.21' implementation "io.cucumber:cucumber-gherkin:${project.cucumber_version}" implementation 'org.slf4j:slf4j-api:2.0.7' @@ -60,7 +60,7 @@ dependencies { testImplementation "org.junit.jupiter:junit-jupiter-api:${project.junit_version}" testImplementation "org.junit.jupiter:junit-jupiter-params:${project.junit_version}" testImplementation "org.junit.jupiter:junit-jupiter-engine:${project.junit_version}" - testImplementation 'org.apache.commons:commons-io:1.3.2' + testImplementation 'commons-io:commons-io:2.16.1' } test { diff --git a/gradle.properties b/gradle.properties index 0bf12d5..8765eeb 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,6 +1,6 @@ version=5.3.3-SNAPSHOT description=EPAM Report portal. Cucumber JVM version [6.0.0; ) adapter -cucumber_version=7.13.0 +cucumber_version=7.20.1 junit_version=5.6.3 junit_runner_version=1.6.3 scripts_url=https://raw.githubusercontent.com/reportportal/gradle-scripts diff --git a/src/main/java/com/epam/reportportal/cucumber/AbstractReporter.java b/src/main/java/com/epam/reportportal/cucumber/AbstractReporter.java index e3519c4..8881904 100644 --- a/src/main/java/com/epam/reportportal/cucumber/AbstractReporter.java +++ b/src/main/java/com/epam/reportportal/cucumber/AbstractReporter.java @@ -27,8 +27,8 @@ import com.epam.reportportal.service.tree.TestItemTree; import com.epam.reportportal.utils.*; import com.epam.reportportal.utils.files.ByteSource; +import com.epam.reportportal.utils.formatting.MarkdownUtils; import com.epam.reportportal.utils.http.ContentType; -import com.epam.reportportal.utils.markdown.MarkdownUtils; import com.epam.reportportal.utils.properties.SystemAttributesExtractor; import com.epam.reportportal.utils.reflect.Accessible; import com.epam.ta.reportportal.ws.model.FinishExecutionRQ; @@ -41,6 +41,7 @@ import io.cucumber.plugin.ConcurrentEventListener; import io.cucumber.plugin.event.*; import io.reactivex.Maybe; +import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.Pair; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -59,9 +60,10 @@ import static com.epam.reportportal.cucumber.Utils.*; import static com.epam.reportportal.cucumber.util.ItemTreeUtils.createKey; import static com.epam.reportportal.cucumber.util.ItemTreeUtils.retrieveLeaf; +import static com.epam.reportportal.utils.formatting.ExceptionUtils.getStackTrace; +import static java.lang.String.format; import static java.util.Optional.ofNullable; import static org.apache.commons.lang3.StringUtils.isNotBlank; -import static org.apache.commons.lang3.exception.ExceptionUtils.getStackTrace; /** * Abstract Cucumber 5.x formatter for Report Portal @@ -85,6 +87,7 @@ public abstract class AbstractReporter implements ConcurrentEventListener { protected static final String METHOD_OPENING_BRACKET = "("; protected static final String HOOK_ = "Hook: "; protected static final String DOCSTRING_DECORATOR = "\n\"\"\"\n"; + private static final String ERROR_FORMAT = "Error:\n%s"; private final Map featureContextMap = new ConcurrentHashMap<>(); private final TestItemTree itemTree = new TestItemTree(); @@ -95,6 +98,15 @@ public abstract class AbstractReporter implements ConcurrentEventListener { // End of feature occurs once launch is finished. private final Map featureEndTime = new ConcurrentHashMap<>(); + /** + * This map uses to record the description of the scenario and the step to append the error to the description. + */ + private final Map, String> descriptionsMap = new ConcurrentHashMap<>(); + /** + * This map uses to record errors to append to the description. + */ + private final Map, Throwable> errorMap = new ConcurrentHashMap<>(); + /** * A method for creation a Start Launch request which will be sent to Report Portal. You can customize it by overriding the method. * @@ -295,14 +307,16 @@ private interface ScenarioContextAware { private void execute(@Nonnull TestCase testCase, @Nonnull ScenarioContextAware context) { URI uri = testCase.getUri(); int line = testCase.getLocation().getLine(); - execute(uri, f -> { - Optional scenario = f.getScenario(line); - if (scenario.isPresent()) { - context.executeWithContext(f, scenario.get()); - } else { - LOGGER.warn("Unable to locate corresponding Feature or Scenario context for URI: " + uri + "; line: " + line); - } - }); + execute( + uri, f -> { + Optional scenario = f.getScenario(line); + if (scenario.isPresent()) { + context.executeWithContext(f, scenario.get()); + } else { + LOGGER.warn("Unable to locate corresponding Feature or Scenario context for URI: " + uri + "; line: " + line); + } + } + ); } private void removeFromTree(Feature featureContext, TestCase scenarioContext) { @@ -318,12 +332,17 @@ private void removeFromTree(Feature featureContext, TestCase scenarioContext) { */ protected void afterScenario(TestCaseFinished event) { TestCase testCase = event.getTestCase(); - execute(testCase, (f, s) -> { - URI featureUri = f.getUri(); - Date endTime = finishTestItem(s.getId(), mapItemStatus(event.getResult().getStatus())); - featureEndTime.put(featureUri, endTime); - removeFromTree(f.getFeature(), testCase); - }); + execute( + testCase, (f, s) -> { + URI featureUri = f.getUri(); + if (mapItemStatus(event.getResult().getStatus()) == ItemStatus.FAILED) { + Optional.ofNullable(event.getResult().getError()).ifPresent(error -> errorMap.put(s.getId(), error)); + } + Date endTime = finishTestItem(s.getId(), mapItemStatus(event.getResult().getStatus()), null); + featureEndTime.put(featureUri, endTime); + removeFromTree(f.getFeature(), testCase); + } + ); } /** @@ -355,7 +374,8 @@ protected TestCaseIdEntry getTestCaseId(@Nonnull TestStep testStep, @Nullable St Pair splitCodeRef = parseJavaCodeRef(codeRef); Optional> testStepClass = getStepClass(splitCodeRef.getKey(), codeRef); return testStepClass.flatMap(c -> getStepMethod(c, splitCodeRef.getValue())) - .map(m -> TestCaseIdUtils.getTestCaseId(m.getAnnotation(TestCaseId.class), + .map(m -> TestCaseIdUtils.getTestCaseId( + m.getAnnotation(TestCaseId.class), m, codeRef, (List) ARGUMENTS_TRANSFORM.apply(arguments) @@ -410,19 +430,24 @@ private void addToTree(@Nonnull TestCase scenario, @Nullable String text, @Nulla * @param testStep a cucumber step object */ protected void beforeStep(@Nonnull TestCase testCase, @Nonnull TestStep testStep) { - execute(testCase, (f, s) -> { - if (testStep instanceof PickleStepTestStep) { - PickleStepTestStep step = (PickleStepTestStep) testStep; - String stepPrefix = step.getStep().getLocation().getLine() < s.getLine() ? BACKGROUND_PREFIX : null; - StartTestItemRQ rq = buildStartStepRequest(testStep, stepPrefix, step.getStep().getKeyword()); - Maybe stepId = startStep(s.getId(), rq); - s.setStepId(stepId); - String stepText = step.getStep().getText(); - if (getLaunch().getParameters().isCallbackReportingEnabled()) { - addToTree(testCase, stepText, stepId); + execute( + testCase, (f, s) -> { + if (testStep instanceof PickleStepTestStep) { + PickleStepTestStep step = (PickleStepTestStep) testStep; + String stepPrefix = step.getStep().getLocation().getLine() < s.getLine() ? BACKGROUND_PREFIX : null; + StartTestItemRQ rq = buildStartStepRequest(testStep, stepPrefix, step.getStep().getKeyword()); + Maybe stepId = startStep(s.getId(), rq); + if (rq.isHasStats()) { + descriptionsMap.put(stepId, ofNullable(rq.getDescription()).orElse(StringUtils.EMPTY)); + } + s.setStepId(stepId); + String stepText = step.getStep().getText(); + if (getLaunch().getParameters().isCallbackReportingEnabled()) { + addToTree(testCase, stepText, stepId); + } + } } - } - }); + ); } /** @@ -434,11 +459,16 @@ protected void beforeStep(@Nonnull TestCase testCase, @Nonnull TestStep testStep */ @SuppressWarnings("unused") protected void afterStep(@Nonnull TestCase testCase, @Nonnull TestStep testStep, @Nonnull Result result) { - execute(testCase, (f, s) -> { - reportResult(result, null); - finishTestItem(s.getStepId(), mapItemStatus(result.getStatus())); - s.setStepId(Maybe.empty()); - }); + execute( + testCase, (f, s) -> { + reportResult(result, null); + if (mapItemStatus(result.getStatus()) == ItemStatus.FAILED) { + Optional.ofNullable(result.getError()).ifPresent(error -> errorMap.put(s.getStepId(), error)); + } + finishTestItem(s.getStepId(), mapItemStatus(result.getStatus()), null); + s.setStepId(Maybe.empty()); + } + ); } /** @@ -500,10 +530,12 @@ protected Maybe startHook(@Nonnull Maybe parentId, @Nonnull Star * @param testStep Cucumber's TestStep object */ protected void beforeHooks(@Nonnull TestCase testCase, @Nonnull HookTestStep testStep) { - execute(testCase, (f, s) -> { - StartTestItemRQ rq = buildStartHookRequest(testCase, testStep); - s.setHookId(startHook(s.getId(), rq)); - }); + execute( + testCase, (f, s) -> { + StartTestItemRQ rq = buildStartHookRequest(testCase, testStep); + s.setHookId(startHook(s.getId(), rq)); + } + ); } private void removeFromTree(TestCase testCase, String text) { @@ -519,16 +551,18 @@ private void removeFromTree(TestCase testCase, String text) { * @param result a cucumber result object */ protected void afterHooks(@Nonnull TestCase testCase, @Nonnull HookTestStep step, Result result) { - execute(testCase, (f, s) -> { - reportResult(result, (isBefore(step) ? "Before" : "After") + " hook: " + step.getCodeLocation()); - finishTestItem(s.getHookId(), mapItemStatus(result.getStatus())); - s.setHookId(Maybe.empty()); - if (step.getHookType() == HookType.AFTER_STEP) { - if (step instanceof PickleStepTestStep) { - removeFromTree(testCase, ((PickleStepTestStep) step).getStep().getText()); + execute( + testCase, (f, s) -> { + reportResult(result, (isBefore(step) ? "Before" : "After") + " hook: " + step.getCodeLocation()); + finishTestItem(s.getHookId(), mapItemStatus(result.getStatus())); + s.setHookId(Maybe.empty()); + if (step.getHookType() == HookType.AFTER_STEP) { + if (step instanceof PickleStepTestStep) { + removeFromTree(testCase, ((PickleStepTestStep) step).getStep().getText()); + } + } } - } - }); + ); } /** @@ -559,7 +593,7 @@ protected void reportResult(@Nonnull Result result, @Nullable String message) { sendLog(message, level); } if (result.getError() != null) { - sendLog(getStackTrace(result.getError()), level); + sendLog(getStackTrace(result.getError(), new Throwable()), level); } } @@ -584,7 +618,8 @@ protected void embedding(@Nullable String name, @Nullable String mimeType, @Nonn String type = ofNullable(mimeType).filter(ContentType::isValidType).orElseGet(() -> getDataType(data, name)); String attachmentName = ofNullable(name).filter(m -> !m.isEmpty()) .orElseGet(() -> ofNullable(type).map(t -> t.substring(0, t.indexOf("/"))).orElse("")); - ReportPortal.emitLog(new ReportPortalMessage(ByteSource.wrap(data), type, attachmentName), + ReportPortal.emitLog( + new ReportPortalMessage(ByteSource.wrap(data), type, attachmentName), "UNKNOWN", Calendar.getInstance().getTime() ); @@ -655,32 +690,42 @@ protected Maybe startRule(@Nonnull Maybe featureId, @Nonnull Sta */ protected void beforeScenario(@Nonnull Feature feature, @Nonnull TestCase scenario) { String scenarioName = Utils.buildName(scenario.getKeyword(), AbstractReporter.COLON_INFIX, scenario.getName()); - execute(scenario, (f, s) -> { - Optional rule = s.getRule(); - Optional currentRule = f.getCurrentRule(); - if (!currentRule.equals(rule)) { - if (currentRule.isEmpty()) { - rule.ifPresent(r -> { - r.setId(startRule(f.getId(), buildStartRuleRequest(r.getRule(), getCodeRef(feature.getUri(), r.getLine())))); - f.setCurrentRule(r); - }); - } else { - finishTestItem(currentRule.get().getId()); - rule.ifPresent(r -> { - r.setId(startRule(f.getId(), buildStartRuleRequest(r.getRule(), getCodeRef(feature.getUri(), r.getLine())))); - f.setCurrentRule(r); - }); + execute( + scenario, (f, s) -> { + Optional rule = s.getRule(); + Optional currentRule = f.getCurrentRule(); + if (!currentRule.equals(rule)) { + if (currentRule.isEmpty()) { + rule.ifPresent(r -> { + r.setId(startRule( + f.getId(), + buildStartRuleRequest(r.getRule(), getCodeRef(feature.getUri(), r.getLine())) + )); + f.setCurrentRule(r); + }); + } else { + finishTestItem(currentRule.get().getId()); + rule.ifPresent(r -> { + r.setId(startRule( + f.getId(), + buildStartRuleRequest(r.getRule(), getCodeRef(feature.getUri(), r.getLine())) + )); + f.setCurrentRule(r); + }); + } + } + Maybe rootId = rule.map(RuleContext::getId).orElseGet(f::getId); + + // If it's a ScenarioOutline use Example's line number as code reference to detach one Test Item from another + int codeLine = s.getExample().map(e -> e.getLocation().getLine()).orElse(s.getLine()); + StartTestItemRQ startTestItemRQ = buildStartScenarioRequest(scenario, scenarioName, s.getUri(), codeLine); + s.setId(startScenario(rootId, startTestItemRQ)); + descriptionsMap.put(s.getId(), ofNullable(startTestItemRQ.getDescription()).orElse(StringUtils.EMPTY)); + if (getLaunch().getParameters().isCallbackReportingEnabled()) { + addToTree(feature, scenario, s.getId()); + } } - } - Maybe rootId = rule.map(RuleContext::getId).orElseGet(f::getId); - - // If it's a ScenarioOutline use Example's line number as code reference to detach one Test Item from another - int codeLine = s.getExample().map(e -> e.getLocation().getLine()).orElse(s.getLine()); - s.setId(startScenario(rootId, buildStartScenarioRequest(scenario, scenarioName, s.getUri(), codeLine))); - if (getLaunch().getParameters().isCallbackReportingEnabled()) { - addToTree(feature, scenario, s.getId()); - } - }); + ); } /** @@ -728,21 +773,25 @@ private void addToTree(Feature feature, Maybe featureId) { protected void handleStartOfTestCase(@Nonnull TestCaseStarted event) { TestCase testCase = event.getTestCase(); URI uri = testCase.getUri(); - execute(uri, f -> { - //noinspection ReactiveStreamsUnusedPublisher - if (f.getId().equals(Maybe.empty())) { - getRootItemId(); // trigger root item creation - StartTestItemRQ featureRq = buildStartFeatureRequest(f.getFeature(), uri); - f.setId(startFeature(featureRq)); - if (getLaunch().getParameters().isCallbackReportingEnabled()) { - addToTree(f.getFeature(), f.getId()); + execute( + uri, f -> { + //noinspection ReactiveStreamsUnusedPublisher + if (f.getId().equals(Maybe.empty())) { + getRootItemId(); // trigger root item creation + StartTestItemRQ featureRq = buildStartFeatureRequest(f.getFeature(), uri); + f.setId(startFeature(featureRq)); + if (getLaunch().getParameters().isCallbackReportingEnabled()) { + addToTree(f.getFeature(), f.getId()); + } + } } - } - }); - execute(testCase, (f, s) -> { - s.setTestCase(testCase); - beforeScenario(f.getFeature(), testCase); - }); + ); + execute( + testCase, (f, s) -> { + s.setTestCase(testCase); + beforeScenario(f.getFeature(), testCase); + } + ); } protected void handleSourceEvents(TestSourceParsed parseEvent) { @@ -867,15 +916,37 @@ protected void handleTestStepFinished(@Nonnull TestStepFinished event) { * @return finish request */ @Nonnull - @SuppressWarnings("unused") protected FinishTestItemRQ buildFinishTestItemRequest(@Nonnull Maybe itemId, @Nullable Date finishTime, @Nullable ItemStatus status) { FinishTestItemRQ rq = new FinishTestItemRQ(); + if (status == ItemStatus.FAILED) { + Optional currentDescription = Optional.ofNullable(descriptionsMap.remove(itemId)); + Optional currentError = Optional.ofNullable(errorMap.remove(itemId)); + currentDescription.flatMap(description -> currentError.map(errorMessage -> resolveDescriptionErrorMessage( + description, + errorMessage + ))).ifPresent(rq::setDescription); + } ofNullable(status).ifPresent(s -> rq.setStatus(s.name())); - rq.setEndTime(ofNullable(finishTime).orElse(Calendar.getInstance().getTime())); + rq.setEndTime(finishTime); return rq; } + /** + * Resolve description + * + * @param currentDescription Current description + * @param error Error message + * @return Description with error + */ + private String resolveDescriptionErrorMessage(String currentDescription, Throwable error) { + String errorStr = format(ERROR_FORMAT, getStackTrace(error, new Throwable())); + return Optional.ofNullable(currentDescription) + .filter(StringUtils::isNotBlank) + .map(description -> MarkdownUtils.asTwoParts(currentDescription, errorStr)) + .orElse(errorStr); + } + /** * Finish a test item with specified status * @@ -889,10 +960,11 @@ protected Date finishTestItem(@Nullable Maybe itemId, @Nullable ItemStat LOGGER.error("BUG: Trying to finish unspecified test item."); return null; } - FinishTestItemRQ rq = buildFinishTestItemRequest(itemId, dateTime, status); + Date endTime = ofNullable(dateTime).orElse(Calendar.getInstance().getTime()); + FinishTestItemRQ rq = buildFinishTestItemRequest(itemId, endTime, status); //noinspection ReactiveStreamsUnusedPublisher getLaunch().finishTestItem(itemId, rq); - return rq.getEndTime(); + return endTime; } /** @@ -907,7 +979,8 @@ protected ItemStatus mapItemStatus(@Nullable Status status) { return null; } else { if (STATUS_MAPPING.get(status) == null) { - LOGGER.error(String.format("Unable to find direct mapping between Cucumber and ReportPortal for TestItem with status: '%s'.", + LOGGER.error(format( + "Unable to find direct mapping between Cucumber and ReportPortal for TestItem with status: '%s'.", status )); return ItemStatus.SKIPPED; @@ -921,11 +994,9 @@ protected ItemStatus mapItemStatus(@Nullable Status status) { * * @param itemId an ID of the item * @param status the status of the item - * @return a date and time object of the finish event */ - @Nullable - protected Date finishTestItem(@Nullable Maybe itemId, @Nullable ItemStatus status) { - return finishTestItem(itemId, status, null); + protected void finishTestItem(@Nullable Maybe itemId, @Nullable ItemStatus status) { + finishTestItem(itemId, status, null); } /** diff --git a/src/test/java/com/epam/reportportal/cucumber/FailedTest.java b/src/test/java/com/epam/reportportal/cucumber/FailedTest.java index b7292c9..70b10b5 100644 --- a/src/test/java/com/epam/reportportal/cucumber/FailedTest.java +++ b/src/test/java/com/epam/reportportal/cucumber/FailedTest.java @@ -25,6 +25,7 @@ import com.epam.reportportal.service.ReportPortal; import com.epam.reportportal.service.ReportPortalClient; import com.epam.reportportal.util.test.CommonUtils; +import com.epam.reportportal.utils.formatting.MarkdownUtils; import com.epam.ta.reportportal.ws.model.FinishTestItemRQ; import com.epam.ta.reportportal.ws.model.log.SaveLogRQ; import io.cucumber.testng.AbstractTestNGCucumberTests; @@ -42,8 +43,8 @@ import static com.epam.reportportal.cucumber.integration.util.TestUtils.filterLogs; import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.*; +import static org.mockito.Mockito.any; import static org.mockito.Mockito.*; /** @@ -52,18 +53,28 @@ public class FailedTest { private static final String EXPECTED_ERROR = "java.lang.IllegalStateException: " + FailedSteps.ERROR_MESSAGE; + private static final String EXPECTED_STACK_TRACE = EXPECTED_ERROR + + "\n\tat com.epam.reportportal.cucumber.integration.feature.FailedSteps.i_have_a_failed_step(FailedSteps.java:31)" + + "\n\tat ✽.I have a failed step(file://" + System.getProperty("user.dir") + + "/src/test/resources/features/FailedScenario.feature:4)\n"; + private static final String ERROR_LOG_TEXT = "Error:\n" + EXPECTED_STACK_TRACE; + + private static final String SCENARIO_CODE_REFERENCES_WITH_ERROR = MarkdownUtils.asTwoParts( + "file://" + System.getProperty("user.dir") + "/src/test/resources/features/FailedScenario.feature", + ERROR_LOG_TEXT + ); @CucumberOptions(features = "src/test/resources/features/FailedScenario.feature", glue = { "com.epam.reportportal.cucumber.integration.feature" }, plugin = { "pretty", "com.epam.reportportal.cucumber.integration.TestScenarioReporter" }) - public static class FailedScenarioReporter extends AbstractTestNGCucumberTests { + public static class FailedScenarioReporterTest extends AbstractTestNGCucumberTests { } @CucumberOptions(features = "src/test/resources/features/FailedScenario.feature", glue = { "com.epam.reportportal.cucumber.integration.feature" }, plugin = { "pretty", "com.epam.reportportal.cucumber.integration.TestStepReporter" }) - public static class FailedStepReporter extends AbstractTestNGCucumberTests { + public static class FailedStepReporterTest extends AbstractTestNGCucumberTests { } @@ -91,7 +102,7 @@ public void initLaunch() { @Test @SuppressWarnings("unchecked") public void verify_failed_step_reporting_scenario_reporter() { - TestUtils.runTests(FailedScenarioReporter.class); + TestUtils.runTests(FailedScenarioReporterTest.class); verify(client).startTestItem(any()); verify(client).startTestItem(same(suiteId), any()); @@ -117,7 +128,7 @@ public void verify_failed_step_reporting_scenario_reporter() { @Test @SuppressWarnings("unchecked") public void verify_failed_step_reporting_step_reporter() { - TestUtils.runTests(FailedStepReporter.class); + TestUtils.runTests(FailedStepReporterTest.class); verify(client).startTestItem(any()); verify(client).startTestItem(same(suiteId), any()); @@ -136,4 +147,44 @@ public void verify_failed_step_reporting_step_reporter() { SaveLogRQ expectedError = expectedErrorList.get(0); assertThat(expectedError.getItemUuid(), equalTo(stepId)); } + + @Test + public void verify_failed_nested_step_description_scenario_reporter() { + TestUtils.runTests(FailedScenarioReporterTest.class); + + verify(client).startTestItem(any()); + verify(client).startTestItem(same(suiteId), any()); + verify(client).startTestItem(same(testId), any()); + verify(client).startTestItem(same(stepId), any()); + ArgumentCaptor finishCaptor = ArgumentCaptor.forClass(FinishTestItemRQ.class); + verify(client).finishTestItem(same(nestedStepId), finishCaptor.capture()); + verify(client).finishTestItem(same(stepId), any()); + verify(client).finishTestItem(same(testId), finishCaptor.capture()); + + List finishRqs = finishCaptor.getAllValues(); + finishRqs.subList(0, finishRqs.size() - 1).forEach(e -> assertThat(e.getStatus(), equalTo(ItemStatus.FAILED.name()))); + + FinishTestItemRQ step = finishRqs.get(0); + assertThat(step.getDescription(), not(equalTo(ERROR_LOG_TEXT))); + } + + @Test + public void verify_failed_step_description_step_reporter() { + TestUtils.runTests(FailedStepReporterTest.class); + + verify(client).startTestItem(any()); + verify(client).startTestItem(same(suiteId), any()); + verify(client).startTestItem(same(testId), any()); + ArgumentCaptor finishCaptor = ArgumentCaptor.forClass(FinishTestItemRQ.class); + verify(client).finishTestItem(same(stepId), finishCaptor.capture()); + verify(client).finishTestItem(same(testId), finishCaptor.capture()); + + List finishRqs = finishCaptor.getAllValues(); + finishRqs.forEach(e -> assertThat(e.getStatus(), equalTo(ItemStatus.FAILED.name()))); + + FinishTestItemRQ step = finishRqs.get(0); + assertThat(step.getDescription(), equalTo(ERROR_LOG_TEXT)); + FinishTestItemRQ test = finishRqs.get(1); + assertThat(test.getDescription(), equalTo(SCENARIO_CODE_REFERENCES_WITH_ERROR)); + } } diff --git a/src/test/java/com/epam/reportportal/cucumber/FeatureDescriptionTest.java b/src/test/java/com/epam/reportportal/cucumber/FeatureDescriptionTest.java index 0360dc8..ca2731d 100644 --- a/src/test/java/com/epam/reportportal/cucumber/FeatureDescriptionTest.java +++ b/src/test/java/com/epam/reportportal/cucumber/FeatureDescriptionTest.java @@ -52,14 +52,14 @@ public class FeatureDescriptionTest { @CucumberOptions(features = "src/test/resources/features/belly.feature", glue = { "com.epam.reportportal.cucumber.integration.feature" }, plugin = { "pretty", "com.epam.reportportal.cucumber.integration.TestScenarioReporter" }) - public static class BellyScenarioReporter extends AbstractTestNGCucumberTests { + public static class BellyScenarioReporterTest extends AbstractTestNGCucumberTests { } @CucumberOptions(features = "src/test/resources/features/belly.feature", glue = { "com.epam.reportportal.cucumber.integration.feature" }, plugin = { "pretty", "com.epam.reportportal.cucumber.integration.TestStepReporter" }) - public static class BellyStepReporter extends AbstractTestNGCucumberTests { + public static class BellyStepReporterTest extends AbstractTestNGCucumberTests { } @@ -82,17 +82,19 @@ public void initLaunch() { TestStepReporter.RP.set(reportPortal); } - private static final Pair FEATURE_CODE_REFERENCES = Pair.of("file:///", + private static final Pair FEATURE_CODE_REFERENCES = Pair.of( + "file:///", "/agent-java-cucumber6/src/test/resources/features/belly.feature" ); - private static final Pair SCENARIO_CODE_REFERENCES = Pair.of("file:///", + private static final Pair SCENARIO_CODE_REFERENCES = Pair.of( + "file:///", "/agent-java-cucumber6/src/test/resources/features/belly.feature" ); @Test public void verify_code_reference_scenario_reporter() { - TestUtils.runTests(BellyScenarioReporter.class); + TestUtils.runTests(BellyScenarioReporterTest.class); verify(client, times(1)).startTestItem(any()); ArgumentCaptor captor = ArgumentCaptor.forClass(StartTestItemRQ.class); @@ -104,17 +106,19 @@ public void verify_code_reference_scenario_reporter() { StartTestItemRQ feature = items.get(0); StartTestItemRQ scenario = items.get(1); - assertThat(feature.getDescription(), + assertThat( + feature.getDescription(), allOf(notNullValue(), startsWith(FEATURE_CODE_REFERENCES.getKey()), endsWith(FEATURE_CODE_REFERENCES.getValue())) ); - assertThat(scenario.getDescription(), + assertThat( + scenario.getDescription(), allOf(notNullValue(), startsWith(SCENARIO_CODE_REFERENCES.getKey()), endsWith(SCENARIO_CODE_REFERENCES.getValue())) ); } @Test public void verify_code_reference_step_reporter() { - TestUtils.runTests(BellyStepReporter.class); + TestUtils.runTests(BellyStepReporterTest.class); ArgumentCaptor captor = ArgumentCaptor.forClass(StartTestItemRQ.class); verify(client, times(1)).startTestItem(captor.capture()); @@ -125,10 +129,12 @@ public void verify_code_reference_step_reporter() { StartTestItemRQ feature = items.get(0); StartTestItemRQ scenario = items.get(1); - assertThat(feature.getDescription(), + assertThat( + feature.getDescription(), allOf(notNullValue(), startsWith(FEATURE_CODE_REFERENCES.getKey()), endsWith(FEATURE_CODE_REFERENCES.getValue())) ); - assertThat(scenario.getDescription(), + assertThat( + scenario.getDescription(), allOf(notNullValue(), startsWith(SCENARIO_CODE_REFERENCES.getKey()), endsWith(SCENARIO_CODE_REFERENCES.getValue())) ); }