Skip to content

Commit

Permalink
Merge pull request #118 from qase-tms/cucumber-4jvm-autogenerate-test…
Browse files Browse the repository at this point in the history
…-cases

cucumber 4 add steps and autogenerate test cases
  • Loading branch information
savkk authored Sep 12, 2023
2 parents df33d93 + ede5132 commit fcbccae
Show file tree
Hide file tree
Showing 5 changed files with 217 additions and 44 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.qase.cucumber4;

import cucumber.api.PickleStepTestStep;
import cucumber.api.Result;
import cucumber.api.event.*;
import gherkin.pickles.PickleTag;
Expand All @@ -8,8 +9,10 @@
import io.qase.api.config.QaseConfig;
import io.qase.api.services.QaseTestCaseListener;
import io.qase.api.utils.CucumberUtils;
import io.qase.api.utils.IntegrationUtils;
import io.qase.client.model.ResultCreate;
import io.qase.client.model.ResultCreate.StatusEnum;
import io.qase.client.model.ResultCreateCase;
import io.qase.client.model.ResultCreateStepsInner;
import io.qase.cucumber4.guice.module.Cucumber4Module;
import lombok.AccessLevel;
Expand Down Expand Up @@ -39,6 +42,47 @@ public void setEventPublisher(EventPublisher publisher) {
publisher.registerHandlerFor(TestCaseStarted.class, this::testCaseStarted);
publisher.registerHandlerFor(TestCaseFinished.class, this::testCaseFinished);
publisher.registerHandlerFor(TestRunFinished.class, this::testRunFinished);
publisher.registerHandlerFor(TestStepStarted.class, this::testStepStarted);
publisher.registerHandlerFor(TestStepFinished.class, this::testStepFinished);
}
}

private void testStepStarted(TestStepStarted testStepStarted) {
if (testStepStarted.testStep instanceof PickleStepTestStep) {
StepStorage.startStep();
}
}

private void testStepFinished(TestStepFinished testStepFinished) {
if (testStepFinished.testStep instanceof PickleStepTestStep) {
PickleStepTestStep step = (PickleStepTestStep) testStepFinished.testStep;
String stepText = step.getStepText();
Result result = testStepFinished.result;
switch (result.getStatus()) {
case PASSED:
StepStorage.getCurrentStep()
.action(stepText)
.status(ResultCreateStepsInner.StatusEnum.PASSED);
StepStorage.stopStep();
break;
case SKIPPED:
break;
case PENDING:
break;
case UNDEFINED:
break;
case AMBIGUOUS:
break;
case FAILED:
StepStorage.getCurrentStep()
.action(stepText)
.status(ResultCreateStepsInner.StatusEnum.FAILED)
.addAttachmentsItem(IntegrationUtils.getStacktrace(result.getError()));
StepStorage.stopStep();
break;
case UNUSED:
break;
}
}
}

Expand All @@ -51,30 +95,37 @@ private void testCaseStarted(TestCaseStarted event) {
}

private void testCaseFinished(TestCaseFinished event) {
getQaseTestCaseListener().onTestCaseFinished(resultCreate -> setupResultItem(resultCreate, event));
getQaseTestCaseListener().onTestCaseFinished(resultCreate -> setupResultItem(resultCreate, event));
}

