diff --git a/plugin/pom.xml b/plugin/pom.xml
index 4a238a3f..f6580a13 100644
--- a/plugin/pom.xml
+++ b/plugin/pom.xml
@@ -25,7 +25,7 @@
9.2.0
- 1.14.0
+ 1.15.1
1.11.4-4
1.17.1
diff --git a/plugin/src/main/resources/io/jenkins/plugins/forensics/git/reference/GitCommitsRecord/summary.jelly b/plugin/src/main/resources/io/jenkins/plugins/forensics/git/reference/GitCommitsRecord/summary.jelly
index c09cf72e..58257c60 100644
--- a/plugin/src/main/resources/io/jenkins/plugins/forensics/git/reference/GitCommitsRecord/summary.jelly
+++ b/plugin/src/main/resources/io/jenkins/plugins/forensics/git/reference/GitCommitsRecord/summary.jelly
@@ -2,19 +2,24 @@
- SCM: ${it.scmKey}
-
-
-
- - Initial recording of ${size(it)} commits
-
-
- - Commits since last build: ${size(it)}
-
-
- - Latest commit:
-
+
+ SCM: ${it.scmKey}
+
+
+
+ - Initial recording of ${size(it)} commits
+
+
+ - Commits since last build: ${size(it)}
+
+
+
+ - Latest commit:
+
+
+
+
diff --git a/ui-tests/etc/assertj-templates/assertions_entry_point_class_template.txt b/ui-tests/etc/assertj-templates/assertions_entry_point_class_template.txt
new file mode 100644
index 00000000..f5204a15
--- /dev/null
+++ b/ui-tests/etc/assertj-templates/assertions_entry_point_class_template.txt
@@ -0,0 +1,17 @@
+package ${package};
+
+/**
+ * Entry point for assertions of different data types. Each method in this class is a static factory for the
+ * type-specific assertion objects.
+ */
+@edu.umd.cs.findbugs.annotations.SuppressFBWarnings("NM")
+@javax.annotation.Generated(value="assertj-assertions-generator")
+public class Assertions extends org.assertj.core.api.Assertions {
+${all_assertions_entry_points}
+ /**
+ * Creates a new {@link Assertions}
.
+ */
+ protected Assertions() {
+ // empty
+ }
+}
diff --git a/ui-tests/etc/assertj-templates/has_assertion_template.txt b/ui-tests/etc/assertj-templates/has_assertion_template.txt
new file mode 100644
index 00000000..e3493927
--- /dev/null
+++ b/ui-tests/etc/assertj-templates/has_assertion_template.txt
@@ -0,0 +1,23 @@
+
+ /**
+ * Verifies that the actual ${class_to_assert}'s ${property} is equal to the given one.
+ * @param ${property_safe} the given ${property} to compare the actual ${class_to_assert}'s ${property} to.
+ * @return this assertion object.
+ * @throws AssertionError - if the actual ${class_to_assert}'s ${property} is not equal to the given one.${throws_javadoc}
+ */
+ public ${self_type} has${Property}(${propertyType} ${property_safe}) ${throws}{
+ // check that actual ${class_to_assert} we want to make assertions on is not null.
+ isNotNull();
+
+ // overrides the default error message with a more explicit one
+ String assertjErrorMessage = "\nExpecting ${property} of:\n <%s>\nto be:\n <%s>\nbut was:\n <%s>";
+
+ // null safe check
+ ${propertyType} actual${Property} = actual.${getter}();
+ if (!java.util.Objects.deepEquals(actual${Property}, ${property_safe})) {
+ failWithMessage(assertjErrorMessage, actual, ${property_safe}, actual${Property});
+ }
+
+ // return the current assertion for method chaining
+ return ${myself};
+ }
diff --git a/ui-tests/etc/assertj-templates/soft_assertions_entry_point_class_template.txt b/ui-tests/etc/assertj-templates/soft_assertions_entry_point_class_template.txt
new file mode 100644
index 00000000..c7485e42
--- /dev/null
+++ b/ui-tests/etc/assertj-templates/soft_assertions_entry_point_class_template.txt
@@ -0,0 +1,10 @@
+package ${package};
+
+/**
+ * Entry point for soft assertions of different data types.
+ */
+@edu.umd.cs.findbugs.annotations.SuppressFBWarnings("NM")
+@javax.annotation.Generated(value="assertj-assertions-generator")
+public class SoftAssertions extends org.assertj.core.api.AutoCloseableSoftAssertions {
+${all_assertions_entry_points}
+}
diff --git a/ui-tests/pom.xml b/ui-tests/pom.xml
index dcc587e8..d71faa25 100644
--- a/ui-tests/pom.xml
+++ b/ui-tests/pom.xml
@@ -16,7 +16,7 @@
UI Tests of Git Forensics Plugin
- 2.338
+ 2.354
${project.groupId}.git.forensics.ui.tests
diff --git a/ui-tests/src/main/java/io/jenkins/plugins/forensics/DetailsTable.java b/ui-tests/src/main/java/io/jenkins/plugins/forensics/git/DetailsTable.java
similarity index 99%
rename from ui-tests/src/main/java/io/jenkins/plugins/forensics/DetailsTable.java
rename to ui-tests/src/main/java/io/jenkins/plugins/forensics/git/DetailsTable.java
index 8b7f5239..ece2acc3 100644
--- a/ui-tests/src/main/java/io/jenkins/plugins/forensics/DetailsTable.java
+++ b/ui-tests/src/main/java/io/jenkins/plugins/forensics/git/DetailsTable.java
@@ -1,4 +1,4 @@
-package io.jenkins.plugins.forensics;
+package io.jenkins.plugins.forensics.git;
import java.util.ArrayList;
import java.util.Collections;
diff --git a/ui-tests/src/main/java/io/jenkins/plugins/forensics/DetailsTableRow.java b/ui-tests/src/main/java/io/jenkins/plugins/forensics/git/DetailsTableRow.java
similarity index 95%
rename from ui-tests/src/main/java/io/jenkins/plugins/forensics/DetailsTableRow.java
rename to ui-tests/src/main/java/io/jenkins/plugins/forensics/git/DetailsTableRow.java
index 4b6e6e1b..cb67cf80 100644
--- a/ui-tests/src/main/java/io/jenkins/plugins/forensics/DetailsTableRow.java
+++ b/ui-tests/src/main/java/io/jenkins/plugins/forensics/git/DetailsTableRow.java
@@ -1,4 +1,4 @@
-package io.jenkins.plugins.forensics;
+package io.jenkins.plugins.forensics.git;
import java.util.Arrays;
import java.util.List;
@@ -8,7 +8,7 @@
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
-import static io.jenkins.plugins.forensics.DetailsTable.*;
+import static io.jenkins.plugins.forensics.git.DetailsTable.*;
/**
* Describes one row in the DetailsTable on the ScmForensics Page.
diff --git a/ui-tests/src/main/java/io/jenkins/plugins/forensics/ForensicsPublisher.java b/ui-tests/src/main/java/io/jenkins/plugins/forensics/git/ForensicsPublisher.java
similarity index 94%
rename from ui-tests/src/main/java/io/jenkins/plugins/forensics/ForensicsPublisher.java
rename to ui-tests/src/main/java/io/jenkins/plugins/forensics/git/ForensicsPublisher.java
index 46a06fe5..71fcf07b 100644
--- a/ui-tests/src/main/java/io/jenkins/plugins/forensics/ForensicsPublisher.java
+++ b/ui-tests/src/main/java/io/jenkins/plugins/forensics/git/ForensicsPublisher.java
@@ -1,4 +1,4 @@
-package io.jenkins.plugins.forensics;
+package io.jenkins.plugins.forensics.git;
import org.jenkinsci.test.acceptance.po.AbstractStep;
import org.jenkinsci.test.acceptance.po.Describable;
diff --git a/ui-tests/src/main/java/io/jenkins/plugins/forensics/ScmForensics.java b/ui-tests/src/main/java/io/jenkins/plugins/forensics/git/ScmForensics.java
similarity index 97%
rename from ui-tests/src/main/java/io/jenkins/plugins/forensics/ScmForensics.java
rename to ui-tests/src/main/java/io/jenkins/plugins/forensics/git/ScmForensics.java
index cbcd4bcb..ad506aa0 100644
--- a/ui-tests/src/main/java/io/jenkins/plugins/forensics/ScmForensics.java
+++ b/ui-tests/src/main/java/io/jenkins/plugins/forensics/git/ScmForensics.java
@@ -1,4 +1,4 @@
-package io.jenkins.plugins.forensics;
+package io.jenkins.plugins.forensics.git;
import java.net.URL;
diff --git a/ui-tests/src/main/java/io/jenkins/plugins/forensics/ScrollerUtil.java b/ui-tests/src/main/java/io/jenkins/plugins/forensics/git/ScrollerUtil.java
similarity index 95%
rename from ui-tests/src/main/java/io/jenkins/plugins/forensics/ScrollerUtil.java
rename to ui-tests/src/main/java/io/jenkins/plugins/forensics/git/ScrollerUtil.java
index 6204f94c..652e3333 100644
--- a/ui-tests/src/main/java/io/jenkins/plugins/forensics/ScrollerUtil.java
+++ b/ui-tests/src/main/java/io/jenkins/plugins/forensics/git/ScrollerUtil.java
@@ -1,4 +1,4 @@
-package io.jenkins.plugins.forensics;
+package io.jenkins.plugins.forensics.git;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
diff --git a/ui-tests/src/main/java/io/jenkins/plugins/forensics/git/Summary.java b/ui-tests/src/main/java/io/jenkins/plugins/forensics/git/Summary.java
new file mode 100644
index 00000000..6c807653
--- /dev/null
+++ b/ui-tests/src/main/java/io/jenkins/plugins/forensics/git/Summary.java
@@ -0,0 +1,79 @@
+package io.jenkins.plugins.forensics.git;
+
+import java.util.List;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+import org.apache.commons.lang3.StringUtils;
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebElement;
+
+import org.jenkinsci.test.acceptance.po.Build;
+import org.jenkinsci.test.acceptance.po.PageObject;
+
+/**
+ * {@link PageObject} representing the analysis summary on the build page of a job.
+ *
+ * @author Ullrich Hafner
+ * @author Manuel Hampp
+ * @author Michaela Reitschuster
+ * @author Alexandra Wenzel
+ */
+public class Summary extends PageObject {
+ private static final Pattern REMOVE_DETAILS = Pattern.compile("(\\r?\\n|\\r).*");
+
+ private final WebElement summarySpan;
+ private final String title;
+ private final List details;
+
+ /**
+ * Creates a new page object representing the analysis summary on the build page of a job.
+ *
+ * @param parent
+ * a finished build configured with a static analysis tool
+ * @param id
+ * the type of the result page (e.g. simian, checkstyle, cpd, etc.)
+ */
+ public Summary(final Build parent, final String id) {
+ super(parent, parent.url(id));
+
+ summarySpan = getElement(By.id(id));
+ title = REMOVE_DETAILS.matcher(summarySpan.getText()).replaceAll("");
+ details = summarySpan.findElements(by.xpath("ul/li")).stream()
+ .map(WebElement::getText)
+ .map(StringUtils::normalizeSpace)
+ .collect(Collectors.toList());
+ }
+
+ /**
+ * Return the title of the summary as text.
+ *
+ * @return the title text
+ */
+ public String getTitle() {
+ return title;
+ }
+
+ /**
+ * Returns the texts of the detail elements of the summary.
+ *
+ * @return the details
+ */
+ public List getDetails() {
+ return details;
+ }
+
+ /**
+ * Opens a link given by the specified text.
+ *
+ * @param text
+ * the text of the link
+ *
+ * @return the URL of the page that has been opened by the link
+ */
+ public String openLinkByText(final String text) {
+ summarySpan.findElement(By.linkText(text)).click();
+
+ return driver.getCurrentUrl();
+ }
+}
diff --git a/ui-tests/src/test/java/io/jenkins/plugins/forensics/ForensicsPluginUiTest.java b/ui-tests/src/test/java/io/jenkins/plugins/forensics/git/ForensicsPluginUiTest.java
similarity index 79%
rename from ui-tests/src/test/java/io/jenkins/plugins/forensics/ForensicsPluginUiTest.java
rename to ui-tests/src/test/java/io/jenkins/plugins/forensics/git/ForensicsPluginUiTest.java
index dc2384be..cfc67e72 100644
--- a/ui-tests/src/test/java/io/jenkins/plugins/forensics/ForensicsPluginUiTest.java
+++ b/ui-tests/src/test/java/io/jenkins/plugins/forensics/git/ForensicsPluginUiTest.java
@@ -1,9 +1,8 @@
-package io.jenkins.plugins.forensics;
+package io.jenkins.plugins.forensics.git;
import java.util.List;
import org.junit.Test;
-import org.openqa.selenium.By;
import org.jenkinsci.test.acceptance.junit.AbstractJUnitTest;
import org.jenkinsci.test.acceptance.junit.WithPlugins;
@@ -11,8 +10,8 @@
import org.jenkinsci.test.acceptance.po.Job;
import org.jenkinsci.test.acceptance.po.WorkflowJob;
-import static io.jenkins.plugins.forensics.DetailsTable.*;
-import static org.assertj.core.api.Assertions.*;
+import static io.jenkins.plugins.forensics.git.Assertions.*;
+import static io.jenkins.plugins.forensics.git.DetailsTable.*;
/**
* Acceptance tests for the Git Forensics Plugin.
@@ -22,9 +21,8 @@
@WithPlugins({"forensics-api", "git-forensics", "git", "workflow-durable-task-step", "workflow-basic-steps"})
public class ForensicsPluginUiTest extends AbstractJUnitTest {
private static final String REPOSITORY_URL = "https://github.com/jenkinsci/git-forensics-plugin.git";
- private static final int GIT_SUMMARY_ROW = 2;
- private static final int COMMIT_RECORDER_ROW = 3;
- private static final int MINER_ROW = 4;
+ private static final String SCM_KEY = "git " + REPOSITORY_URL;
+ private static final int SCM_HASH = SCM_KEY.hashCode();
/**
* Verifies the Git miner by running a build with the forensics plugin analyzing a commit hash of the
@@ -41,27 +39,29 @@ public void shouldAggregateToolsIntoSingleResult() {
"-> 10444 lines deleted");
build.open();
- assertThat(getSummaryText(build, GIT_SUMMARY_ROW)).contains(
- "Revision: 28af63def44286729e3b19b03464d100fd1d0587", "detached");
-
- // TODO: create page objects
- assertThat(getSummaryText(build, COMMIT_RECORDER_ROW)).contains(
- "SCM: git " + REPOSITORY_URL,
- "Initial recording of 200 commits",
- "Latest commit: 28af63d");
-
- assertThat(getSummaryText(build, MINER_ROW)).contains(
- "New commits: 402",
- "4 authors",
- "131 files",
- "16510 added",
- "10444 deleted");
-
- ScmForensics scmForensics = new ScmForensics(build, "forensics");
- scmForensics.open();
- DetailsTable detailsTable = new DetailsTable(scmForensics);
-
- assertThat(scmForensics.getTotal()).isEqualTo(51);
+
+ Summary commitStatistics = new Summary(build, "commits-of-" + SCM_HASH);
+ assertThat(commitStatistics).hasTitle("SCM: " + SCM_KEY);
+ assertThat(commitStatistics).hasDetails("Initial recording of 200 commits", "Latest commit: 28af63d");
+ assertThat(commitStatistics.openLinkByText("28af63d")).isEqualTo("https://github.com/jenkinsci/git-forensics-plugin/commit/28af63def44286729e3b19b03464d100fd1d0587");
+
+ build.open();
+
+ Summary scmForensics = new Summary(build, "scm-forensics-of-" + SCM_HASH);
+ assertThat(scmForensics).hasTitle("SCM Forensics: " + SCM_KEY);
+ assertThat(scmForensics).hasDetails("51 repository files (total lines of code: 6066, total churn: 16966)",
+ "New commits: 402 (from 4 authors in 131 files)",
+ "Changed lines: 16510 added, 10444 deleted");
+
+ assertThat(scmForensics.openLinkByText("51 repository files")).endsWith("1/forensics/");
+
+ // TODO: navigate from summary
+
+ ScmForensics forensicsDetails = new ScmForensics(build, "forensics");
+ forensicsDetails.open();
+ assertThat(forensicsDetails.getTotal()).isEqualTo(51);
+
+ DetailsTable detailsTable = new DetailsTable(forensicsDetails);
assertTableHeaders(detailsTable);
assertTableEntriesAndSorting(detailsTable);
assertSearch(detailsTable);
@@ -80,11 +80,6 @@ private WorkflowJob createJob() {
return job;
}
- private String getSummaryText(final Build referenceBuild, final int row) {
- return referenceBuild.getElement(
- By.xpath("/html/body/div[4]/div[2]/table/tbody/tr[" + row + "]/td[2]")).getText();
- }
-
/**
* asserts the headers of the table by their size and entries.
*