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} - + + 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. *