From 5faba3ff1a976548a88b6b7e3d43d7e7702f764f Mon Sep 17 00:00:00 2001 From: savkk Date: Sun, 19 Nov 2023 01:30:59 +0300 Subject: [PATCH] cucumber 6 parameterization support --- .../cucumber5/QaseEventListenerTests.java | 5 +- qase-cucumber6-jvm/pom.xml | 5 + .../io/qase/cucumber6/QaseEventListener.java | 67 ++++++++++++- .../cucumber6/QaseEventListenerTests.java | 97 ++++++++++++++++++- .../test/java/io/qase/cucumber6/Steps.java | 4 + .../resources/features/with_examples.feature | 15 +++ .../cucumber7/QaseEventListenerTests.java | 2 +- 7 files changed, 185 insertions(+), 10 deletions(-) create mode 100644 qase-cucumber6-jvm/src/test/resources/features/with_examples.feature diff --git a/qase-cucumber5-jvm/src/test/java/io/qase/cucumber5/QaseEventListenerTests.java b/qase-cucumber5-jvm/src/test/java/io/qase/cucumber5/QaseEventListenerTests.java index 52cca5c..28ba7f5 100644 --- a/qase-cucumber5-jvm/src/test/java/io/qase/cucumber5/QaseEventListenerTests.java +++ b/qase-cucumber5-jvm/src/test/java/io/qase/cucumber5/QaseEventListenerTests.java @@ -73,7 +73,8 @@ void bulk() { String[] args = new String[]{ "-g", "io.qase.cucumber5", "--add-plugin", "io.qase.cucumber5.QaseEventListener", - "classpath:features/" + "classpath:features/", + "--threads", "4" }; Main.run(args, Thread.currentThread().getContextClassLoader()); @@ -247,7 +248,7 @@ void bulk() { " \"action\" : \"Given success step\"\n" + " } ]\n" + " } ]\n" + - "}"))); + "}", true, false))); } @Test diff --git a/qase-cucumber6-jvm/pom.xml b/qase-cucumber6-jvm/pom.xml index 5711386..d141eef 100644 --- a/qase-cucumber6-jvm/pom.xml +++ b/qase-cucumber6-jvm/pom.xml @@ -34,6 +34,11 @@ cucumber-java ${cucumber6-java.version} + + io.cucumber + gherkin + 18.0.0 + org.projectlombok lombok diff --git a/qase-cucumber6-jvm/src/main/java/io/qase/cucumber6/QaseEventListener.java b/qase-cucumber6-jvm/src/main/java/io/qase/cucumber6/QaseEventListener.java index e9a933d..9ce5f76 100644 --- a/qase-cucumber6-jvm/src/main/java/io/qase/cucumber6/QaseEventListener.java +++ b/qase-cucumber6-jvm/src/main/java/io/qase/cucumber6/QaseEventListener.java @@ -1,5 +1,8 @@ package io.qase.cucumber6; +import io.cucumber.gherkin.Gherkin; +import io.cucumber.messages.IdGenerator; +import io.cucumber.messages.Messages; import io.cucumber.plugin.ConcurrentEventListener; import io.cucumber.plugin.event.*; import io.qase.api.QaseClient; @@ -16,18 +19,22 @@ import lombok.AccessLevel; import lombok.Getter; -import java.util.LinkedList; -import java.util.List; -import java.util.Optional; +import java.net.URI; +import java.util.*; +import java.util.stream.Stream; +import static io.cucumber.gherkin.Gherkin.makeSourceEnvelope; +import static io.qase.api.utils.CucumberUtils.getHash; import static io.qase.api.utils.IntegrationUtils.getStacktrace; public class QaseEventListener implements ConcurrentEventListener { + private static final Map> EXAMPLES = new HashMap<>(); private static final String REPORTER_NAME = "Cucumber 6-JVM"; @Getter(lazy = true, value = AccessLevel.PRIVATE) private final QaseTestCaseListener qaseTestCaseListener = createQaseListener(); + private final Map sources = new HashMap<>(); static { System.setProperty(QaseConfig.QASE_CLIENT_REPORTER_NAME_KEY, REPORTER_NAME); @@ -36,6 +43,7 @@ public class QaseEventListener implements ConcurrentEventListener { @Override public void setEventPublisher(EventPublisher publisher) { if (QaseClient.isEnabled()) { + publisher.registerHandlerFor(TestSourceRead.class, this::testSourceRead); publisher.registerHandlerFor(TestCaseStarted.class, this::testCaseStarted); publisher.registerHandlerFor(TestCaseFinished.class, this::testCaseFinished); publisher.registerHandlerFor(TestRunFinished.class, this::testRunFinished); @@ -44,6 +52,10 @@ public void setEventPublisher(EventPublisher publisher) { } } + private void testSourceRead(TestSourceRead testSourceRead) { + sources.put(testSourceRead.getUri(), testSourceRead.getSource()); + } + private void testCaseStarted(TestStepStarted testStepStarted) { if (testStepStarted.getTestStep() instanceof PickleStepTestStep) { StepStorage.startStep(); @@ -88,20 +100,63 @@ private void testRunFinished(TestRunFinished testRunFinished) { } private void testCaseStarted(TestCaseStarted event) { + URI uri = event.getTestCase().getUri(); + if (EXAMPLES.get(getHash(uri, (long) event.getTestCase().getLine())) == null && sources.containsKey(uri)) { + + Messages.Envelope envelope = makeSourceEnvelope(this.sources.get(uri), uri.toString()); + + Stream envelopes = Gherkin.fromSources( + Collections.singletonList(envelope), + true, + true, + true, + new IdGenerator.UUID()); + + envelopes + .filter(Messages.Envelope::hasGherkinDocument) + .map(Messages.Envelope::getGherkinDocument) + .findFirst() + .ifPresent(gherkinDocument -> parseExamples(uri, gherkinDocument)); + } getQaseTestCaseListener().onTestCaseStarted(); } + private void parseExamples(URI uri, Messages.GherkinDocument gherkinDocument) { + Messages.GherkinDocument.Feature feature = gherkinDocument.getFeature(); + List childrenList = feature.getChildrenList(); + for (int i = 0; i < childrenList.size(); i++) { + List examplesList = childrenList.get(i).getScenario().getExamplesList(); + for (int j = 0; j < examplesList.size(); j++) { + List headers = new ArrayList<>(); + Messages.GherkinDocument.Feature.TableRow tableHeader = examplesList.get(j).getTableHeader(); + tableHeader.getCellsList().forEach(h -> headers.add(h.getValue())); + List tableBodyList = examplesList.get(j).getTableBodyList(); + for (int k = 0; k < tableBodyList.size(); k++) { + Messages.GherkinDocument.Feature.TableRow tableRow = tableBodyList.get(k); + List cellsList = tableRow.getCellsList(); + HashMap example = new HashMap<>(); + for (int l = 0; l < cellsList.size(); l++) { + String value = cellsList.get(l).getValue(); + example.put(headers.get(l), value); + } + EXAMPLES.put(getHash(uri, (long) tableRow.getLocation().getLine()), example); + } + } + } + } + private void testCaseFinished(TestCaseFinished event) { getQaseTestCaseListener().onTestCaseFinished(resultCreate -> setupResultItem(resultCreate, event)); } private void setupResultItem(ResultCreate resultCreate, TestCaseFinished event) { - List tags = event.getTestCase().getTags(); + TestCase testCase = event.getTestCase(); + List tags = testCase.getTags(); Long caseId = CucumberUtils.getCaseId(tags); String caseTitle = null; if (caseId == null) { - caseTitle = event.getTestCase().getName(); + caseTitle = testCase.getName(); } StatusEnum status = convertStatus(event.getResult().getStatus()); @@ -122,6 +177,8 @@ private void setupResultItem(ResultCreate resultCreate, TestCaseFinished event) .stacktrace(stacktrace) .steps(steps.isEmpty() ? null : steps) .defect(isDefect); + Map params = EXAMPLES.get(getHash(testCase.getUri(), (long) testCase.getLocation().getLine())); + resultCreate.param(params); } private StatusEnum convertStatus(Status status) { diff --git a/qase-cucumber6-jvm/src/test/java/io/qase/cucumber6/QaseEventListenerTests.java b/qase-cucumber6-jvm/src/test/java/io/qase/cucumber6/QaseEventListenerTests.java index e73c83b..a6bf6df 100644 --- a/qase-cucumber6-jvm/src/test/java/io/qase/cucumber6/QaseEventListenerTests.java +++ b/qase-cucumber6-jvm/src/test/java/io/qase/cucumber6/QaseEventListenerTests.java @@ -74,7 +74,8 @@ void bulk() { String[] args = new String[]{ "-g", "io.qase.cucumber6", "--plugin", "io.qase.cucumber6.QaseEventListener", - "classpath:features/" + "classpath:features/", + "--threads", "4" }; Main.run(args, Thread.currentThread().getContextClassLoader()); @@ -155,8 +156,100 @@ void bulk() { " \"status\" : \"passed\",\n" + " \"action\" : \"Given success step\"\n" + " } ]\n" + + " }, {\n" + + " \"case\" : {\n" + + " \"title\" : \"success with Positive Examples\"\n" + + " },\n" + + " \"status\" : \"passed\",\n" + + " \"time_ms\" : \"${json-unit.ignore}\",\n" + + " \"defect\" : false,\n" + + " \"param\" : {\n" + + " \"a\" : \"\\\"1\\\"\",\n" + + " \"b\" : \"\\\"2\\\"\"\n" + + " },\n" + + " \"steps\" : [ {\n" + + " \"position\" : 1,\n" + + " \"status\" : \"passed\",\n" + + " \"action\" : \"Given success step with parameter \\\"1\\\"\"\n" + + " }, {\n" + + " \"position\" : 2,\n" + + " \"status\" : \"passed\",\n" + + " \"action\" : \"Given success step with parameter \\\"2\\\"\"\n" + + " } ]\n" + + " }, {\n" + + " \"case\" : {\n" + + " \"title\" : \"success with Positive Examples\"\n" + + " },\n" + + " \"status\" : \"passed\",\n" + + " \"time_ms\" : \"${json-unit.ignore}\",\n" + + " \"defect\" : false,\n" + + " \"param\" : {\n" + + " \"a\" : \"\\\"3\\\"\",\n" + + " \"b\" : \"\\\"4\\\"\"\n" + + " },\n" + + " \"steps\" : [ {\n" + + " \"position\" : 1,\n" + + " \"status\" : \"passed\",\n" + + " \"action\" : \"Given success step with parameter \\\"3\\\"\"\n" + + " }, {\n" + + " \"position\" : 2,\n" + + " \"status\" : \"passed\",\n" + + " \"action\" : \"Given success step with parameter \\\"4\\\"\"\n" + + " } ]\n" + + " }, {\n" + + " \"case\" : {\n" + + " \"title\" : \"success with Positive Examples\"\n" + + " },\n" + + " \"status\" : \"passed\",\n" + + " \"time_ms\" : \"${json-unit.ignore}\",\n" + + " \"defect\" : false,\n" + + " \"param\" : {\n" + + " \"a\" : \"\\\"5\\\"\",\n" + + " \"b\" : \"\\\"6\\\"\"\n" + + " },\n" + + " \"steps\" : [ {\n" + + " \"position\" : 1,\n" + + " \"status\" : \"passed\",\n" + + " \"action\" : \"Given success step with parameter \\\"5\\\"\"\n" + + " }, {\n" + + " \"position\" : 2,\n" + + " \"status\" : \"passed\",\n" + + " \"action\" : \"Given success step with parameter \\\"6\\\"\"\n" + + " } ]\n" + + " }, {\n" + + " \"case\" : {\n" + + " \"title\" : \"success with Positive Examples\"\n" + + " },\n" + + " \"status\" : \"passed\",\n" + + " \"time_ms\" : \"${json-unit.ignore}\",\n" + + " \"defect\" : false,\n" + + " \"param\" : {\n" + + " \"a\" : \"\\\"7\\\"\",\n" + + " \"b\" : \"\\\"8\\\"\"\n" + + " },\n" + + " \"steps\" : [ {\n" + + " \"position\" : 1,\n" + + " \"status\" : \"passed\",\n" + + " \"action\" : \"Given success step with parameter \\\"7\\\"\"\n" + + " }, {\n" + + " \"position\" : 2,\n" + + " \"status\" : \"passed\",\n" + + " \"action\" : \"Given success step with parameter \\\"8\\\"\"\n" + + " } ]\n" + + " }, {\n" + + " \"case\" : {\n" + + " \"title\" : \"Success scenario\"\n" + + " },\n" + + " \"status\" : \"passed\",\n" + + " \"time_ms\" : \"${json-unit.ignore}\",\n" + + " \"defect\" : false,\n" + + " \"steps\" : [ {\n" + + " \"position\" : 1,\n" + + " \"status\" : \"passed\",\n" + + " \"action\" : \"Given success step\"\n" + + " } ]\n" + " } ]\n" + - "}"))); + "}", true, false))); } @Test diff --git a/qase-cucumber6-jvm/src/test/java/io/qase/cucumber6/Steps.java b/qase-cucumber6-jvm/src/test/java/io/qase/cucumber6/Steps.java index 668e45e..6615252 100644 --- a/qase-cucumber6-jvm/src/test/java/io/qase/cucumber6/Steps.java +++ b/qase-cucumber6-jvm/src/test/java/io/qase/cucumber6/Steps.java @@ -10,6 +10,10 @@ public class Steps { public void success() { } + @Given("success step with parameter {string}") + public void success_step_with_parameter(String string) { + } + @Given("timeout {int} seconds") public void success(int integer) throws InterruptedException { TimeUnit.SECONDS.sleep(integer); diff --git a/qase-cucumber6-jvm/src/test/resources/features/with_examples.feature b/qase-cucumber6-jvm/src/test/resources/features/with_examples.feature new file mode 100644 index 0000000..44e7b68 --- /dev/null +++ b/qase-cucumber6-jvm/src/test/resources/features/with_examples.feature @@ -0,0 +1,15 @@ +Feature: New case with examples + + Scenario Outline: success with Positive Examples + Given success step with parameter + Given success step with parameter + + Examples: + | a | b | + | "1" | "2" | + | "3" | "4" | + | "5" | "6" | + | "7" | "8" | + + Scenario: Success scenario + Given success step \ No newline at end of file diff --git a/qase-cucumber7-jvm/src/test/java/io/qase/cucumber7/QaseEventListenerTests.java b/qase-cucumber7-jvm/src/test/java/io/qase/cucumber7/QaseEventListenerTests.java index 0e6d87e..ef03eba 100644 --- a/qase-cucumber7-jvm/src/test/java/io/qase/cucumber7/QaseEventListenerTests.java +++ b/qase-cucumber7-jvm/src/test/java/io/qase/cucumber7/QaseEventListenerTests.java @@ -75,7 +75,7 @@ void bulk() { "-g", "io.qase.cucumber7", "--plugin", "io.qase.cucumber7.QaseEventListener", "classpath:features/", - "--threads", "2" + "--threads", "4" }; Main.run(args, Thread.currentThread().getContextClassLoader());