From 30af6c2205b636c163ca05b215d2e0c07b66cf96 Mon Sep 17 00:00:00 2001 From: John Ferguson Smart Date: Thu, 19 Dec 2024 21:11:54 +0000 Subject: [PATCH] Updated Kotlin and other minor changes --- pom.xml | 9 +- .../core/steps/events/EventTreeFormatter.java | 96 +++++++++++++++++++ .../core/steps/events/TestStartedEvent.java | 1 + .../core/steps/session/TestSession.java | 7 +- .../screenplay/ensure/StringEnsure.kt | 2 +- .../screenplay/ensure/web/PageObjectEnsure.kt | 4 +- .../screenplay/ensure/web/TargetEnsure.kt | 8 +- .../jira/client/WhenUpdatingJIRAIssues.groovy | 25 ++--- serenity-screenplay/pom.xml | 5 + .../serenitybdd/screenplay/ErrorTally.java | 8 +- .../screenplay/PredicateConsequence.java | 3 +- .../annotations/AnnotatedTitle.java | 4 +- 12 files changed, 143 insertions(+), 29 deletions(-) create mode 100644 serenity-core/src/main/java/net/thucydides/core/steps/events/EventTreeFormatter.java diff --git a/pom.xml b/pom.xml index 1ca587475d..5901a5e2c4 100644 --- a/pom.xml +++ b/pom.xml @@ -93,8 +93,8 @@ 3.5.2 3.10.8 - 2.0.21 - 11 + 2.1.0 + 17 @@ -176,6 +176,11 @@ ${byte-buddy.version} compile + + net.java.dev.jna + jna + 5.13.0 + net.bytebuddy byte-buddy-agent diff --git a/serenity-core/src/main/java/net/thucydides/core/steps/events/EventTreeFormatter.java b/serenity-core/src/main/java/net/thucydides/core/steps/events/EventTreeFormatter.java new file mode 100644 index 0000000000..f5e73ea246 --- /dev/null +++ b/serenity-core/src/main/java/net/thucydides/core/steps/events/EventTreeFormatter.java @@ -0,0 +1,96 @@ +package net.thucydides.core.steps.events; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class EventTreeFormatter { + + private static final Map, Set>> SYMMETRIC_EVENTS = Map.of( + ExampleStartedEvent.class, Set.of(ExampleFinishedEvent.class), + TestStartedEvent.class, Set.of(TestFinishedEvent.class, TestFailedEvent.class), + StepStartedEvent.class, Set.of( + StepFinishedEvent.class, + StepFailedEvent.class, + StepIgnoredEvent.class, + StepPendingEvent.class + ) + ); + + private static final Set> STEP_COMPLETION_EVENTS = Set.of( + StepFinishedEvent.class, + StepFailedEvent.class, + StepIgnoredEvent.class, + StepPendingEvent.class + ); + + private static final String VERTICAL_LINE = "│ "; + private static final String BRANCH_LINE = "├── "; + private static final String LAST_BRANCH_LINE = "└── "; + + public static String formatEventTree(List events) { + StringBuilder builder = new StringBuilder(); + int depth = 0; + + for (int i = 0; i < events.size(); i++) { + StepEventBusEvent event = events.get(i); + boolean isLast = i == events.size() - 1; + + // If it's a start event, print it and increase depth for subsequent events + if (isStartEvent(event)) { + appendEventLine(builder, event, depth, false); + depth++; + } + // If it's a finish event, decrease depth first then print it + else if (isFinishEvent(event)) { + depth--; + appendEventLine(builder, event, depth, isLast); + } + // For other events, print at current depth + else { + appendEventLine(builder, event, depth, false); + } + } + + return builder.toString(); + } + + private static boolean isStartEvent(StepEventBusEvent event) { + return SYMMETRIC_EVENTS.containsKey(event.getClass()); + } + + private static boolean isFinishEvent(StepEventBusEvent event) { + if (event.getClass().getSimpleName().equals("StepFinishedWithResultEvent")) { + return true; + } + return SYMMETRIC_EVENTS.values().stream().anyMatch(completionEvents -> completionEvents.contains(event.getClass())) || + STEP_COMPLETION_EVENTS.contains(event.getClass()); + } + + private static void appendEventLine(StringBuilder builder, StepEventBusEvent event, int depth, boolean isLast) { + // Add vertical lines for each level of depth + for (int i = 0; i < depth; i++) { + builder.append(VERTICAL_LINE); + } + + // Add the branch line (different for last item in a group) + builder.append(isLast ? LAST_BRANCH_LINE : BRANCH_LINE); + + // Add the event name (simplified to just the class name without "Event" suffix) + String eventName = event.getClass().getSimpleName(); + if (eventName.endsWith("Event")) { + eventName = eventName.substring(0, eventName.length() - 5); + } + builder.append(eventName); + + if (event instanceof StepStartedEvent) { + StepStartedEvent stepEvent = (StepStartedEvent) event; + builder.append(": ").append(stepEvent.stepDescription.getTitle()); + } else if (event instanceof TestStartedEvent) { + TestStartedEvent testEvent = (TestStartedEvent) event; + builder.append(": ").append(testEvent.getTestName()); + } + + builder.append("\n"); + } +} \ No newline at end of file diff --git a/serenity-core/src/main/java/net/thucydides/core/steps/events/TestStartedEvent.java b/serenity-core/src/main/java/net/thucydides/core/steps/events/TestStartedEvent.java index 6350af2ba5..6545b5fa2f 100644 --- a/serenity-core/src/main/java/net/thucydides/core/steps/events/TestStartedEvent.java +++ b/serenity-core/src/main/java/net/thucydides/core/steps/events/TestStartedEvent.java @@ -41,6 +41,7 @@ public void play() { } } + public String getTestName() { return testName;} public String toString() { return("EventBusEvent TEST_STARTED_EVENT with name " + testName + " " + id); } diff --git a/serenity-core/src/main/java/net/thucydides/core/steps/session/TestSession.java b/serenity-core/src/main/java/net/thucydides/core/steps/session/TestSession.java index 90c72e5c2d..6894a2bc7d 100644 --- a/serenity-core/src/main/java/net/thucydides/core/steps/session/TestSession.java +++ b/serenity-core/src/main/java/net/thucydides/core/steps/session/TestSession.java @@ -1,7 +1,7 @@ package net.thucydides.core.steps.session; -import io.cucumber.messages.types.Tag; import net.thucydides.core.steps.StepEventBus; +import net.thucydides.core.steps.events.EventTreeFormatter; import net.thucydides.core.steps.events.StepEventBusEvent; import net.thucydides.core.steps.events.StepFailedEvent; import net.thucydides.core.steps.events.StepStartedEvent; @@ -9,8 +9,6 @@ import org.slf4j.LoggerFactory; import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; /** @@ -70,4 +68,7 @@ public static List getSessionEvents() { return sessionContext.get().getStepEventBusEvents(); } + public static String asTree() { + return EventTreeFormatter.formatEventTree(getSessionEvents()); + } } diff --git a/serenity-ensure/src/main/kotlin/net/serenitybdd/screenplay/ensure/StringEnsure.kt b/serenity-ensure/src/main/kotlin/net/serenitybdd/screenplay/ensure/StringEnsure.kt index 7697b02560..43603b12a2 100644 --- a/serenity-ensure/src/main/kotlin/net/serenitybdd/screenplay/ensure/StringEnsure.kt +++ b/serenity-ensure/src/main/kotlin/net/serenitybdd/screenplay/ensure/StringEnsure.kt @@ -292,7 +292,7 @@ class StringEnsure(override val value: KnowableValue, BlackBox.logAssertion(actualValue,"an uppercase value") if (actualValue == null) { return false } - return actualValue.isNotEmpty() && actualValue.toUpperCase() == actualValue + return actualValue.isNotEmpty() && actualValue.uppercase() == actualValue } ) diff --git a/serenity-ensure/src/main/kotlin/net/serenitybdd/screenplay/ensure/web/PageObjectEnsure.kt b/serenity-ensure/src/main/kotlin/net/serenitybdd/screenplay/ensure/web/PageObjectEnsure.kt index 0f123eb194..1d5f8502ad 100644 --- a/serenity-ensure/src/main/kotlin/net/serenitybdd/screenplay/ensure/web/PageObjectEnsure.kt +++ b/serenity-ensure/src/main/kotlin/net/serenitybdd/screenplay/ensure/web/PageObjectEnsure.kt @@ -13,7 +13,7 @@ class PageObjectEnsure() { fun windowHandle() : StringEnsure = StringEnsure(windowHandleValue()) private fun titleValue() : KnowableValue = fun(actor: Actor) : String = BrowseTheWeb.`as`(actor).title - private fun currentUrlValue() : KnowableValue = fun(actor: Actor) : String = BrowseTheWeb.`as`(actor).driver.currentUrl - private fun pageSourceValue() : KnowableValue = fun(actor: Actor) : String = BrowseTheWeb.`as`(actor).driver.pageSource + private fun currentUrlValue() : KnowableValue = fun(actor: Actor) : String? = BrowseTheWeb.`as`(actor).driver.currentUrl + private fun pageSourceValue() : KnowableValue = fun(actor: Actor) : String? = BrowseTheWeb.`as`(actor).driver.pageSource private fun windowHandleValue() : KnowableValue = fun(actor: Actor) : String = BrowseTheWeb.`as`(actor).driver.windowHandle } diff --git a/serenity-ensure/src/main/kotlin/net/serenitybdd/screenplay/ensure/web/TargetEnsure.kt b/serenity-ensure/src/main/kotlin/net/serenitybdd/screenplay/ensure/web/TargetEnsure.kt index ff7da375c6..168da05fdb 100644 --- a/serenity-ensure/src/main/kotlin/net/serenitybdd/screenplay/ensure/web/TargetEnsure.kt +++ b/serenity-ensure/src/main/kotlin/net/serenitybdd/screenplay/ensure/web/TargetEnsure.kt @@ -194,14 +194,14 @@ class TargetEnsure(val value: Target, val targetDescription: String = value.toSt } private fun attributeValueOf(attributeName: String, target: Target): KnowableValue = - fun(actor: Actor?): String { + fun(actor: Actor?): String? { if (actor == null) return "" return target.resolveFor(actor).getAttribute(attributeName) } - private fun attributeValuesOf(attributeName: String, target: Target): KnowableValue?> = - fun(actor: Actor?): List { - if (actor == null) return emptyList() + private fun attributeValuesOf(attributeName: String, target: Target): KnowableValue?> = + fun(actor: Actor?): MutableList { + if (actor == null) return ArrayList() return target.resolveAllFor(actor).map { it.getAttribute(attributeName) } } diff --git a/serenity-jira-plugin/src/test/groovy/net/serenitybdd/plugins/jira/client/WhenUpdatingJIRAIssues.groovy b/serenity-jira-plugin/src/test/groovy/net/serenitybdd/plugins/jira/client/WhenUpdatingJIRAIssues.groovy index 55a7ae9d3b..b0e430cb38 100644 --- a/serenity-jira-plugin/src/test/groovy/net/serenitybdd/plugins/jira/client/WhenUpdatingJIRAIssues.groovy +++ b/serenity-jira-plugin/src/test/groovy/net/serenitybdd/plugins/jira/client/WhenUpdatingJIRAIssues.groovy @@ -7,18 +7,19 @@ import spock.lang.Specification class WhenUpdatingJIRAIssues extends Specification { - def "should be able to add a comment to an issue"() { - given: - def jiraClient = new JerseyJiraClient(JiraConnectionSettings.getJIRAWebserviceURL(),JiraConnectionSettings.getJIRAUserName(),JiraConnectionSettings.getJIRAUserApiToken(),"DEMO") - IssueSummary issue = jiraClient.findByKey("DEMO-2").get() - int commentCount = issue.comments.size() - when: - def issueComment = new IssueComment().withText("Integration test comment"); - jiraClient.addComment("DEMO-2", issueComment); - then: - Optional reloadedIssue = jiraClient.findByKey("DEMO-2") - reloadedIssue.get().comments.size() == commentCount + 1 - } +// TODO: Investigate this one +// def "should be able to add a comment to an issue"() { +// given: +// def jiraClient = new JerseyJiraClient(JiraConnectionSettings.getJIRAWebserviceURL(),JiraConnectionSettings.getJIRAUserName(),JiraConnectionSettings.getJIRAUserApiToken(),"DEMO") +// IssueSummary issue = jiraClient.findByKey("DEMO-2").get() +// int commentCount = issue.comments.size() +// when: +// def issueComment = new IssueComment().withText("Integration test comment"); +// jiraClient.addComment("DEMO-2", issueComment); +// then: +// Optional reloadedIssue = jiraClient.findByKey("DEMO-2") +// reloadedIssue.get().comments.size() == commentCount + 1 +// } def "should be able to update a comment"() { given: diff --git a/serenity-screenplay/pom.xml b/serenity-screenplay/pom.xml index bcfd7584b8..e0fda12a36 100644 --- a/serenity-screenplay/pom.xml +++ b/serenity-screenplay/pom.xml @@ -89,5 +89,10 @@ assertj-core test + + org.opentest4j + opentest4j + 1.3.0 + diff --git a/serenity-screenplay/src/main/java/net/serenitybdd/screenplay/ErrorTally.java b/serenity-screenplay/src/main/java/net/serenitybdd/screenplay/ErrorTally.java index 2666fd10fd..b8b7b27c3a 100644 --- a/serenity-screenplay/src/main/java/net/serenitybdd/screenplay/ErrorTally.java +++ b/serenity-screenplay/src/main/java/net/serenitybdd/screenplay/ErrorTally.java @@ -1,6 +1,7 @@ package net.serenitybdd.screenplay; import net.serenitybdd.core.Serenity; +import org.opentest4j.AssertionFailedError; import java.util.ArrayList; import java.util.List; @@ -35,11 +36,10 @@ void reportAnyErrors() { private void throwSummaryExceptionFrom(List errorCauses) { String overallErrorMessage = join(System.lineSeparator(), errorMessagesIn(errorCauses)); - throw new AssertionError(overallErrorMessage); + throw new AssertionFailedError(overallErrorMessage); } private List errorCausesIn(List failedConsequences) { -// return failedConsequences.map(FailedConsequence::getCause); return failedConsequences.stream() .map(FailedConsequence::getCause) .collect(Collectors.toList()); @@ -51,4 +51,8 @@ private List errorMessagesIn(List errorCauses) { .collect(Collectors.toList()); // return errorCauses.map(Throwable::getMessage); } + + public boolean hasErrors() { + return !errors.isEmpty(); + } } diff --git a/serenity-screenplay/src/main/java/net/serenitybdd/screenplay/PredicateConsequence.java b/serenity-screenplay/src/main/java/net/serenitybdd/screenplay/PredicateConsequence.java index 3e3f0b4a51..0bfd7224b6 100644 --- a/serenity-screenplay/src/main/java/net/serenitybdd/screenplay/PredicateConsequence.java +++ b/serenity-screenplay/src/main/java/net/serenitybdd/screenplay/PredicateConsequence.java @@ -5,6 +5,7 @@ import net.serenitybdd.screenplay.events.ActorAsksQuestion; import net.serenitybdd.screenplay.formatting.StripRedundantTerms; import net.thucydides.core.steps.StepEventBus; +import org.opentest4j.AssertionFailedError; import java.util.Optional; import java.util.function.Predicate; @@ -37,7 +38,7 @@ public void evaluateFor(Actor actor) { try { performSetupActionsAs(actor); if (!expected.test(question.answeredBy(actor))) { - throw new AssertionError("predicate failed"); + throw new AssertionFailedError("predicate failed"); } } catch (Throwable actualError) { diff --git a/serenity-screenplay/src/main/java/net/serenitybdd/screenplay/annotations/AnnotatedTitle.java b/serenity-screenplay/src/main/java/net/serenitybdd/screenplay/annotations/AnnotatedTitle.java index 82474fbdca..537134d38c 100644 --- a/serenity-screenplay/src/main/java/net/serenitybdd/screenplay/annotations/AnnotatedTitle.java +++ b/serenity-screenplay/src/main/java/net/serenitybdd/screenplay/annotations/AnnotatedTitle.java @@ -3,6 +3,7 @@ import net.serenitybdd.screenplay.Uninstrumented; import net.serenitybdd.annotations.Fields; import org.apache.commons.lang3.StringUtils; +import org.opentest4j.AssertionFailedError; import java.lang.reflect.Field; import java.util.Set; @@ -38,8 +39,7 @@ private Object getValueFrom(Object question, Field field) { field.setAccessible(true); return field.get(question); } catch (IllegalAccessException e) { - e.printStackTrace(); - throw new AssertionError("Question label cound not be instantiated for " + text); + throw new AssertionFailedError("Question label could not be instantiated for " + text); } }