private ResultCreate setupResultItem(ResultCreate resultCreate, TestCaseFinished event) {
List<PickleTag> pickleTags = event.testCase.getTags();
List<String> tags = pickleTags.stream().map(PickleTag::getName).collect(Collectors.toList());
Long caseId = CucumberUtils.getCaseId(tags);

String caseTitle = null;
if (caseId == null) {
caseTitle = event.getTestCase().getName();
}

StatusEnum status = convertStatus(event.result.getStatus());
Optional<Throwable> optionalThrowable = Optional.ofNullable(event.result.getError());
String comment = optionalThrowable
.flatMap(throwable -> Optional.of(throwable.toString())).orElse(null);
.flatMap(throwable -> Optional.of(throwable.toString())).orElse(null);
Boolean isDefect = optionalThrowable
.flatMap(throwable -> Optional.of(throwable instanceof AssertionError))
.orElse(false);
.flatMap(throwable -> Optional.of(throwable instanceof AssertionError))
.orElse(false);
String stacktrace = optionalThrowable
.flatMap(throwable -> Optional.of(getStacktrace(throwable))).orElse(null);
.flatMap(throwable -> Optional.of(getStacktrace(throwable))).orElse(null);
LinkedList<ResultCreateStepsInner> steps = StepStorage.stopSteps();
return resultCreate
.caseId(caseId)
.status(status)
.comment(comment)
.stacktrace(stacktrace)
.steps(steps.isEmpty() ? null : steps)
.defect(isDefect);
._case(caseTitle == null ? null : new ResultCreateCase().title(caseTitle))
.caseId(caseId)
.status(status)
.comment(comment)
.stacktrace(stacktrace)
.steps(steps.isEmpty() ? null : steps)
.defect(isDefect);
}

private ResultCreate.StatusEnum convertStatus(Result.Type status) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,40 @@ void resetRequests() {
wireMockServer.resetRequests();
}

@Test
void newCase() {
useBulk(false);
String[] args = new String[]{
"-g", "io.qase.cucumber4",
"--add-plugin", "io.qase.cucumber4.QaseEventListener",
"classpath:features/"
};
Main.run(args, Thread.currentThread().getContextClassLoader());
verify(postRequestedFor(urlPathEqualTo("/v1/result/PRJ/777"))
.withHeader("Token", equalTo("secret-token"))
.withHeader("Content-Type", equalTo("application/json; charset=UTF-8"))
.withRequestBody(equalToJson("{\n" +
" \"case\" : {\n" +
" \"title\" : \"Failed scenario\"\n" +
" },\n" +
" \"status\" : \"failed\",\n" +
" \"time_ms\" : \"${json-unit.ignore}\",\n" +
" \"defect\" : true,\n" +
" \"stacktrace\" : \"${json-unit.ignore}\",\n" +
" \"comment\" : \"java.lang.AssertionError\",\n" +
" \"steps\" : [ {\n" +
" \"position\" : 1,\n" +
" \"status\" : \"passed\",\n" +
" \"action\" : \"success step\"\n" +
" }, {\n" +
" \"position\" : 2,\n" +
" \"status\" : \"failed\",\n" +
" \"attachments\" : \"${json-unit.ignore}\"," +
" \"action\" : \"failed step\"\n" +
" } ]\n" +
"}")));
}

@Test
void bulk() {
useBulk(true);
Expand All @@ -53,26 +87,75 @@ void bulk() {
" \"time_ms\" : \"${json-unit.ignore}\",\n" +
" \"defect\" : true,\n" +
" \"stacktrace\" : \"${json-unit.ignore}\",\n" +
" \"comment\" : \"java.lang.AssertionError\"\n" +
" \"comment\" : \"java.lang.AssertionError\",\n" +
" \"steps\" : [ {\n" +
" \"position\" : 1,\n" +
" \"status\" : \"failed\",\n" +
" \"attachments\" : \"${json-unit.ignore}\"," +
" \"action\" : \"failed step\"\n" +
" } ]\n" +
" }, {\n" +
" \"case_id\" : 123,\n" +
" \"status\" : \"failed\",\n" +
" \"time_ms\" : \"${json-unit.ignore}\",\n" +
" \"defect\" : true,\n" +
" \"stacktrace\" : \"${json-unit.ignore}\",\n" +
" \"comment\" : \"java.lang.AssertionError\"\n" +
" \"comment\" : \"java.lang.AssertionError\",\n" +
" \"steps\" : [ {\n" +
" \"position\" : 1,\n" +
" \"status\" : \"passed\",\n" +
" \"action\" : \"timeout 3 seconds\"\n" +
" }, {\n" +
" \"position\" : 2,\n" +
" \"status\" : \"failed\",\n" +
" \"attachments\" : \"${json-unit.ignore}\"," +
" \"action\" : \"failed step\"\n" +
" } ]\n" +
" }, {\n" +
" \"case\" : {\n" +
" \"title\" : \"Failed scenario\"\n" +
" },\n" +
" \"status\" : \"failed\",\n" +
" \"time_ms\" : \"${json-unit.ignore}\",\n" +
" \"defect\" : true,\n" +
" \"stacktrace\" : \"${json-unit.ignore}\",\n" +
" \"comment\" : \"java.lang.AssertionError\",\n" +
" \"steps\" : [ {\n" +
" \"position\" : 1,\n" +
" \"status\" : \"passed\",\n" +
" \"action\" : \"success step\"\n" +
" }, {\n" +
" \"position\" : 2,\n" +
" \"status\" : \"failed\",\n" +
" \"attachments\" : \"${json-unit.ignore}\"," +
" \"action\" : \"failed step\"\n" +
" } ]\n" +
" }, {\n" +
" \"case_id\" : 123,\n" +
" \"status\" : \"passed\",\n" +
" \"time_ms\" : \"${json-unit.ignore}\",\n" +
" \"defect\" : false\n" +
" \"defect\" : false,\n" +
" \"steps\" : [ {\n" +
" \"position\" : 1,\n" +
" \"status\" : \"passed\",\n" +
" \"action\" : \"success step\"\n" +
" } ]\n" +
" }, {\n" +
" \"case_id\" : 123,\n" +
" \"status\" : \"passed\",\n" +
" \"time_ms\" : \"${json-unit.ignore}\",\n" +
" \"defect\" : false\n" +
" \"defect\" : false,\n" +
" \"steps\" : [ {\n" +
" \"position\" : 1,\n" +
" \"status\" : \"passed\",\n" +
" \"action\" : \"timeout 5 seconds\"\n" +
" }, {\n" +
" \"position\" : 2,\n" +
" \"status\" : \"passed\",\n" +
" \"action\" : \"success step\"\n" +
" } ]\n" +
" } ]\n" +
"}", true, false)));
"}")));
}

@Test
Expand All @@ -88,11 +171,17 @@ void success() {
verify(postRequestedFor(urlPathEqualTo("/v1/result/PRJ/777"))
.withHeader("Token", equalTo("secret-token"))
.withHeader("Content-Type", equalTo("application/json; charset=UTF-8"))
.withRequestBody(equalToJson("{\n " +
"\"case_id\": 123,\n " +
"\"status\": \"passed\",\n " +
"\"defect\" : false,\n" +
"\"time_ms\": \"${json-unit.ignore}\"\n}")));
.withRequestBody(equalToJson("{\n" +
" \"case_id\" : 123,\n" +
" \"status\" : \"passed\",\n" +
" \"time_ms\" : \"${json-unit.ignore}\",\n" +
" \"defect\" : false,\n" +
" \"steps\" : [ {\n" +
" \"position\" : 1,\n" +
" \"status\" : \"passed\",\n" +
" \"action\" : \"success step\"\n" +
" } ]" +
"}")));
}

@Test
Expand All @@ -109,10 +198,19 @@ void successWithTime() {
.withHeader("Token", equalTo("secret-token"))
.withHeader("Content-Type", equalTo("application/json; charset=UTF-8"))
.withRequestBody(equalToJson("{\n" +
"\"case_id\" : 123,\n" +
"\"status\" : \"passed\",\n" +
"\"time_ms\" : \"${json-unit.ignore}\",\n" +
"\"defect\" : false\n" +
" \"case_id\" : 123,\n" +
" \"status\" : \"passed\",\n" +
" \"time_ms\" : \"${json-unit.ignore}\",\n" +
" \"defect\" : false,\n" +
" \"steps\" : [ {\n" +
" \"position\" : 1,\n" +
" \"status\" : \"passed\",\n" +
" \"action\" : \"timeout 5 seconds\"\n" +
" }, {\n" +
" \"position\" : 2,\n" +
" \"status\" : \"passed\",\n" +
" \"action\" : \"success step\"\n" +
" } ]\n" +
"}")));
}

Expand All @@ -130,12 +228,18 @@ void failed() {
.withHeader("Token", equalTo("secret-token"))
.withHeader("Content-Type", equalTo("application/json; charset=UTF-8"))
.withRequestBody(equalToJson("{\n" +
"\"case_id\" : 123,\n" +
"\"status\" : \"failed\",\n" +
"\"time_ms\" : \"${json-unit.ignore}\",\n" +
"\"comment\" : \"java.lang.AssertionError\",\n" +
"\"stacktrace\" : \"${json-unit.ignore}\"," +
"\"defect\" : true\n" +
" \"case_id\" : 123,\n" +
" \"status\" : \"failed\",\n" +
" \"time_ms\" : \"${json-unit.ignore}\",\n" +
" \"defect\" : true,\n" +
" \"stacktrace\" : \"${json-unit.ignore}\",\n" +
" \"comment\" : \"java.lang.AssertionError\",\n" +
" \"steps\" : [ {\n" +
" \"position\" : 1,\n" +
" \"status\" : \"failed\",\n" +
" \"attachments\" : \"${json-unit.ignore}\"," +
" \"action\" : \"failed step\"\n" +
" } ]\n" +
"}")));
}

Expand All @@ -153,12 +257,22 @@ void failedWithTime() {
.withHeader("Token", equalTo("secret-token"))
.withHeader("Content-Type", equalTo("application/json; charset=UTF-8"))
.withRequestBody(equalToJson("{\n" +
"\"case_id\" : 123,\n" +
"\"status\" : \"failed\",\n" +
"\"time_ms\" : \"${json-unit.ignore}\",\n" +
"\"comment\" : \"java.lang.AssertionError\",\n" +
"\"stacktrace\" : \"${json-unit.ignore}\"," +
"\"defect\" : true\n" +
" \"case_id\" : 123,\n" +
" \"status\" : \"failed\",\n" +
" \"time_ms\" : \"${json-unit.ignore}\",\n" +
" \"defect\" : true,\n" +
" \"stacktrace\" : \"${json-unit.ignore}\",\n" +
" \"comment\" : \"java.lang.AssertionError\",\n" +
" \"steps\" : [ {\n" +
" \"position\" : 1,\n" +
" \"status\" : \"passed\",\n" +
" \"action\" : \"timeout 3 seconds\"\n" +
" }, {\n" +
" \"position\" : 2,\n" +
" \"status\" : \"failed\",\n" +
" \"attachments\" : \"${json-unit.ignore}\"," +
" \"action\" : \"failed step\"\n" +
" } ]\n" +
"}")));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Feature: Failed feature

Scenario: Failed scenario
Given success step
Given failed step
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ Feature: Success feature

@caseId=123
Scenario: Success scenario
Given timeout 5 seconds
Given timeout 5 seconds
Given success step
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import io.cucumber.plugin.ConcurrentEventListener;
import io.cucumber.plugin.event.*;
import io.qase.api.QaseClient;
import io.qase.api.StepStorage;
import io.qase.api.config.QaseConfig;
import io.qase.api.services.QaseTestCaseListener;
Expand Down Expand Up @@ -34,12 +35,13 @@ public class QaseEventListener implements ConcurrentEventListener {

@Override
public void setEventPublisher(EventPublisher publisher) {
publisher.registerHandlerFor(TestCaseStarted.class, this::testCaseStarted);
publisher.registerHandlerFor(TestCaseFinished.class, this::testCaseFinished);
publisher.registerHandlerFor(TestRunFinished.class, this::testRunFinished);
publisher.registerHandlerFor(TestStepFinished.class, this::testStepFinished);
publisher.registerHandlerFor(TestStepStarted.class, this::testCaseStarted);

if (QaseClient.isEnabled()) {
publisher.registerHandlerFor(TestCaseStarted.class, this::testCaseStarted);
publisher.registerHandlerFor(TestCaseFinished.class, this::testCaseFinished);
publisher.registerHandlerFor(TestRunFinished.class, this::testRunFinished);
publisher.registerHandlerFor(TestStepFinished.class, this::testStepFinished);
publisher.registerHandlerFor(TestStepStarted.class, this::testCaseStarted);
}
}

private void testCaseStarted(TestStepStarted testStepStarted) {
Expand Down

0 comments on commit fcbccae

Please sign in to comment.