diff --git a/doc/style/style.xml b/doc/style/style.xml index d29bd4c5..43e12d26 100755 --- a/doc/style/style.xml +++ b/doc/style/style.xml @@ -1,77 +1,124 @@ + "-//Checkstyle//DTD Checkstyle Configuration 1.3//EN" + "https://checkstyle.org/dtds/configuration_1_3.dtd"> - - - - - + - + + + + + + + + + + + + + - - + - - - - + + + - - + value="\\u00(09|0(a|A)|0(c|C)|0(d|D)|22|27|5(C|c))|\\(0(10|11|12|14|15|42|47)|134)"/> + + - + + + - - + + + + + + + + + + + + value="CLASS_DEF, METHOD_DEF, CTOR_DEF, LITERAL_FOR, LITERAL_WHILE, STATIC_INIT, + INSTANCE_INIT, ANNOTATION_DEF, ENUM_DEF, INTERFACE_DEF, RECORD_DEF, + COMPACT_CTOR_DEF"/> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + @@ -112,27 +182,45 @@ value="Member name ''{0}'' must match pattern ''{1}''."/> - + + + + + - + - - - + + + + + + + + + + + + + + @@ -154,61 +243,118 @@ value="GenericWhitespace ''{0}'' is not preceded with whitespace."/> - - - + + + + - - + + - - + + + + + + + + + + + + + - + value="BAND, BOR, BSR, BXOR, DIV, EQUAL, GE, GT, LAND, LE, LITERAL_INSTANCEOF, LOR, + LT, MINUS, MOD, NOT_EQUAL, PLUS, QUESTION, SL, SR, STAR, METHOD_REF, + TYPE_EXTENSION_AND "/> + + value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF, METHOD_DEF, CTOR_DEF, + RECORD_DEF, COMPACT_CTOR_DEF"/> + - - - - - - - - - + + + + + + + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + \ No newline at end of file diff --git a/pom.xml b/pom.xml index 15d61c9f..8be68dad 100644 --- a/pom.xml +++ b/pom.xml @@ -247,7 +247,7 @@ com.puppycrawl.tools checkstyle - 8.41.1 + 8.42 diff --git a/src/main/java/com/frameworkium/core/api/Endpoint.java b/src/main/java/com/frameworkium/core/api/Endpoint.java index 17f7c830..67b7472c 100644 --- a/src/main/java/com/frameworkium/core/api/Endpoint.java +++ b/src/main/java/com/frameworkium/core/api/Endpoint.java @@ -26,11 +26,11 @@ */ public interface Endpoint { - /** - * Calls {@link String#format(String, Object...)} on the url. - * - * @param params Arguments referenced by the format specifiers in the url. - * @return A formatted String representing the URL of the given constant. - */ - String getUrl(Object... params); + /** + * Calls {@link String#format(String, Object...)} on the url. + * + * @param params Arguments referenced by the format specifiers in the url. + * @return A formatted String representing the URL of the given constant. + */ + String getUrl(Object... params); } diff --git a/src/main/java/com/frameworkium/core/api/dto/AbstractDTO.java b/src/main/java/com/frameworkium/core/api/dto/AbstractDTO.java index 53c5f041..707e19ac 100644 --- a/src/main/java/com/frameworkium/core/api/dto/AbstractDTO.java +++ b/src/main/java/com/frameworkium/core/api/dto/AbstractDTO.java @@ -1,35 +1,37 @@ package com.frameworkium.core.api.dto; -import org.apache.commons.lang3.SerializationUtils; -import org.apache.commons.lang3.builder.*; - import java.io.Serializable; +import org.apache.commons.lang3.SerializationUtils; +import org.apache.commons.lang3.builder.EqualsBuilder; +import org.apache.commons.lang3.builder.HashCodeBuilder; +import org.apache.commons.lang3.builder.ReflectionToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; public abstract class AbstractDTO implements Serializable, Cloneable { - @Override - public int hashCode() { - return HashCodeBuilder.reflectionHashCode(this); - } + @Override + public int hashCode() { + return HashCodeBuilder.reflectionHashCode(this); + } - @Override - public boolean equals(Object obj) { - return EqualsBuilder.reflectionEquals(this, obj); - } + @Override + public boolean equals(Object obj) { + return EqualsBuilder.reflectionEquals(this, obj); + } - @Override - @SuppressWarnings("unchecked") - protected T clone() throws CloneNotSupportedException { - try { - return (T) SerializationUtils.clone(this); - } catch (Exception e) { - throw new CloneNotSupportedException(e.getMessage()); - } + @Override + @SuppressWarnings("unchecked") + protected T clone() throws CloneNotSupportedException { + try { + return (T) SerializationUtils.clone(this); + } catch (Exception e) { + throw new CloneNotSupportedException(e.getMessage()); } + } - @Override - public String toString() { - return ReflectionToStringBuilder.toString( - this, ToStringStyle.SHORT_PREFIX_STYLE); - } + @Override + public String toString() { + return ReflectionToStringBuilder.toString( + this, ToStringStyle.SHORT_PREFIX_STYLE); + } } diff --git a/src/main/java/com/frameworkium/core/api/services/BaseService.java b/src/main/java/com/frameworkium/core/api/services/BaseService.java index fc57ac03..98f5f366 100755 --- a/src/main/java/com/frameworkium/core/api/services/BaseService.java +++ b/src/main/java/com/frameworkium/core/api/services/BaseService.java @@ -7,124 +7,123 @@ import io.restassured.response.ExtractableResponse; import io.restassured.specification.RequestSpecification; import io.restassured.specification.ResponseSpecification; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - import java.net.URI; import java.net.URISyntaxException; import java.util.Map; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; public abstract class BaseService { - protected static final Logger logger = LogManager.getLogger(); + protected static final Logger logger = LogManager.getLogger(); - static { - if (Property.PROXY.isSpecified()) { - try { - RestAssured.proxy(new URI(Property.PROXY.getValue())); - } catch (URISyntaxException e) { - logger.error("Proxy URI given is in an invalid format." - + " Ensure it's in the format of: http://{hostname}:{port}", e); - } - } + static { + if (Property.PROXY.isSpecified()) { + try { + RestAssured.proxy(new URI(Property.PROXY.getValue())); + } catch (URISyntaxException e) { + logger.error("Proxy URI given is in an invalid format." + + " Ensure it's in the format of: http://{hostname}:{port}", e); + } } + } - /** - * Used to define the RequestSpecification common to all operations - * defined in the given service. For example: - *
RestAssured.given().proxy(...)
- * - * @return the RestAssured RequestSpecification with appropriate defaults - */ - protected abstract RequestSpecification getRequestSpec(); + /** + * Used to define the RequestSpecification common to all operations + * defined in the given service. For example: + *
RestAssured.given().proxy(...)
+ * + * @return the RestAssured RequestSpecification with appropriate defaults + */ + protected abstract RequestSpecification getRequestSpec(); - /** - * Used to define the RequestSpecification common to all operations - * defined in the given service. For example: - *
-     *     getDefaultRequestSpecification().then().response().statusCode(200);
-     * 
- * - * @return the RestAssured ResponseSpecification with appropriate defaults - */ - protected abstract ResponseSpecification getResponseSpec(); + /** + * Used to define the RequestSpecification common to all operations + * defined in the given service. For example: + *
+   *     getDefaultRequestSpecification().then().response().statusCode(200);
+   * 
+ * + * @return the RestAssured ResponseSpecification with appropriate defaults + */ + protected abstract ResponseSpecification getResponseSpec(); - /** - * Performs GET request of the URL. - * - * @return The response from the request - */ - protected ExtractableResponse get(String url) { - return get(ImmutableMap.of(), url); - } + /** + * Performs GET request of the URL. + * + * @return The response from the request + */ + protected ExtractableResponse get(String url) { + return get(ImmutableMap.of(), url); + } - /** - * Performs GET request of the URL with parameters. - * - * @param params the GET parameters - * @param url the URL to GET - * @return The response from the request - */ - protected ExtractableResponse get(Map params, String url) { - return request(Method.GET, params, url); - } + /** + * Performs GET request of the URL with parameters. + * + * @param params the GET parameters + * @param url the URL to GET + * @return The response from the request + */ + protected ExtractableResponse get(Map params, String url) { + return request(Method.GET, params, url); + } - /** - * Performs GET request of the URL. - * - * @return The response from the request - * @deprecated use {@link #get(String)} - */ - @Deprecated - protected ExtractableResponse request(String url) { - return request(ImmutableMap.of(), url); - } + /** + * Performs GET request of the URL. + * + * @return The response from the request + * @deprecated use {@link #get(String)} + */ + @Deprecated + protected ExtractableResponse request(String url) { + return request(ImmutableMap.of(), url); + } - /** - * Performs GET request of the URL with parameters. - * - * @return The response from the request - * @deprecated use {@link #get(Map, String)} - */ - @Deprecated - protected ExtractableResponse request(Map params, String url) { - return request(Method.GET, params, url); - } + /** + * Performs GET request of the URL with parameters. + * + * @return The response from the request + * @deprecated use {@link #get(Map, String)} + */ + @Deprecated + protected ExtractableResponse request(Map params, String url) { + return request(Method.GET, params, url); + } - /** - * Performs specified HTTP verb request of the URL with parameters. - * - * @param method the HTTP method to request - * @param params the request parameters - * @param url the URL to request - * @return The response from the request - */ - protected ExtractableResponse request(Method method, Map params, String url) { - return getRequestSpec() - .params(params) - .when() - .request(method, url) - .then() - .spec(getResponseSpec()) - .extract(); - } + /** + * Performs specified HTTP verb request of the URL with parameters. + * + * @param method the HTTP method to request + * @param params the request parameters + * @param url the URL to request + * @return The response from the request + */ + protected ExtractableResponse request(Method method, Map params, String url) { + return getRequestSpec() + .params(params) + .when() + .request(method, url) + .then() + .spec(getResponseSpec()) + .extract(); + } - /** - * Performs specified HTTP verb request of the URL with the given body. - * - * @param method the HTTP method to request - * @param body the body of the request - * @param url the URL to request - * @return The response from the request - */ - protected ExtractableResponse request(Method method, Object body, String url) { - return getRequestSpec() - .when() - .body(body) - .request(method, url) - .then() - .spec(getResponseSpec()) - .extract(); - } + /** + * Performs specified HTTP verb request of the URL with the given body. + * + * @param method the HTTP method to request + * @param body the body of the request + * @param url the URL to request + * @return The response from the request + */ + protected ExtractableResponse request(Method method, Object body, String url) { + return getRequestSpec() + .when() + .body(body) + .request(method, url) + .then() + .spec(getResponseSpec()) + .extract(); + } } diff --git a/src/main/java/com/frameworkium/core/api/tests/BaseAPITest.java b/src/main/java/com/frameworkium/core/api/tests/BaseAPITest.java index 008c4ce8..cc40a943 100644 --- a/src/main/java/com/frameworkium/core/api/tests/BaseAPITest.java +++ b/src/main/java/com/frameworkium/core/api/tests/BaseAPITest.java @@ -1,23 +1,29 @@ package com.frameworkium.core.api.tests; -import com.frameworkium.core.common.listeners.*; +import com.frameworkium.core.common.listeners.MethodInterceptor; +import com.frameworkium.core.common.listeners.ResultLoggerListener; +import com.frameworkium.core.common.listeners.TestListener; import com.frameworkium.core.common.reporting.allure.AllureProperties; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.testng.annotations.*; +import org.testng.annotations.AfterSuite; +import org.testng.annotations.Listeners; +import org.testng.annotations.Test; @Listeners({MethodInterceptor.class, - TestListener.class, - ResultLoggerListener.class}) + TestListener.class, + ResultLoggerListener.class}) @Test(groups = "base-api") public abstract class BaseAPITest { - protected final Logger logger = LogManager.getLogger(this); + protected final Logger logger = LogManager.getLogger(this); - /** Creates the allure properties for the report, after the test run. */ - @AfterSuite(alwaysRun = true) - public static void createAllureProperties() { - AllureProperties.createAPI(); - } + /** + * Creates the allure properties for the report, after the test run. + */ + @AfterSuite(alwaysRun = true) + public static void createAllureProperties() { + AllureProperties.createAPI(); + } } diff --git a/src/main/java/com/frameworkium/core/common/listeners/CreateJiraCycleListener.java b/src/main/java/com/frameworkium/core/common/listeners/CreateJiraCycleListener.java index 1f7c7ac6..ad307c9d 100644 --- a/src/main/java/com/frameworkium/core/common/listeners/CreateJiraCycleListener.java +++ b/src/main/java/com/frameworkium/core/common/listeners/CreateJiraCycleListener.java @@ -1,8 +1,12 @@ package com.frameworkium.core.common.listeners; +import static java.lang.String.format; + import com.beust.jcommander.ParameterException; import com.frameworkium.core.common.properties.Property; -import com.frameworkium.core.common.reporting.jira.dto.cycle.*; +import com.frameworkium.core.common.reporting.jira.dto.cycle.CreateNewCycleDto; +import com.frameworkium.core.common.reporting.jira.dto.cycle.CycleDto; +import com.frameworkium.core.common.reporting.jira.dto.cycle.CycleLightDto; import com.frameworkium.core.common.reporting.jira.dto.execution.AddTestToCycleOperationDto; import com.frameworkium.core.common.reporting.jira.dto.project.ProjectDto; import com.frameworkium.core.common.reporting.jira.dto.version.VersionDto; @@ -11,180 +15,188 @@ import com.frameworkium.core.common.reporting.jira.zapi.Cycle; import com.frameworkium.core.common.reporting.jira.zapi.Execution; import io.qameta.allure.TmsLink; +import java.util.Arrays; +import java.util.List; +import java.util.Map.Entry; +import java.util.Objects; +import java.util.Optional; +import java.util.function.Predicate; +import java.util.stream.Collectors; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.openqa.selenium.NotFoundException; -import org.testng.*; +import org.testng.ISuite; +import org.testng.ISuiteListener; +import org.testng.ITestNGMethod; import org.testng.internal.ConstructorOrMethod; -import java.util.*; -import java.util.Map.Entry; -import java.util.function.Predicate; -import java.util.stream.Collectors; - -import static java.lang.String.format; - public class CreateJiraCycleListener implements ISuiteListener { - private final Logger logger = LogManager.getLogger(CreateJiraCycleListener.class); - private final Project project = new Project(); - private final Version version = new Version(); - private final Cycle cycle = new Cycle(); - private final Execution execution = new Execution(); - - - @Override - public void onStart(ISuite suite) { - if (!hasResultVersionSpecified() || !hasZapiRegexCycleSpecified()) { - logger.info("ResultVersion and/or ZapiCycleRegex was not set. " - + "Skipping automated creation of JIRA version and Zephyr cycle as it is not needed..."); - return; - } - final String targetProjectKey = getProjectKey(suite); - final List jiraTestLinksInSuite = getAllTestLinksInSuite(suite); - final ProjectDto targetProjectDto = project.getProject(targetProjectKey); - createExecutionCyclesInJiraIfNeeded(targetProjectDto, jiraTestLinksInSuite); - } - - @Override - public void onFinish(ISuite suite) { - logger.debug("CreateJiraCycleListener finish. Nothing left to do"); - } - - private boolean hasResultVersionSpecified() { - return Property.JIRA_URL.isSpecified() - && Property.RESULT_VERSION.isSpecified(); - } - - private boolean hasZapiRegexCycleSpecified() { - return Property.JIRA_URL.isSpecified() - && Property.ZAPI_CYCLE_REGEX.isSpecified(); - } - - private String getProjectKey(ISuite suite) { - final String targetProjectKey = suite.getParameter("project-key"); - if (targetProjectKey == null) { - throw new ParameterException("Missing JIRA project-key for CreateJiraCycleListener. " - + "Try setting project-key parameter in your testng.xml file e.g.\n" - + "https://testng.org/doc/documentation-main.html#testng-listeners\n" - + "\n" - + " \n" - + " \n" - + " " - + "\n"); - } - logger.info(() -> format("Targeting JIRA project with key: %s", targetProjectKey)); - return targetProjectKey; - } - - private List getAllTestLinksInSuite(ISuite suite) { - return suite.getAllMethods().stream() - .map(ITestNGMethod::getConstructorOrMethod) - .map(ConstructorOrMethod::getMethod) - .flatMap(method -> Arrays.stream(method.getAnnotationsByType(TmsLink.class))) - .filter(Objects::nonNull) - .map(TmsLink::value) - .distinct() - .collect(Collectors.toList()); + private final Logger logger = LogManager.getLogger(CreateJiraCycleListener.class); + private final Project project = new Project(); + private final Version version = new Version(); + private final Cycle cycle = new Cycle(); + private final Execution execution = new Execution(); + + + @Override + public void onStart(ISuite suite) { + if (!hasResultVersionSpecified() || !hasZapiRegexCycleSpecified()) { + logger.info("ResultVersion and/or ZapiCycleRegex was not set. " + + "Skipping automated creation of JIRA version and Zephyr cycle as it is not needed..."); + return; } - - private void createExecutionCyclesInJiraIfNeeded(ProjectDto targetProjectDto, List testLinks) { - final VersionDto targetVersionDto = createResultVersionIfNoneExist(targetProjectDto); - final Entry targetCycleEntry = createZapiCycleIfNoneExist(targetProjectDto, targetVersionDto); - createExecutionsIfNoneExist(targetProjectDto, targetVersionDto, targetCycleEntry, testLinks); - } - - private VersionDto createResultVersionIfNoneExist(ProjectDto targetProject) { - final List projectVersions = project.getProjectVersions(targetProject.key); - - final Optional targetVersion = projectVersions.stream() - .filter(versionDto -> versionDto.name.equals(Property.RESULT_VERSION.getValue())) - .findFirst(); - targetVersion.ifPresent(foundVersion -> - logger.info(() -> format("Found in Zephyr; [ resultVersion: %s ] with [ resultVersionId: %s ]", - Property.RESULT_VERSION.getValue(), foundVersion.id))); - return targetVersion.orElseGet(() -> { - final VersionDto createdVersion = version - .createVersion(VersionDto.newBuilder() - .projectId(targetProject.id) - .name(Property.RESULT_VERSION.getValue()) - .build()); - logger.info(() -> format("Created in Zephyr; [ resultVersion: %s ] with [ resultVersionId: %s ]", - Property.RESULT_VERSION.getValue(), createdVersion.id)); - return createdVersion; - }); + final String targetProjectKey = getProjectKey(suite); + final List jiraTestLinksInSuite = getAllTestLinksInSuite(suite); + final ProjectDto targetProjectDto = project.getProject(targetProjectKey); + createExecutionCyclesInJiraIfNeeded(targetProjectDto, jiraTestLinksInSuite); + } + + @Override + public void onFinish(ISuite suite) { + logger.debug("CreateJiraCycleListener finish. Nothing left to do"); + } + + private boolean hasResultVersionSpecified() { + return Property.JIRA_URL.isSpecified() + && Property.RESULT_VERSION.isSpecified(); + } + + private boolean hasZapiRegexCycleSpecified() { + return Property.JIRA_URL.isSpecified() + && Property.ZAPI_CYCLE_REGEX.isSpecified(); + } + + private String getProjectKey(ISuite suite) { + final String targetProjectKey = suite.getParameter("project-key"); + if (targetProjectKey == null) { + throw new ParameterException("Missing JIRA project-key for CreateJiraCycleListener. " + + "Try setting project-key parameter in your testng.xml file e.g.\n" + + "https://testng.org/doc/documentation-main.html#testng-listeners\n" + + "\n" + + " \n" + + " \n" + + " " + + "\n"); } - - private Entry createZapiCycleIfNoneExist( - ProjectDto targetProjectDto, VersionDto targetVersionDto) { - - final Optional> targetCycleEntry = - getListOfCycles(targetProjectDto.id, targetVersionDto.id); - targetCycleEntry.ifPresent(cycleDtoEntry -> - logger.info(() -> format("Found in Zephyr; [ cycle: %s ] with [ cycleId: %s ]", - Property.ZAPI_CYCLE_REGEX.getValue(), cycleDtoEntry.getKey()))); - return targetCycleEntry.orElseGet(() -> { - final String createdCycleId = cycle.createNewCycle( - CreateNewCycleDto.newBuilder().cycleLightDto( - CycleLightDto.newBuilder() - .versionId(targetVersionDto.id) - .projectId(targetProjectDto.id) - .name(Property.ZAPI_CYCLE_REGEX.getValue()) - .build()) - .build()).id; - logger.info(() -> format("Created in Zephyr; [ cycle: %s ] with [ cycleId: %s ]", - Property.ZAPI_CYCLE_REGEX.getValue(), createdCycleId)); - - return getListOfCycles(targetProjectDto.id, targetVersionDto.id) - .orElseThrow(() -> new NotFoundException(format("Unable to find in JIRA newly created" - + " [ cycle: %s ] with [ cycleId: %s ]. Cycle creation may have failed", - Property.ZAPI_CYCLE_REGEX.getValue(), createdCycleId))); - }); + logger.info(() -> format("Targeting JIRA project with key: %s", targetProjectKey)); + return targetProjectKey; + } + + private List getAllTestLinksInSuite(ISuite suite) { + return suite.getAllMethods().stream() + .map(ITestNGMethod::getConstructorOrMethod) + .map(ConstructorOrMethod::getMethod) + .flatMap(method -> Arrays.stream(method.getAnnotationsByType(TmsLink.class))) + .filter(Objects::nonNull) + .map(TmsLink::value) + .distinct() + .collect(Collectors.toList()); + } + + private void createExecutionCyclesInJiraIfNeeded(ProjectDto targetProjectDto, + List testLinks) { + final VersionDto targetVersionDto = createResultVersionIfNoneExist(targetProjectDto); + final Entry targetCycleEntry = + createZapiCycleIfNoneExist(targetProjectDto, targetVersionDto); + createExecutionsIfNoneExist(targetProjectDto, targetVersionDto, targetCycleEntry, testLinks); + } + + private VersionDto createResultVersionIfNoneExist(ProjectDto targetProject) { + final List projectVersions = project.getProjectVersions(targetProject.key); + + final Optional targetVersion = projectVersions.stream() + .filter(versionDto -> versionDto.name.equals(Property.RESULT_VERSION.getValue())) + .findFirst(); + targetVersion.ifPresent(foundVersion -> + logger.info( + () -> format("Found in Zephyr; [ resultVersion: %s ] with [ resultVersionId: %s ]", + Property.RESULT_VERSION.getValue(), foundVersion.id))); + return targetVersion.orElseGet(() -> { + final VersionDto createdVersion = version + .createVersion(VersionDto.newBuilder() + .projectId(targetProject.id) + .name(Property.RESULT_VERSION.getValue()) + .build()); + logger.info( + () -> format("Created in Zephyr; [ resultVersion: %s ] with [ resultVersionId: %s ]", + Property.RESULT_VERSION.getValue(), createdVersion.id)); + return createdVersion; + }); + } + + private Entry createZapiCycleIfNoneExist( + ProjectDto targetProjectDto, VersionDto targetVersionDto) { + + final Optional> targetCycleEntry = + getListOfCycles(targetProjectDto.id, targetVersionDto.id); + targetCycleEntry.ifPresent(cycleDtoEntry -> + logger.info(() -> format("Found in Zephyr; [ cycle: %s ] with [ cycleId: %s ]", + Property.ZAPI_CYCLE_REGEX.getValue(), cycleDtoEntry.getKey()))); + return targetCycleEntry.orElseGet(() -> { + final String createdCycleId = cycle.createNewCycle( + CreateNewCycleDto.newBuilder().cycleLightDto( + CycleLightDto.newBuilder() + .versionId(targetVersionDto.id) + .projectId(targetProjectDto.id) + .name(Property.ZAPI_CYCLE_REGEX.getValue()) + .build()) + .build()).id; + logger.info(() -> format("Created in Zephyr; [ cycle: %s ] with [ cycleId: %s ]", + Property.ZAPI_CYCLE_REGEX.getValue(), createdCycleId)); + + return getListOfCycles(targetProjectDto.id, targetVersionDto.id) + .orElseThrow(() -> new NotFoundException(format("Unable to find in JIRA newly created" + + " [ cycle: %s ] with [ cycleId: %s ]. Cycle creation may have failed", + Property.ZAPI_CYCLE_REGEX.getValue(), createdCycleId))); + }); + } + + private Optional> getListOfCycles( + Long targetProjectId, Long targetVersionId) { + Predicate> hasTargetVersion = stringCycleInformationDtoEntry + -> stringCycleInformationDtoEntry.getValue().versionName + .equals(Property.RESULT_VERSION.getValue()); + Predicate> hasTargetCycle = stringCycleInformationDtoEntry + -> stringCycleInformationDtoEntry.getValue() + .cycleLightDto.name.equals(Property.ZAPI_CYCLE_REGEX.getValue()); + return cycle + .getListOfCycle(targetProjectId, targetVersionId).map.entrySet().stream() + .filter(hasTargetVersion) + .filter(hasTargetCycle) + .findFirst(); + } + + private void createExecutionsIfNoneExist( + ProjectDto targetProjectDto, VersionDto targetVersionDto, + Entry targetCycleEntry, List testLinks) { + Long totalCycleExecutions = targetCycleEntry.getValue().totalCycleExecutions; + + logger.info(() -> format("Preexisting executions (%d total) found under " + + "[ version: %s, cycle: %s ]. Opting to NOT add further executions.", + totalCycleExecutions, + targetVersionDto.name, + targetCycleEntry.getValue().cycleLightDto.name)); + if (totalCycleExecutions != 0) { + return; } - private Optional> getListOfCycles( - Long targetProjectId, Long targetVersionId) { - Predicate> hasTargetVersion = stringCycleInformationDtoEntry - -> stringCycleInformationDtoEntry.getValue().versionName.equals(Property.RESULT_VERSION.getValue()); - Predicate> hasTargetCycle = stringCycleInformationDtoEntry - -> stringCycleInformationDtoEntry.getValue() - .cycleLightDto.name.equals(Property.ZAPI_CYCLE_REGEX.getValue()); - return cycle - .getListOfCycle(targetProjectId, targetVersionId).map.entrySet().stream() - .filter(hasTargetVersion) - .filter(hasTargetCycle) - .findFirst(); - } - - private void createExecutionsIfNoneExist( - ProjectDto targetProjectDto, VersionDto targetVersionDto, - Entry targetCycleEntry, List testLinks) { - Long totalCycleExecutions = targetCycleEntry.getValue().totalCycleExecutions; - - logger.info(() -> format("Preexisting executions (%d total) found under " - + "[ version: %s, cycle: %s ]. Opting to NOT add further executions.", - totalCycleExecutions, - targetVersionDto.name, - targetCycleEntry.getValue().cycleLightDto.name)); - if (totalCycleExecutions != 0) { - return; - } - - execution.addTestsToCycle( - AddTestToCycleOperationDto.newBuilder() - .cycleId(targetCycleEntry.getKey()) - .projectId(targetProjectDto.id) - .versionId(targetVersionDto.id) - .issues(testLinks) - .method("1") - .build()); - - logger.info(() -> format("Added execution run in JIRA under [ version: %s, cycleName: %s, cycleId: %s ].\n" - + " List of tests added into execution: \n" - + " %s", - targetVersionDto.name, - targetCycleEntry.getValue().cycleLightDto.name, - targetCycleEntry.getKey(), - testLinks)); - } + execution.addTestsToCycle( + AddTestToCycleOperationDto.newBuilder() + .cycleId(targetCycleEntry.getKey()) + .projectId(targetProjectDto.id) + .versionId(targetVersionDto.id) + .issues(testLinks) + .method("1") + .build()); + + logger.info(() -> format( + "Added execution run in JIRA under [ version: %s, cycleName: %s, cycleId: %s ].\n" + + " List of tests added into execution: \n" + + " %s", + targetVersionDto.name, + targetCycleEntry.getValue().cycleLightDto.name, + targetCycleEntry.getKey(), + testLinks)); + } } diff --git a/src/main/java/com/frameworkium/core/common/listeners/MethodInterceptor.java b/src/main/java/com/frameworkium/core/common/listeners/MethodInterceptor.java index 6dfc5712..a9841644 100644 --- a/src/main/java/com/frameworkium/core/common/listeners/MethodInterceptor.java +++ b/src/main/java/com/frameworkium/core/common/listeners/MethodInterceptor.java @@ -1,65 +1,66 @@ package com.frameworkium.core.common.listeners; -import com.frameworkium.core.common.reporting.TestIdUtils; -import com.frameworkium.core.common.reporting.jira.service.Search; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.testng.*; - -import java.lang.reflect.Method; -import java.util.List; - import static com.frameworkium.core.common.properties.Property.JIRA_URL; import static com.frameworkium.core.common.properties.Property.JQL_QUERY; import static java.util.stream.Collectors.joining; import static java.util.stream.Collectors.toList; +import com.frameworkium.core.common.reporting.TestIdUtils; +import com.frameworkium.core.common.reporting.jira.service.Search; +import java.lang.reflect.Method; +import java.util.List; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.testng.IMethodInstance; +import org.testng.IMethodInterceptor; +import org.testng.ITestContext; + public class MethodInterceptor implements IMethodInterceptor { - private static final Logger logger = LogManager.getLogger(); + private static final Logger logger = LogManager.getLogger(); - @Override - public List intercept( - List methods, ITestContext context) { + @Override + public List intercept( + List methods, ITestContext context) { - return filterTestsToRunByJQL(methods); - } + return filterTestsToRunByJQL(methods); + } - private List filterTestsToRunByJQL( - List methodsToBeFiltered) { + private List filterTestsToRunByJQL( + List methodsToBeFiltered) { - if (!(JQL_QUERY.isSpecified() && JIRA_URL.isSpecified())) { - // Can't run the JQL without both JIRA_URL and JQL_QUERY - return methodsToBeFiltered; - } + if (!(JQL_QUERY.isSpecified() && JIRA_URL.isSpecified())) { + // Can't run the JQL without both JIRA_URL and JQL_QUERY + return methodsToBeFiltered; + } - logger.info("Filtering specified tests to run with JQL query results"); + logger.info("Filtering specified tests to run with JQL query results"); - List testIDsFromJQL = - new Search(JQL_QUERY.getValue()).getKeys(); + List testIDsFromJQL = + new Search(JQL_QUERY.getValue()).getKeys(); - List methodsToRun = methodsToBeFiltered.stream() - .filter(m -> TestIdUtils.getIssueOrTmsLinkValue(m).isPresent()) - .filter(m -> testIDsFromJQL.contains( - TestIdUtils.getIssueOrTmsLinkValue(m).orElseThrow(IllegalStateException::new))) - .collect(toList()); + List methodsToRun = methodsToBeFiltered.stream() + .filter(m -> TestIdUtils.getIssueOrTmsLinkValue(m).isPresent()) + .filter(m -> testIDsFromJQL.contains( + TestIdUtils.getIssueOrTmsLinkValue(m).orElseThrow(IllegalStateException::new))) + .collect(toList()); - logTestMethodInformation(methodsToRun); + logTestMethodInformation(methodsToRun); - return methodsToRun; - } + return methodsToRun; + } - private void logTestMethodInformation(List methodsToRun) { + private void logTestMethodInformation(List methodsToRun) { - logger.debug("Running the following test methods:\n{}", () -> - methodsToRun.stream() - .map(m -> getMethodFromIMethod(m).getName()) - .collect(joining("\n"))); + logger.debug("Running the following test methods:\n{}", () -> + methodsToRun.stream() + .map(m -> getMethodFromIMethod(m).getName()) + .collect(joining("\n"))); - logger.info("Running {} tests specified by JQL query", methodsToRun.size()); - } + logger.info("Running {} tests specified by JQL query", methodsToRun.size()); + } - private Method getMethodFromIMethod(IMethodInstance iMethod) { - return iMethod.getMethod().getConstructorOrMethod().getMethod(); - } + private Method getMethodFromIMethod(IMethodInstance iMethod) { + return iMethod.getMethod().getConstructorOrMethod().getMethod(); + } } diff --git a/src/main/java/com/frameworkium/core/common/listeners/ResultLoggerListener.java b/src/main/java/com/frameworkium/core/common/listeners/ResultLoggerListener.java index 031a6379..b70e0eb7 100644 --- a/src/main/java/com/frameworkium/core/common/listeners/ResultLoggerListener.java +++ b/src/main/java/com/frameworkium/core/common/listeners/ResultLoggerListener.java @@ -1,5 +1,10 @@ package com.frameworkium.core.common.listeners; +import static com.frameworkium.core.common.properties.Property.CAPTURE_URL; +import static java.text.MessageFormat.format; +import static java.util.Objects.isNull; +import static org.apache.commons.lang3.time.DateUtils.MILLIS_PER_SECOND; + import com.frameworkium.core.common.properties.Property; import com.frameworkium.core.common.reporting.TestIdUtils; import com.frameworkium.core.common.reporting.jira.JiraConfig; @@ -9,288 +14,287 @@ import com.frameworkium.core.ui.UITestLifecycle; import com.frameworkium.core.ui.capture.ScreenshotCapture; import com.google.common.base.Throwables; +import java.lang.reflect.Method; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.testng.*; +import org.testng.ITestContext; +import org.testng.ITestListener; +import org.testng.ITestResult; -import java.lang.reflect.Method; +public class ResultLoggerListener implements ITestListener { -import static com.frameworkium.core.common.properties.Property.CAPTURE_URL; -import static java.text.MessageFormat.format; -import static java.util.Objects.isNull; -import static org.apache.commons.lang3.time.DateUtils.MILLIS_PER_SECOND; + private final Logger logger = LogManager.getLogger(); -public class ResultLoggerListener implements ITestListener { + @Override + public void onTestStart(ITestResult result) { - private final Logger logger = LogManager.getLogger(); - - @Override - public void onTestStart(ITestResult result) { - - String issueOrTestCaseId = getIssueOrTestCaseIdAnnotation(result); - if (issueOrTestCaseId.isEmpty()) { - return; - } - Issue issue = new Issue(issueOrTestCaseId); - - String comment = String.format( - "Starting %s.%s", - result.getTestClass().getName(), - result.getMethod().getMethodName()); - - if (zapiLoggingParamsProvided(result)) { - logger.info("Logging WIP to zapi"); - new ExecutionUtil(issueOrTestCaseId) - .update(JiraConfig.ZapiStatus.ZAPI_STATUS_WIP, comment); - } - if (jiraTransitionLoggingParamsProvided(result)) { - logger.info("Logging WIP to Jira using issue transitions"); - moveThroughTransitions(issueOrTestCaseId, - JiraConfig.JiraTransition.JIRA_TRANSITION_WIP); - issue.addComment(comment); - } - if (jiraFieldLoggingParamsProvided(result)) { - logger.info(() -> - format("Logging WIP to Jira by updating the specified field - {0}", - Property.JIRA_RESULT_FIELD_NAME.getValue())); - issue.editField( - Property.JIRA_RESULT_FIELD_NAME.getValue(), - JiraConfig.JiraFieldStatus.JIRA_STATUS_WIP - ); - issue.addComment(comment); - } + String issueOrTestCaseId = getIssueOrTestCaseIdAnnotation(result); + if (issueOrTestCaseId.isEmpty()) { + return; } + Issue issue = new Issue(issueOrTestCaseId); - private void moveThroughTransitions(String issueAnnotation, String[] jiraTransitions) { - Issue issue = new Issue(issueAnnotation); - for (String jiraTransition : jiraTransitions) { - try { - issue.transition(jiraTransition); - logger.debug( - "Performed transition '{}' on '{}'", - jiraTransition, - issueAnnotation); - } catch (Exception e) { - logger.error( - "Failed to perform transition '{}' on '{}' - maybe not possible given the state?", - jiraTransition, - issueAnnotation); - } - } - } + String comment = String.format( + "Starting %s.%s", + result.getTestClass().getName(), + result.getMethod().getMethodName()); - @Override - public void onTestSuccess(ITestResult result) { - - String issueOrTestCaseId = getIssueOrTestCaseIdAnnotation(result); - if (issueOrTestCaseId.isEmpty()) { - return; - } - Issue issue = new Issue(issueOrTestCaseId); - - String comment = "PASS\n" + baseComment(result); - - if (zapiLoggingParamsProvided(result)) { - logger.info("Logging PASS to zapi"); - new ExecutionUtil(issueOrTestCaseId) - .update(JiraConfig.ZapiStatus.ZAPI_STATUS_PASS, comment); - } - if (jiraTransitionLoggingParamsProvided(result)) { - logger.info("Logging PASS to Jira using issue transitions"); - moveThroughTransitions(issueOrTestCaseId, - JiraConfig.JiraTransition.JIRA_TRANSITION_PASS); - issue.addComment(comment); - } - if (jiraFieldLoggingParamsProvided(result)) { - logger.info(() -> - format("Logging PASS to Jira by updating the specified field - {0}", - Property.JIRA_RESULT_FIELD_NAME.getValue())); - issue.editField( - Property.JIRA_RESULT_FIELD_NAME.getValue(), - JiraConfig.JiraFieldStatus.JIRA_STATUS_PASS); - issue.addComment(comment); - } - if (spiraLoggingParamsProvided(result)) { - new SpiraExecution().recordTestResult( - issueOrTestCaseId, - JiraConfig.SpiraStatus.SPIRA_STATUS_PASS, - comment, - result); - } + if (zapiLoggingParamsProvided(result)) { + logger.info("Logging WIP to zapi"); + new ExecutionUtil(issueOrTestCaseId) + .update(JiraConfig.ZapiStatus.ZAPI_STATUS_WIP, comment); } + if (jiraTransitionLoggingParamsProvided(result)) { + logger.info("Logging WIP to Jira using issue transitions"); + moveThroughTransitions(issueOrTestCaseId, + JiraConfig.JiraTransition.JIRA_TRANSITION_WIP); + issue.addComment(comment); + } + if (jiraFieldLoggingParamsProvided(result)) { + logger.info(() -> + format("Logging WIP to Jira by updating the specified field - {0}", + Property.JIRA_RESULT_FIELD_NAME.getValue())); + issue.editField( + Property.JIRA_RESULT_FIELD_NAME.getValue(), + JiraConfig.JiraFieldStatus.JIRA_STATUS_WIP + ); + issue.addComment(comment); + } + } + + private void moveThroughTransitions(String issueAnnotation, String[] jiraTransitions) { + Issue issue = new Issue(issueAnnotation); + for (String jiraTransition : jiraTransitions) { + try { + issue.transition(jiraTransition); + logger.debug( + "Performed transition '{}' on '{}'", + jiraTransition, + issueAnnotation); + } catch (Exception e) { + logger.error( + "Failed to perform transition '{}' on '{}' - maybe not possible given the state?", + jiraTransition, + issueAnnotation); + } + } + } - @Override - public void onTestFailure(ITestResult result) { + @Override + public void onTestSuccess(ITestResult result) { - if (result.getThrowable() instanceof AssertionError) { - markAsFailed(result); - } else { - markAsBlocked(result); - } + String issueOrTestCaseId = getIssueOrTestCaseIdAnnotation(result); + if (issueOrTestCaseId.isEmpty()) { + return; } + Issue issue = new Issue(issueOrTestCaseId); - private void markAsFailed(ITestResult result) { - - String issueOrTestCaseId = getIssueOrTestCaseIdAnnotation(result); - if (issueOrTestCaseId.isEmpty()) { - return; - } - Issue issue = new Issue(issueOrTestCaseId); - - String comment = "FAIL\n" + this.baseComment(result); - - if (zapiLoggingParamsProvided(result)) { - logger.info("Logging FAIL to zapi"); - new ExecutionUtil(issueOrTestCaseId) - .update(JiraConfig.ZapiStatus.ZAPI_STATUS_FAIL, comment); - } - if (jiraTransitionLoggingParamsProvided(result)) { - logger.info("Logging FAIL to Jira using issue transitions"); - moveThroughTransitions(issueOrTestCaseId, - JiraConfig.JiraTransition.JIRA_TRANSITION_FAIL); - issue.addComment(comment); - } - if (jiraFieldLoggingParamsProvided(result)) { - logger.info(() -> format("Logging FAIL to Jira by updating the specified field - {0}", - Property.JIRA_RESULT_FIELD_NAME.getValue())); - issue.editField( - Property.JIRA_RESULT_FIELD_NAME.getValue(), - JiraConfig.JiraFieldStatus.JIRA_STATUS_FAIL); - issue.addComment(comment); - } - if (spiraLoggingParamsProvided(result)) { - new SpiraExecution().recordTestResult( - issueOrTestCaseId, - JiraConfig.SpiraStatus.SPIRA_STATUS_FAIL, - comment, - result); - } - } + String comment = "PASS\n" + baseComment(result); - @Override - public void onTestSkipped(ITestResult result) { - markAsBlocked(result); + if (zapiLoggingParamsProvided(result)) { + logger.info("Logging PASS to zapi"); + new ExecutionUtil(issueOrTestCaseId) + .update(JiraConfig.ZapiStatus.ZAPI_STATUS_PASS, comment); } - - private void markAsBlocked(ITestResult result) { - - String issueOrTestCaseId = getIssueOrTestCaseIdAnnotation(result); - if (issueOrTestCaseId.isEmpty()) { - return; - } - Issue issue = new Issue(issueOrTestCaseId); - - String comment = "BLOCKED\n" + this.baseComment(result); - - if (zapiLoggingParamsProvided(result)) { - logger.info("Logging BLOCKED to zapi"); - new ExecutionUtil(issueOrTestCaseId) - .update(JiraConfig.ZapiStatus.ZAPI_STATUS_BLOCKED, comment); - } - if (jiraTransitionLoggingParamsProvided(result)) { - logger.info("Logging BLOCKED to Jira using issue transitions"); - moveThroughTransitions(issueOrTestCaseId, - JiraConfig.JiraTransition.JIRA_TRANSITION_BLOCKED); - issue.addComment(comment); - } - if (jiraFieldLoggingParamsProvided(result)) { - logger.info(() -> format("Logging BLOCKED to Jira by updating the specified field - {0}", - Property.JIRA_RESULT_FIELD_NAME.getValue())); - issue.editField( - Property.JIRA_RESULT_FIELD_NAME.getValue(), - JiraConfig.JiraFieldStatus.JIRA_STATUS_BLOCKED); - issue.addComment(comment); - } - if (spiraLoggingParamsProvided(result)) { - new SpiraExecution().recordTestResult( - issueOrTestCaseId, - JiraConfig.SpiraStatus.SPIRA_STATUS_BLOCKED, - comment, - result); - } + if (jiraTransitionLoggingParamsProvided(result)) { + logger.info("Logging PASS to Jira using issue transitions"); + moveThroughTransitions(issueOrTestCaseId, + JiraConfig.JiraTransition.JIRA_TRANSITION_PASS); + issue.addComment(comment); + } + if (jiraFieldLoggingParamsProvided(result)) { + logger.info(() -> + format("Logging PASS to Jira by updating the specified field - {0}", + Property.JIRA_RESULT_FIELD_NAME.getValue())); + issue.editField( + Property.JIRA_RESULT_FIELD_NAME.getValue(), + JiraConfig.JiraFieldStatus.JIRA_STATUS_PASS); + issue.addComment(comment); + } + if (spiraLoggingParamsProvided(result)) { + new SpiraExecution().recordTestResult( + issueOrTestCaseId, + JiraConfig.SpiraStatus.SPIRA_STATUS_PASS, + comment, + result); } + } - @Override - public void onTestFailedButWithinSuccessPercentage(ITestResult result) {} + @Override + public void onTestFailure(ITestResult result) { - @Override - public void onStart(ITestContext context) {} + if (result.getThrowable() instanceof AssertionError) { + markAsFailed(result); + } else { + markAsBlocked(result); + } + } - @Override - public void onFinish(ITestContext context) {} + private void markAsFailed(ITestResult result) { - private boolean zapiLoggingParamsProvided(ITestResult result) { - return Property.JIRA_URL.isSpecified() - && Property.RESULT_VERSION.isSpecified() - && !getIssueOrTestCaseIdAnnotation(result).isEmpty(); + String issueOrTestCaseId = getIssueOrTestCaseIdAnnotation(result); + if (issueOrTestCaseId.isEmpty()) { + return; } + Issue issue = new Issue(issueOrTestCaseId); - private boolean jiraTransitionLoggingParamsProvided(ITestResult result) { - return Property.JIRA_URL.isSpecified() - && Property.JIRA_RESULT_TRANSITION.isSpecified() - && !getIssueOrTestCaseIdAnnotation(result).isEmpty(); - } + String comment = "FAIL\n" + this.baseComment(result); - private boolean jiraFieldLoggingParamsProvided(ITestResult result) { - return Property.JIRA_URL.isSpecified() - && Property.JIRA_RESULT_FIELD_NAME.isSpecified() - && !getIssueOrTestCaseIdAnnotation(result).isEmpty(); + if (zapiLoggingParamsProvided(result)) { + logger.info("Logging FAIL to zapi"); + new ExecutionUtil(issueOrTestCaseId) + .update(JiraConfig.ZapiStatus.ZAPI_STATUS_FAIL, comment); } - - private boolean spiraLoggingParamsProvided(ITestResult result) { - return Property.SPIRA_URL.isSpecified() - && !getIssueOrTestCaseIdAnnotation(result).isEmpty(); + if (jiraTransitionLoggingParamsProvided(result)) { + logger.info("Logging FAIL to Jira using issue transitions"); + moveThroughTransitions(issueOrTestCaseId, + JiraConfig.JiraTransition.JIRA_TRANSITION_FAIL); + issue.addComment(comment); } - - /** - * If neither are specified then the empty string will be returned. - * {@see TestIdUtils#getIssueOrTestCaseIdValue(Method)} - * - * @return the value of either the @Issue or @TestCaseId annotation for the provided test result. - */ - private String getIssueOrTestCaseIdAnnotation(ITestResult result) { - Method method = result.getMethod().getConstructorOrMethod().getMethod(); - return TestIdUtils.getIssueOrTmsLinkValue(method).orElse(""); + if (jiraFieldLoggingParamsProvided(result)) { + logger.info(() -> format("Logging FAIL to Jira by updating the specified field - {0}", + Property.JIRA_RESULT_FIELD_NAME.getValue())); + issue.editField( + Property.JIRA_RESULT_FIELD_NAME.getValue(), + JiraConfig.JiraFieldStatus.JIRA_STATUS_FAIL); + issue.addComment(comment); } + if (spiraLoggingParamsProvided(result)) { + new SpiraExecution().recordTestResult( + issueOrTestCaseId, + JiraConfig.SpiraStatus.SPIRA_STATUS_FAIL, + comment, + result); + } + } + + @Override + public void onTestSkipped(ITestResult result) { + markAsBlocked(result); + } - private String getOSInfo() { - return String.format( - "%s - %s (%s)", - System.getProperty("os.name"), - System.getProperty("os.version"), - System.getProperty("os.arch")); + private void markAsBlocked(ITestResult result) { + + String issueOrTestCaseId = getIssueOrTestCaseIdAnnotation(result); + if (issueOrTestCaseId.isEmpty()) { + return; } + Issue issue = new Issue(issueOrTestCaseId); + + String comment = "BLOCKED\n" + this.baseComment(result); - private String baseComment(ITestResult result) { - - StringBuilder commentBuilder = new StringBuilder(); - - commentBuilder.append("Test: ") - .append(result.getTestClass().getName()) - .append(".") - .append(result.getMethod().getMethodName()) - .append("\nDuration: ") - .append(((result.getEndMillis() - result.getStartMillis()) / MILLIS_PER_SECOND)) - .append("seconds"); - - if (!isNull(System.getenv("BUILD_URL"))) { - commentBuilder.append("Jenkins build: ") - .append(System.getenv("BUILD_URL")); - } - if (ScreenshotCapture.isRequired()) { - commentBuilder.append("Capture API: ") - .append(CAPTURE_URL.getValue()); - } - commentBuilder.append("\nOS: ") - .append(getOSInfo()) - .append("\nUserAgent: ") - .append(UITestLifecycle.get().getUserAgent()); - - if (!isNull(result.getThrowable())) { - commentBuilder.append("\nStacktrace: ") - .append(Throwables.getStackTraceAsString(result.getThrowable())); - } - - return commentBuilder.toString(); + if (zapiLoggingParamsProvided(result)) { + logger.info("Logging BLOCKED to zapi"); + new ExecutionUtil(issueOrTestCaseId) + .update(JiraConfig.ZapiStatus.ZAPI_STATUS_BLOCKED, comment); + } + if (jiraTransitionLoggingParamsProvided(result)) { + logger.info("Logging BLOCKED to Jira using issue transitions"); + moveThroughTransitions(issueOrTestCaseId, + JiraConfig.JiraTransition.JIRA_TRANSITION_BLOCKED); + issue.addComment(comment); + } + if (jiraFieldLoggingParamsProvided(result)) { + logger.info(() -> format("Logging BLOCKED to Jira by updating the specified field - {0}", + Property.JIRA_RESULT_FIELD_NAME.getValue())); + issue.editField( + Property.JIRA_RESULT_FIELD_NAME.getValue(), + JiraConfig.JiraFieldStatus.JIRA_STATUS_BLOCKED); + issue.addComment(comment); + } + if (spiraLoggingParamsProvided(result)) { + new SpiraExecution().recordTestResult( + issueOrTestCaseId, + JiraConfig.SpiraStatus.SPIRA_STATUS_BLOCKED, + comment, + result); } + } + + @Override + public void onTestFailedButWithinSuccessPercentage(ITestResult result) { + } + + @Override + public void onStart(ITestContext context) { + } + + @Override + public void onFinish(ITestContext context) { + } + + private boolean zapiLoggingParamsProvided(ITestResult result) { + return Property.JIRA_URL.isSpecified() + && Property.RESULT_VERSION.isSpecified() + && !getIssueOrTestCaseIdAnnotation(result).isEmpty(); + } + + private boolean jiraTransitionLoggingParamsProvided(ITestResult result) { + return Property.JIRA_URL.isSpecified() + && Property.JIRA_RESULT_TRANSITION.isSpecified() + && !getIssueOrTestCaseIdAnnotation(result).isEmpty(); + } + + private boolean jiraFieldLoggingParamsProvided(ITestResult result) { + return Property.JIRA_URL.isSpecified() + && Property.JIRA_RESULT_FIELD_NAME.isSpecified() + && !getIssueOrTestCaseIdAnnotation(result).isEmpty(); + } + + private boolean spiraLoggingParamsProvided(ITestResult result) { + return Property.SPIRA_URL.isSpecified() + && !getIssueOrTestCaseIdAnnotation(result).isEmpty(); + } + + /** + * If neither are specified then the empty string will be returned. + * {@see TestIdUtils#getIssueOrTestCaseIdValue(Method)} + * + * @return the value of either the @Issue or @TestCaseId annotation for the provided test result. + */ + private String getIssueOrTestCaseIdAnnotation(ITestResult result) { + Method method = result.getMethod().getConstructorOrMethod().getMethod(); + return TestIdUtils.getIssueOrTmsLinkValue(method).orElse(""); + } + + private String getOSInfo() { + return String.format( + "%s - %s (%s)", + System.getProperty("os.name"), + System.getProperty("os.version"), + System.getProperty("os.arch")); + } + + private String baseComment(ITestResult result) { + + StringBuilder commentBuilder = new StringBuilder(); + + commentBuilder.append("Test: ") + .append(result.getTestClass().getName()) + .append(".") + .append(result.getMethod().getMethodName()) + .append("\nDuration: ") + .append(((result.getEndMillis() - result.getStartMillis()) / MILLIS_PER_SECOND)) + .append("seconds"); + + if (!isNull(System.getenv("BUILD_URL"))) { + commentBuilder.append("Jenkins build: ") + .append(System.getenv("BUILD_URL")); + } + if (ScreenshotCapture.isRequired()) { + commentBuilder.append("Capture API: ") + .append(CAPTURE_URL.getValue()); + } + commentBuilder.append("\nOS: ") + .append(getOSInfo()) + .append("\nUserAgent: ") + .append(UITestLifecycle.get().getUserAgent()); + + if (!isNull(result.getThrowable())) { + commentBuilder.append("\nStacktrace: ") + .append(Throwables.getStackTraceAsString(result.getThrowable())); + } + + return commentBuilder.toString(); + } } diff --git a/src/main/java/com/frameworkium/core/common/listeners/TestListener.java b/src/main/java/com/frameworkium/core/common/listeners/TestListener.java index bce320e9..2a7aa00a 100644 --- a/src/main/java/com/frameworkium/core/common/listeners/TestListener.java +++ b/src/main/java/com/frameworkium/core/common/listeners/TestListener.java @@ -2,52 +2,58 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.testng.*; +import org.testng.ITestContext; +import org.testng.ITestListener; +import org.testng.ITestResult; +import org.testng.SkipException; public class TestListener implements ITestListener { - private final Logger logger = LogManager.getLogger(); + private final Logger logger = LogManager.getLogger(); - @Override - public void onTestStart(ITestResult result) { - logger.info("START {}", getTestIdentifier(result)); - } + @Override + public void onTestStart(ITestResult result) { + logger.info("START {}", getTestIdentifier(result)); + } - @Override - public void onTestSuccess(ITestResult result) { - logger.info("PASS {}", getTestIdentifier(result)); - } + @Override + public void onTestSuccess(ITestResult result) { + logger.info("PASS {}", getTestIdentifier(result)); + } - @Override - public void onTestFailure(ITestResult result) { - logger.error("FAIL {}", getTestIdentifier(result)); - Throwable cause = result.getThrowable(); - if (cause != null) { - logger.error(cause.getMessage(), cause); - } + @Override + public void onTestFailure(ITestResult result) { + logger.error("FAIL {}", getTestIdentifier(result)); + Throwable cause = result.getThrowable(); + if (cause != null) { + logger.error(cause.getMessage(), cause); } - - @Override - public void onTestSkipped(ITestResult result) { - logger.warn("SKIP {}", getTestIdentifier(result)); - Throwable cause = result.getThrowable(); - if (cause != null && SkipException.class.isAssignableFrom(cause.getClass())) { - logger.warn(cause.getMessage()); - } + } + + @Override + public void onTestSkipped(ITestResult result) { + logger.warn("SKIP {}", getTestIdentifier(result)); + Throwable cause = result.getThrowable(); + if (cause != null && SkipException.class.isAssignableFrom(cause.getClass())) { + logger.warn(cause.getMessage()); } + } - private String getTestIdentifier(ITestResult result) { - return String.format("%s.%s", - result.getInstanceName(), - result.getMethod().getMethodName()); - } + private String getTestIdentifier(ITestResult result) { + return String.format("%s.%s", + result.getInstanceName(), + result.getMethod().getMethodName()); + } - @Override - public void onTestFailedButWithinSuccessPercentage(ITestResult result) {} + @Override + public void onTestFailedButWithinSuccessPercentage(ITestResult result) { + } - @Override - public void onStart(ITestContext context) {} + @Override + public void onStart(ITestContext context) { + } - @Override - public void onFinish(ITestContext context) {} + @Override + public void onFinish(ITestContext context) { + } } diff --git a/src/main/java/com/frameworkium/core/common/properties/Property.java b/src/main/java/com/frameworkium/core/common/properties/Property.java index 64812a4e..f9852953 100755 --- a/src/main/java/com/frameworkium/core/common/properties/Property.java +++ b/src/main/java/com/frameworkium/core/common/properties/Property.java @@ -1,120 +1,119 @@ package com.frameworkium.core.common.properties; -import org.apache.commons.lang3.StringUtils; - import java.io.IOException; import java.io.InputStream; import java.util.Objects; import java.util.Properties; +import org.apache.commons.lang.StringUtils; public enum Property { - BUILD("build"), - JIRA_URL("jiraURL"), - SPIRA_URL("spiraURL"), - RESULT_VERSION("resultVersion"), - ZAPI_CYCLE_REGEX("zapiCycleRegEx"), - JQL_QUERY("jqlQuery"), - JIRA_USERNAME("jiraUsername"), - JIRA_PASSWORD("jiraPassword"), - SUT_NAME("sutName"), - SUT_VERSION("sutVersion"), - JIRA_RESULT_FIELD_NAME("jiraResultFieldName"), - JIRA_RESULT_TRANSITION("jiraResultTransition"), - PROXY("proxy"), - MAX_RETRY_COUNT("maxRetryCount"), - // UI specific - BROWSER("browser"), - BROWSER_VERSION("browserVersion"), - PLATFORM("platform"), - PLATFORM_VERSION("platformVersion"), - DEVICE("device"), - CAPTURE_URL("captureURL"), - GRID_URL("gridURL"), - APP_PATH("appPath"), - APPLICATION_NAME("applicationName"), - SAUCE("sauce"), - BROWSER_STACK("browserStack"), - MAXIMISE("maximise"), - RESOLUTION("resolution"), - VIDEO_CAPTURE_URL("videoCaptureUrl"), - CUSTOM_BROWSER_IMPL("customBrowserImpl"), - REUSE_BROWSER("reuseBrowser"), - THREADS("threads"), - HEADLESS("headless"); - - private static Properties properties = null; - private String value; - private String systemPropertyKey; - - Property(String key) { - this.systemPropertyKey = key; - this.value = retrieveValue(key); + BUILD("build"), + JIRA_URL("jiraURL"), + SPIRA_URL("spiraURL"), + RESULT_VERSION("resultVersion"), + ZAPI_CYCLE_REGEX("zapiCycleRegEx"), + JQL_QUERY("jqlQuery"), + JIRA_USERNAME("jiraUsername"), + JIRA_PASSWORD("jiraPassword"), + SUT_NAME("sutName"), + SUT_VERSION("sutVersion"), + JIRA_RESULT_FIELD_NAME("jiraResultFieldName"), + JIRA_RESULT_TRANSITION("jiraResultTransition"), + PROXY("proxy"), + MAX_RETRY_COUNT("maxRetryCount"), + // UI specific + BROWSER("browser"), + BROWSER_VERSION("browserVersion"), + PLATFORM("platform"), + PLATFORM_VERSION("platformVersion"), + DEVICE("device"), + CAPTURE_URL("captureURL"), + GRID_URL("gridURL"), + APP_PATH("appPath"), + APPLICATION_NAME("applicationName"), + SAUCE("sauce"), + BROWSER_STACK("browserStack"), + MAXIMISE("maximise"), + RESOLUTION("resolution"), + VIDEO_CAPTURE_URL("videoCaptureUrl"), + CUSTOM_BROWSER_IMPL("customBrowserImpl"), + REUSE_BROWSER("reuseBrowser"), + THREADS("threads"), + HEADLESS("headless"); + + private static Properties properties = null; + private String value; + private String systemPropertyKey; + + Property(String key) { + this.systemPropertyKey = key; + this.value = retrieveValue(key); + } + + private static String getValueFromConfigFile(String key) { + if (properties == null) { + properties = loadConfigFile(); } - private String retrieveValue(String key) { - if (System.getProperty(key) != null) { - return System.getProperty(key); - } else { - return getValueFromConfigFile(key); - } - } - - private static String getValueFromConfigFile(String key) { - if (properties == null) { - properties = loadConfigFile(); - } - - Object objFromFile = properties.get(key); - if (objFromFile != null) { - return Objects.toString(objFromFile); - } else { - return null; - } + Object objFromFile = properties.get(key); + if (objFromFile != null) { + return Objects.toString(objFromFile); + } else { + return null; } + } - private static Properties loadConfigFile() { - String configFileName = System.getProperty("config"); - - if (StringUtils.isBlank(configFileName)) { - return new Properties(); - } - - try (InputStream configFileStream = - ClassLoader.getSystemClassLoader() - .getResourceAsStream(configFileName)) { - Properties properties = new Properties(); - properties.load(configFileStream); - return properties; - } catch (IOException e) { - throw new IllegalArgumentException( - "Properties file '" + configFileName + "' not found.", e); - } - } - - /** - * Check if a property is specified. - * - * @return true if the property is not empty ("") and not null - */ - public boolean isSpecified() { - return StringUtils.isNotEmpty(value); - } + private static Properties loadConfigFile() { + String configFileName = System.getProperty("config"); - public String getValue() { - return retrieveValue(this.systemPropertyKey); + if (StringUtils.isBlank(configFileName)) { + return new Properties(); } - /** - * @return true if the property is set and is equal, ignoring case, to "true". - */ - public boolean getBoolean() { - return isSpecified() && Boolean.parseBoolean(value); + try (InputStream configFileStream = + ClassLoader.getSystemClassLoader() + .getResourceAsStream(configFileName)) { + Properties properties = new Properties(); + properties.load(configFileStream); + return properties; + } catch (IOException e) { + throw new IllegalArgumentException( + "Properties file '" + configFileName + "' not found.", e); } + } - public int getIntWithDefault(int defaultValue) { - return isSpecified() - ? Integer.parseInt(value) - : defaultValue; + private String retrieveValue(String key) { + if (System.getProperty(key) != null) { + return System.getProperty(key); + } else { + return getValueFromConfigFile(key); } + } + + /** + * Check if a property is specified. + * + * @return true if the property is not empty ("") and not null + */ + public boolean isSpecified() { + return StringUtils.isNotEmpty(value); + } + + public String getValue() { + return retrieveValue(this.systemPropertyKey); + } + + /** + * @return true if the property is set and is equal, ignoring case, to "true". + */ + public boolean getBoolean() { + return isSpecified() && Boolean.parseBoolean(value); + } + + public int getIntWithDefault(int defaultValue) { + return isSpecified() + ? Integer.parseInt(value) + : defaultValue; + } } diff --git a/src/main/java/com/frameworkium/core/common/reporting/TestIdUtils.java b/src/main/java/com/frameworkium/core/common/reporting/TestIdUtils.java index 7e0a7bc2..381477f1 100644 --- a/src/main/java/com/frameworkium/core/common/reporting/TestIdUtils.java +++ b/src/main/java/com/frameworkium/core/common/reporting/TestIdUtils.java @@ -1,90 +1,91 @@ package com.frameworkium.core.common.reporting; +import static java.util.Objects.nonNull; + import io.qameta.allure.Issue; import io.qameta.allure.TmsLink; -import org.testng.IMethodInstance; - import java.lang.reflect.Method; -import java.util.*; +import java.util.Collections; +import java.util.List; +import java.util.Optional; import java.util.stream.Collectors; import java.util.stream.Stream; - -import static java.util.Objects.nonNull; +import org.testng.IMethodInstance; public class TestIdUtils { - private TestIdUtils() { - // hide default constructor for this util class - } + private TestIdUtils() { + // hide default constructor for this util class + } - /** - * Get TMS Link or Issue ID value. - * - * @param iMethod the {@link IMethodInstance} to check for test ID annotations. - * @return Optional of either the {@link TmsLink} or {@link Issue} value. - * @throws IllegalStateException if {@link TmsLink} and {@link Issue} - * are specified inconstantly. - * @deprecated Use - * {@link TestIdUtils#getIssueOrTmsLinkValues(IMethodInstance)} instead - */ - @Deprecated - public static Optional getIssueOrTmsLinkValue(IMethodInstance iMethod) { - Method method = iMethod.getMethod().getConstructorOrMethod().getMethod(); - return getIssueOrTmsLinkValue(method); - } + /** + * Get TMS Link or Issue ID value. + * + * @param iMethod the {@link IMethodInstance} to check for test ID annotations. + * @return Optional of either the {@link TmsLink} or {@link Issue} value. + * @throws IllegalStateException if {@link TmsLink} and {@link Issue} + * are specified inconstantly. + * @deprecated Use + * {@link TestIdUtils#getIssueOrTmsLinkValues(IMethodInstance)} instead + */ + @Deprecated + public static Optional getIssueOrTmsLinkValue(IMethodInstance iMethod) { + Method method = iMethod.getMethod().getConstructorOrMethod().getMethod(); + return getIssueOrTmsLinkValue(method); + } - /** - * Get {@link TmsLink} or {@link Issue} for a method. - * If both are specified it will return jus the {@link TmsLink} value. - * - * @param method the method to check for test ID annotations. - * @return Optional of the {@link TmsLink} or {@link Issue} value. - * @deprecated Use - * {@link TestIdUtils#getIssueOrTmsLinkValues(Method)} instead. - */ - @Deprecated - public static Optional getIssueOrTmsLinkValue(Method method) { - TmsLink tcIdAnnotation = method.getAnnotation(TmsLink.class); - Issue issueAnnotation = method.getAnnotation(Issue.class); + /** + * Get {@link TmsLink} or {@link Issue} for a method. + * If both are specified it will return jus the {@link TmsLink} value. + * + * @param method the method to check for test ID annotations. + * @return Optional of the {@link TmsLink} or {@link Issue} value. + * @deprecated Use + * {@link TestIdUtils#getIssueOrTmsLinkValues(Method)} instead. + */ + @Deprecated + public static Optional getIssueOrTmsLinkValue(Method method) { + TmsLink tcIdAnnotation = method.getAnnotation(TmsLink.class); + Issue issueAnnotation = method.getAnnotation(Issue.class); - if (nonNull(tcIdAnnotation)) { - return Optional.of(tcIdAnnotation.value()); - } else if (nonNull(issueAnnotation)) { - return Optional.of(issueAnnotation.value()); - } else { - return Optional.empty(); - } + if (nonNull(tcIdAnnotation)) { + return Optional.of(tcIdAnnotation.value()); + } else if (nonNull(issueAnnotation)) { + return Optional.of(issueAnnotation.value()); + } else { + return Optional.empty(); } + } - /** - * Get list of {@link TmsLink} or {@link Issue}. - * - * @param iMethod the {@link IMethodInstance} to check for test ID annotations. - * @return List of either the {@link TmsLink} or {@link Issue} value. - * @throws IllegalStateException if {@link TmsLink} and {@link Issue} - * are specified inconstantly. - */ - public static List getIssueOrTmsLinkValues(IMethodInstance iMethod) { - Method method = iMethod.getMethod().getConstructorOrMethod().getMethod(); - return getIssueOrTmsLinkValues(method); - } + /** + * Get list of {@link TmsLink} or {@link Issue}. + * + * @param iMethod the {@link IMethodInstance} to check for test ID annotations. + * @return List of either the {@link TmsLink} or {@link Issue} value. + * @throws IllegalStateException if {@link TmsLink} and {@link Issue} + * are specified inconstantly. + */ + public static List getIssueOrTmsLinkValues(IMethodInstance iMethod) { + Method method = iMethod.getMethod().getConstructorOrMethod().getMethod(); + return getIssueOrTmsLinkValues(method); + } - /** - * Get a list of {@link TmsLink} or {@link Issue} for a method. - * If both are specified it will return just the list of {@link TmsLink} values. - * - * @param method the method to check for test Id annotations. - * @return List of {@link TmsLink} or {@link Issue} values. - */ - public static List getIssueOrTmsLinkValues(Method method) { - TmsLink[] tcIdAnnotations = method.getAnnotationsByType(TmsLink.class); - Issue[] issueAnnotations = method.getAnnotationsByType(Issue.class); - if (tcIdAnnotations.length > 0) { - return Stream.of(tcIdAnnotations).map(TmsLink::value).collect(Collectors.toList()); - } - if (issueAnnotations.length > 0) { - return Stream.of(issueAnnotations).map(Issue::value).collect(Collectors.toList()); - } - return Collections.emptyList(); + /** + * Get a list of {@link TmsLink} or {@link Issue} for a method. + * If both are specified it will return just the list of {@link TmsLink} values. + * + * @param method the method to check for test Id annotations. + * @return List of {@link TmsLink} or {@link Issue} values. + */ + public static List getIssueOrTmsLinkValues(Method method) { + TmsLink[] tcIdAnnotations = method.getAnnotationsByType(TmsLink.class); + Issue[] issueAnnotations = method.getAnnotationsByType(Issue.class); + if (tcIdAnnotations.length > 0) { + return Stream.of(tcIdAnnotations).map(TmsLink::value).collect(Collectors.toList()); + } + if (issueAnnotations.length > 0) { + return Stream.of(issueAnnotations).map(Issue::value).collect(Collectors.toList()); } + return Collections.emptyList(); + } } diff --git a/src/main/java/com/frameworkium/core/common/reporting/allure/AllureLogger.java b/src/main/java/com/frameworkium/core/common/reporting/allure/AllureLogger.java index f9fea908..8060402d 100644 --- a/src/main/java/com/frameworkium/core/common/reporting/allure/AllureLogger.java +++ b/src/main/java/com/frameworkium/core/common/reporting/allure/AllureLogger.java @@ -1,42 +1,43 @@ package com.frameworkium.core.common.reporting.allure; +import static io.qameta.allure.Allure.getLifecycle; + import io.qameta.allure.Step; import io.qameta.allure.model.StepResult; +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.UUID; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import java.util.*; - -import static io.qameta.allure.Allure.getLifecycle; - public class AllureLogger { - private static final Logger logger = LogManager.getLogger(); - private static final ThreadLocal> STEP_UUID_STACK = - ThreadLocal.withInitial(ArrayDeque::new); - - private AllureLogger() { - // hide default constructor for this util class - } - - /** - * Uses the @Step annotation to log the given log message to Allure. - * - * @param message the message to log to the allure report - */ - @Step("{message}") - public static void logToAllure(String message) { - logger.debug("Logged to allure: " + message); - } - - public static void stepStart(String stepName) { - StepResult result = new StepResult().setName(stepName); - String uuid = UUID.randomUUID().toString(); - getLifecycle().startStep(uuid, result); - STEP_UUID_STACK.get().addFirst(uuid); - } - - public static void stepFinish() { - getLifecycle().stopStep(STEP_UUID_STACK.get().removeFirst()); - } + private static final Logger logger = LogManager.getLogger(); + private static final ThreadLocal> STEP_UUID_STACK = + ThreadLocal.withInitial(ArrayDeque::new); + + private AllureLogger() { + // hide default constructor for this util class + } + + /** + * Uses the @Step annotation to log the given log message to Allure. + * + * @param message the message to log to the allure report + */ + @Step("{message}") + public static void logToAllure(String message) { + logger.debug("Logged to allure: " + message); + } + + public static void stepStart(String stepName) { + StepResult result = new StepResult().setName(stepName); + String uuid = UUID.randomUUID().toString(); + getLifecycle().startStep(uuid, result); + STEP_UUID_STACK.get().addFirst(uuid); + } + + public static void stepFinish() { + getLifecycle().stopStep(STEP_UUID_STACK.get().removeFirst()); + } } diff --git a/src/main/java/com/frameworkium/core/common/reporting/allure/AllureProperties.java b/src/main/java/com/frameworkium/core/common/reporting/allure/AllureProperties.java index 348fb4b0..43196a42 100644 --- a/src/main/java/com/frameworkium/core/common/reporting/allure/AllureProperties.java +++ b/src/main/java/com/frameworkium/core/common/reporting/allure/AllureProperties.java @@ -1,18 +1,17 @@ package com.frameworkium.core.common.reporting.allure; +import static java.util.Objects.nonNull; + import com.frameworkium.core.common.properties.Property; import com.frameworkium.core.ui.UITestLifecycle; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - import java.io.FileOutputStream; import java.io.IOException; import java.util.Arrays; import java.util.Map; import java.util.Properties; import java.util.stream.Collectors; - -import static java.util.Objects.nonNull; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; /** * Creates the Allure environment.properties file based on properties used. @@ -20,82 +19,82 @@ */ public class AllureProperties { - private static final Logger logger = LogManager.getLogger(); - - private AllureProperties() { - // hide default constructor for this util class + private static final Logger logger = LogManager.getLogger(); + + private AllureProperties() { + // hide default constructor for this util class + } + + public static void createUI() { + Properties props = new Properties(); + props.putAll(getAllFrameworkiumProperties()); + props.putAll(getCommonProps()); + props.putAll(getUIProperties()); + save(props); + } + + public static void createAPI() { + Properties props = new Properties(); + props.putAll(getAllFrameworkiumProperties()); + props.putAll(getCommonProps()); + save(props); + } + + private static Properties getAllFrameworkiumProperties() { + Map allProperties = + Arrays.stream(Property.values()) + .filter(Property::isSpecified) + .collect(Collectors.toMap( + Property::toString, + AllureProperties::obfuscatePasswordValue)); + + Properties properties = new Properties(); + properties.putAll(allProperties); + return properties; + } + + private static String obfuscatePasswordValue(Property p) { + String key = p.toString(); + String value = p.getValue(); + if (key.toLowerCase().contains("password")) { + return value.replaceAll(".", "*"); } + return value; + } - public static void createUI() { - Properties props = new Properties(); - props.putAll(getAllFrameworkiumProperties()); - props.putAll(getCommonProps()); - props.putAll(getUIProperties()); - save(props); - } - - public static void createAPI() { - Properties props = new Properties(); - props.putAll(getAllFrameworkiumProperties()); - props.putAll(getCommonProps()); - save(props); - } - - private static Properties getAllFrameworkiumProperties() { - Map allProperties = - Arrays.stream(Property.values()) - .filter(Property::isSpecified) - .collect(Collectors.toMap( - Property::toString, - AllureProperties::obfuscatePasswordValue)); - - Properties properties = new Properties(); - properties.putAll(allProperties); - return properties; - } + private static Properties getCommonProps() { + Properties props = new Properties(); - private static String obfuscatePasswordValue(Property p) { - String key = p.toString(); - String value = p.getValue(); - if (key.toLowerCase().contains("password")) { - return value.replaceAll(".", "*"); - } - return value; + if (nonNull(System.getenv("BUILD_URL"))) { + props.setProperty("CI build URL", System.getenv("BUILD_URL")); } - - private static Properties getCommonProps() { - Properties props = new Properties(); - - if (nonNull(System.getenv("BUILD_URL"))) { - props.setProperty("CI build URL", System.getenv("BUILD_URL")); - } - if (nonNull(System.getProperty("config"))) { - props.setProperty("Config file", System.getProperty("config")); - } - - if (Property.JIRA_URL.isSpecified()) { - final String jiraPattern = Property.JIRA_URL.getValue() + "/browse/%s"; - props.setProperty("allure.issues.tracker.pattern", jiraPattern); - props.setProperty("allure.tests.management.pattern", jiraPattern); - } - - return props; + if (nonNull(System.getProperty("config"))) { + props.setProperty("Config file", System.getProperty("config")); } - private static Properties getUIProperties() { - Properties props = new Properties(); - UITestLifecycle.get().getUserAgent() - .ifPresent(ua -> props.setProperty("UserAgent", ua)); - return props; + if (Property.JIRA_URL.isSpecified()) { + final String jiraPattern = Property.JIRA_URL.getValue() + "/browse/%s"; + props.setProperty("allure.issues.tracker.pattern", jiraPattern); + props.setProperty("allure.tests.management.pattern", jiraPattern); } - private static void save(Properties props) { - try (FileOutputStream fos = new FileOutputStream( - "target/allure-results/environment.properties")) { - props.store(fos, - "See https://github.com/allure-framework/allure-core/wiki/Environment"); - } catch (IOException e) { - logger.error("IO problem when writing allure properties file", e); - } + return props; + } + + private static Properties getUIProperties() { + Properties props = new Properties(); + UITestLifecycle.get().getUserAgent() + .ifPresent(ua -> props.setProperty("UserAgent", ua)); + return props; + } + + private static void save(Properties props) { + try (FileOutputStream fos = new FileOutputStream( + "target/allure-results/environment.properties")) { + props.store(fos, + "See https://github.com/allure-framework/allure-core/wiki/Environment"); + } catch (IOException e) { + logger.error("IO problem when writing allure properties file", e); } + } } diff --git a/src/main/java/com/frameworkium/core/common/reporting/jira/JiraConfig.java b/src/main/java/com/frameworkium/core/common/reporting/jira/JiraConfig.java index 8a388a26..0b104612 100644 --- a/src/main/java/com/frameworkium/core/common/reporting/jira/JiraConfig.java +++ b/src/main/java/com/frameworkium/core/common/reporting/jira/JiraConfig.java @@ -1,55 +1,55 @@ package com.frameworkium.core.common.reporting.jira; public class JiraConfig { - private JiraConfig() { - // hide default constructor for this util class - } + private JiraConfig() { + // hide default constructor for this util class + } - /** - * These should correspond to your ZAPI result IDs and - * are only used if logging to Zephyr for JIRA. - */ - public static class ZapiStatus { + /** + * These should correspond to your ZAPI result IDs and + * are only used if logging to Zephyr for JIRA. + */ + public static class ZapiStatus { - public static final int ZAPI_STATUS_PASS = 1; - public static final int ZAPI_STATUS_FAIL = 2; - public static final int ZAPI_STATUS_WIP = 3; - public static final int ZAPI_STATUS_BLOCKED = 4; - } + public static final int ZAPI_STATUS_PASS = 1; + public static final int ZAPI_STATUS_FAIL = 2; + public static final int ZAPI_STATUS_WIP = 3; + public static final int ZAPI_STATUS_BLOCKED = 4; + } - /** - * These should correspond to your field options - * if logging a test result to a field. - */ - public static class JiraFieldStatus { - public static final String JIRA_STATUS_PASS = "Pass"; - public static final String JIRA_STATUS_FAIL = "Fail"; - public static final String JIRA_STATUS_WIP = "WIP"; - public static final String JIRA_STATUS_BLOCKED = "Blocked"; - } + /** + * These should correspond to your field options + * if logging a test result to a field. + */ + public static class JiraFieldStatus { + public static final String JIRA_STATUS_PASS = "Pass"; + public static final String JIRA_STATUS_FAIL = "Fail"; + public static final String JIRA_STATUS_WIP = "WIP"; + public static final String JIRA_STATUS_BLOCKED = "Blocked"; + } - /** - * These should correspond to the workflow transition names required to mark - * the result if using a customised jira issue type & workflow to manage - * tests NB - put all required transitions to get between statuses - * (e.g. restart, then mark result) - each will be tried & ignored if not possible - */ - public static class JiraTransition { - public static final String[] JIRA_TRANSITION_PASS = {"Done"}; - public static final String[] JIRA_TRANSITION_FAIL = {"Done"}; - public static final String[] JIRA_TRANSITION_WIP = {"Reopen", "Start Progress"}; - public static final String[] JIRA_TRANSITION_BLOCKED = {"Done"}; - } + /** + * These should correspond to the workflow transition names required to mark + * the result if using a customised jira issue type & workflow to manage + * tests NB - put all required transitions to get between statuses + * (e.g. restart, then mark result) - each will be tried & ignored if not possible + */ + public static class JiraTransition { + public static final String[] JIRA_TRANSITION_PASS = {"Done"}; + public static final String[] JIRA_TRANSITION_FAIL = {"Done"}; + public static final String[] JIRA_TRANSITION_WIP = {"Reopen", "Start Progress"}; + public static final String[] JIRA_TRANSITION_BLOCKED = {"Done"}; + } - /** - * These should correspond to your field options - * if logging a test result to a field. - */ - public static class SpiraStatus { - public static final int SPIRA_STATUS_PASS = 2; - public static final int SPIRA_STATUS_FAIL = 1; - public static final int SPIRA_STATUS_WIP = 4; - public static final int SPIRA_STATUS_BLOCKED = 5; - } + /** + * These should correspond to your field options + * if logging a test result to a field. + */ + public static class SpiraStatus { + public static final int SPIRA_STATUS_PASS = 2; + public static final int SPIRA_STATUS_FAIL = 1; + public static final int SPIRA_STATUS_WIP = 4; + public static final int SPIRA_STATUS_BLOCKED = 5; + } } diff --git a/src/main/java/com/frameworkium/core/common/reporting/jira/dto/attachment/AttachmentDto.java b/src/main/java/com/frameworkium/core/common/reporting/jira/dto/attachment/AttachmentDto.java index c099eb4c..0583071e 100755 --- a/src/main/java/com/frameworkium/core/common/reporting/jira/dto/attachment/AttachmentDto.java +++ b/src/main/java/com/frameworkium/core/common/reporting/jira/dto/attachment/AttachmentDto.java @@ -3,12 +3,12 @@ import com.frameworkium.core.api.dto.AbstractDTO; public class AttachmentDto extends AbstractDTO { - public String fileName; - public String dateCreated; - public String fileSize; - public String fileIcon; - public String author; - public String fileIconAltText; - public String comment; - public String fileId; + public String fileName; + public String dateCreated; + public String fileSize; + public String fileIcon; + public String author; + public String fileIconAltText; + public String comment; + public String fileId; } diff --git a/src/main/java/com/frameworkium/core/common/reporting/jira/dto/attachment/AttachmentListDto.java b/src/main/java/com/frameworkium/core/common/reporting/jira/dto/attachment/AttachmentListDto.java index ae1b1422..dde71493 100755 --- a/src/main/java/com/frameworkium/core/common/reporting/jira/dto/attachment/AttachmentListDto.java +++ b/src/main/java/com/frameworkium/core/common/reporting/jira/dto/attachment/AttachmentListDto.java @@ -1,9 +1,8 @@ package com.frameworkium.core.common.reporting.jira.dto.attachment; import com.frameworkium.core.api.dto.AbstractDTO; - import java.util.List; public class AttachmentListDto extends AbstractDTO { - public List data; + public List data; } diff --git a/src/main/java/com/frameworkium/core/common/reporting/jira/dto/cycle/CreateCycleSuccessDto.java b/src/main/java/com/frameworkium/core/common/reporting/jira/dto/cycle/CreateCycleSuccessDto.java index 77cd567e..0c7a2ec9 100644 --- a/src/main/java/com/frameworkium/core/common/reporting/jira/dto/cycle/CreateCycleSuccessDto.java +++ b/src/main/java/com/frameworkium/core/common/reporting/jira/dto/cycle/CreateCycleSuccessDto.java @@ -3,6 +3,6 @@ import com.frameworkium.core.api.dto.AbstractDTO; public class CreateCycleSuccessDto extends AbstractDTO { - public String id; - public String responseMessage; + public String id; + public String responseMessage; } diff --git a/src/main/java/com/frameworkium/core/common/reporting/jira/dto/cycle/CreateNewCycleDto.java b/src/main/java/com/frameworkium/core/common/reporting/jira/dto/cycle/CreateNewCycleDto.java index 2d1c3360..401f3e17 100644 --- a/src/main/java/com/frameworkium/core/common/reporting/jira/dto/cycle/CreateNewCycleDto.java +++ b/src/main/java/com/frameworkium/core/common/reporting/jira/dto/cycle/CreateNewCycleDto.java @@ -7,47 +7,48 @@ @JsonDeserialize(builder = CreateNewCycleDto.Builder.class) public class CreateNewCycleDto extends AbstractDTO { + @JsonUnwrapped + public CycleLightDto cycleLightDto; + public String cloneCycleId; + public String sprintId; + + private CreateNewCycleDto(final Builder builder) { + cycleLightDto = builder.cycleLightDto; + cloneCycleId = builder.cloneCycleId; + sprintId = builder.sprintId; + } + + public static Builder newBuilder() { + return new Builder(); + } + + @JsonPOJOBuilder(withPrefix = "") + public static final class Builder { @JsonUnwrapped - public CycleLightDto cycleLightDto; - public String cloneCycleId; - public String sprintId; - - private CreateNewCycleDto(final Builder builder) { - cycleLightDto = builder.cycleLightDto; - cloneCycleId = builder.cloneCycleId; - sprintId = builder.sprintId; + private CycleLightDto cycleLightDto; + private String cloneCycleId; + private String sprintId; + + private Builder() { + } + + public Builder cycleLightDto(final CycleLightDto cycleLightDto) { + this.cycleLightDto = cycleLightDto; + return this; + } + + public Builder cloneCycleId(final String cloneCycleId) { + this.cloneCycleId = cloneCycleId; + return this; } - public static Builder newBuilder() { - return new Builder(); + public Builder sprintId(final String sprintId) { + this.sprintId = sprintId; + return this; } - @JsonPOJOBuilder(withPrefix = "") - public static final class Builder { - @JsonUnwrapped - private CycleLightDto cycleLightDto; - private String cloneCycleId; - private String sprintId; - - private Builder() {} - - public Builder cycleLightDto(final CycleLightDto cycleLightDto) { - this.cycleLightDto = cycleLightDto; - return this; - } - - public Builder cloneCycleId(final String cloneCycleId) { - this.cloneCycleId = cloneCycleId; - return this; - } - - public Builder sprintId(final String sprintId) { - this.sprintId = sprintId; - return this; - } - - public CreateNewCycleDto build() { - return new CreateNewCycleDto(this); - } + public CreateNewCycleDto build() { + return new CreateNewCycleDto(this); } + } } diff --git a/src/main/java/com/frameworkium/core/common/reporting/jira/dto/cycle/CycleDto.java b/src/main/java/com/frameworkium/core/common/reporting/jira/dto/cycle/CycleDto.java index 4ea17002..cc608697 100644 --- a/src/main/java/com/frameworkium/core/common/reporting/jira/dto/cycle/CycleDto.java +++ b/src/main/java/com/frameworkium/core/common/reporting/jira/dto/cycle/CycleDto.java @@ -7,167 +7,169 @@ @JsonDeserialize(builder = CycleDto.Builder.class) public class CycleDto extends AbstractDTO { + @JsonUnwrapped + public CycleLightDto cycleLightDto; + public String createdBy; + public String createdByDisplay; + public String createdDate; + public String ended; + public String expand; + public Boolean isExecutionWorkflowEnabledForProject; + public Boolean isTimeTrackingEnabled; + public String modifiedBy; + public String projectKey; + public String started; + public Long totalCycleExecutions; + public Long totalDefects; + public Long totalExecuted; + public Long totalExecutions; + public Long totalFolders; + public String versionName; + public Long recordsCount; + + private CycleDto(final Builder builder) { + cycleLightDto = builder.cycleLightDto; + createdBy = builder.createdBy; + createdByDisplay = builder.createdByDisplay; + createdDate = builder.createdDate; + ended = builder.ended; + expand = builder.expand; + isExecutionWorkflowEnabledForProject = builder.isExecutionWorkflowEnabledForProject; + isTimeTrackingEnabled = builder.isTimeTrackingEnabled; + modifiedBy = builder.modifiedBy; + projectKey = builder.projectKey; + started = builder.started; + totalCycleExecutions = builder.totalCycleExecutions; + totalDefects = builder.totalDefects; + totalExecuted = builder.totalExecuted; + totalExecutions = builder.totalExecutions; + totalFolders = builder.totalFolders; + versionName = builder.versionName; + recordsCount = builder.recordsCount; + } + + public static Builder newBuilder() { + return new Builder(); + } + + @JsonPOJOBuilder(withPrefix = "") + public static final class Builder { @JsonUnwrapped - public CycleLightDto cycleLightDto; - public String createdBy; - public String createdByDisplay; - public String createdDate; - public String ended; - public String expand; - public Boolean isExecutionWorkflowEnabledForProject; - public Boolean isTimeTrackingEnabled; - public String modifiedBy; - public String projectKey; - public String started; - public Long totalCycleExecutions; - public Long totalDefects; - public Long totalExecuted; - public Long totalExecutions; - public Long totalFolders; - public String versionName; - public Long recordsCount; - - private CycleDto(final Builder builder) { - cycleLightDto = builder.cycleLightDto; - createdBy = builder.createdBy; - createdByDisplay = builder.createdByDisplay; - createdDate = builder.createdDate; - ended = builder.ended; - expand = builder.expand; - isExecutionWorkflowEnabledForProject = builder.isExecutionWorkflowEnabledForProject; - isTimeTrackingEnabled = builder.isTimeTrackingEnabled; - modifiedBy = builder.modifiedBy; - projectKey = builder.projectKey; - started = builder.started; - totalCycleExecutions = builder.totalCycleExecutions; - totalDefects = builder.totalDefects; - totalExecuted = builder.totalExecuted; - totalExecutions = builder.totalExecutions; - totalFolders = builder.totalFolders; - versionName = builder.versionName; - recordsCount = builder.recordsCount; - } - - public static Builder newBuilder() { - return new Builder(); - } - - @JsonPOJOBuilder(withPrefix = "") - public static final class Builder { - @JsonUnwrapped - private CycleLightDto cycleLightDto; - private String createdBy; - private String createdByDisplay; - private String createdDate; - private String ended; - private String expand; - private Boolean isExecutionWorkflowEnabledForProject; - private Boolean isTimeTrackingEnabled; - private String modifiedBy; - private String projectKey; - private String started; - private Long totalCycleExecutions; - private Long totalDefects; - private Long totalExecuted; - private Long totalExecutions; - private Long totalFolders; - private String versionName; - private Long recordsCount; - - private Builder() {} - - public Builder cycleLightDto(final CycleLightDto cycleLightDto) { - this.cycleLightDto = cycleLightDto; - return this; - } - - public Builder createdBy(final String createdBy) { - this.createdBy = createdBy; - return this; - } - - public Builder createdByDisplay(final String createdByDisplay) { - this.createdByDisplay = createdByDisplay; - return this; - } - - public Builder createdDate(final String createdDate) { - this.createdDate = createdDate; - return this; - } - - public Builder ended(final String ended) { - this.ended = ended; - return this; - } - - public Builder expand(final String expand) { - this.expand = expand; - return this; - } - - public Builder isExecutionWorkflowEnabledForProject(final Boolean isExecutionWorkflowEnabledForProject) { - this.isExecutionWorkflowEnabledForProject = isExecutionWorkflowEnabledForProject; - return this; - } - - public Builder isTimeTrackingEnabled(final Boolean isTimeTrackingEnabled) { - this.isTimeTrackingEnabled = isTimeTrackingEnabled; - return this; - } - - public Builder modifiedBy(final String modifiedBy) { - this.modifiedBy = modifiedBy; - return this; - } - - public Builder projectKey(final String projectKey) { - this.projectKey = projectKey; - return this; - } - - public Builder started(final String started) { - this.started = started; - return this; - } - - public Builder totalCycleExecutions(final Long totalCycleExecutions) { - this.totalCycleExecutions = totalCycleExecutions; - return this; - } - - public Builder totalDefects(final Long totalDefects) { - this.totalDefects = totalDefects; - return this; - } - - public Builder totalExecuted(final Long totalExecuted) { - this.totalExecuted = totalExecuted; - return this; - } - - public Builder totalExecutions(final Long totalExecutions) { - this.totalExecutions = totalExecutions; - return this; - } - - public Builder totalFolders(final Long totalFolders) { - this.totalFolders = totalFolders; - return this; - } - - public Builder versionName(final String versionName) { - this.versionName = versionName; - return this; - } - - public Builder recordsCount(final Long recordsCount) { - this.recordsCount = recordsCount; - return this; - } - - public CycleDto build() { - return new CycleDto(this); - } + private CycleLightDto cycleLightDto; + private String createdBy; + private String createdByDisplay; + private String createdDate; + private String ended; + private String expand; + private Boolean isExecutionWorkflowEnabledForProject; + private Boolean isTimeTrackingEnabled; + private String modifiedBy; + private String projectKey; + private String started; + private Long totalCycleExecutions; + private Long totalDefects; + private Long totalExecuted; + private Long totalExecutions; + private Long totalFolders; + private String versionName; + private Long recordsCount; + + private Builder() { } + + public Builder cycleLightDto(final CycleLightDto cycleLightDto) { + this.cycleLightDto = cycleLightDto; + return this; + } + + public Builder createdBy(final String createdBy) { + this.createdBy = createdBy; + return this; + } + + public Builder createdByDisplay(final String createdByDisplay) { + this.createdByDisplay = createdByDisplay; + return this; + } + + public Builder createdDate(final String createdDate) { + this.createdDate = createdDate; + return this; + } + + public Builder ended(final String ended) { + this.ended = ended; + return this; + } + + public Builder expand(final String expand) { + this.expand = expand; + return this; + } + + public Builder isExecutionWorkflowEnabledForProject( + final Boolean isExecutionWorkflowEnabledForProject) { + this.isExecutionWorkflowEnabledForProject = isExecutionWorkflowEnabledForProject; + return this; + } + + public Builder isTimeTrackingEnabled(final Boolean isTimeTrackingEnabled) { + this.isTimeTrackingEnabled = isTimeTrackingEnabled; + return this; + } + + public Builder modifiedBy(final String modifiedBy) { + this.modifiedBy = modifiedBy; + return this; + } + + public Builder projectKey(final String projectKey) { + this.projectKey = projectKey; + return this; + } + + public Builder started(final String started) { + this.started = started; + return this; + } + + public Builder totalCycleExecutions(final Long totalCycleExecutions) { + this.totalCycleExecutions = totalCycleExecutions; + return this; + } + + public Builder totalDefects(final Long totalDefects) { + this.totalDefects = totalDefects; + return this; + } + + public Builder totalExecuted(final Long totalExecuted) { + this.totalExecuted = totalExecuted; + return this; + } + + public Builder totalExecutions(final Long totalExecutions) { + this.totalExecutions = totalExecutions; + return this; + } + + public Builder totalFolders(final Long totalFolders) { + this.totalFolders = totalFolders; + return this; + } + + public Builder versionName(final String versionName) { + this.versionName = versionName; + return this; + } + + public Builder recordsCount(final Long recordsCount) { + this.recordsCount = recordsCount; + return this; + } + + public CycleDto build() { + return new CycleDto(this); + } + } } diff --git a/src/main/java/com/frameworkium/core/common/reporting/jira/dto/cycle/CycleLightDto.java b/src/main/java/com/frameworkium/core/common/reporting/jira/dto/cycle/CycleLightDto.java index 15cb5b22..4c017fbb 100644 --- a/src/main/java/com/frameworkium/core/common/reporting/jira/dto/cycle/CycleLightDto.java +++ b/src/main/java/com/frameworkium/core/common/reporting/jira/dto/cycle/CycleLightDto.java @@ -4,89 +4,89 @@ import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; import com.frameworkium.core.api.dto.AbstractDTO; - import java.time.LocalDate; @JsonDeserialize(builder = CycleLightDto.Builder.class) public class CycleLightDto extends AbstractDTO { - public String name; - public String build; - public String environment; - public String description; - public LocalDate startDate; - public LocalDate endDate; - public Long projectId; - public Long versionId; + public String name; + public String build; + public String environment; + public String description; + public LocalDate startDate; + public LocalDate endDate; + public Long projectId; + public Long versionId; - private CycleLightDto(final Builder builder) { - name = builder.name; - build = builder.build; - environment = builder.environment; - description = builder.description; - startDate = builder.startDate; - endDate = builder.endDate; - projectId = builder.projectId; - versionId = builder.versionId; - } + private CycleLightDto(final Builder builder) { + name = builder.name; + build = builder.build; + environment = builder.environment; + description = builder.description; + startDate = builder.startDate; + endDate = builder.endDate; + projectId = builder.projectId; + versionId = builder.versionId; + } - public static Builder newBuilder() { - return new Builder(); - } + public static Builder newBuilder() { + return new Builder(); + } - @JsonPOJOBuilder(withPrefix = "") - public static final class Builder { - private String name; - private String build; - private String environment; - private String description; - @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "d/MMM/yy", - with = JsonFormat.Feature.ACCEPT_CASE_INSENSITIVE_VALUES) - private LocalDate startDate; - @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "d/MMM/yy", - with = JsonFormat.Feature.ACCEPT_CASE_INSENSITIVE_VALUES) - private LocalDate endDate; - private Long projectId; - private Long versionId; + @JsonPOJOBuilder(withPrefix = "") + public static final class Builder { + private String name; + private String build; + private String environment; + private String description; + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "d/MMM/yy", + with = JsonFormat.Feature.ACCEPT_CASE_INSENSITIVE_VALUES) + private LocalDate startDate; + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "d/MMM/yy", + with = JsonFormat.Feature.ACCEPT_CASE_INSENSITIVE_VALUES) + private LocalDate endDate; + private Long projectId; + private Long versionId; - private Builder() {} + private Builder() { + } - public Builder name(final String name) { - this.name = name; - return this; - } + public Builder name(final String name) { + this.name = name; + return this; + } - public Builder environment(final String environment) { - this.environment = environment; - return this; - } + public Builder environment(final String environment) { + this.environment = environment; + return this; + } - public Builder description(final String description) { - this.description = description; - return this; - } + public Builder description(final String description) { + this.description = description; + return this; + } - public Builder startDate(final LocalDate startDate) { - this.startDate = startDate; - return this; - } + public Builder startDate(final LocalDate startDate) { + this.startDate = startDate; + return this; + } - public Builder endDate(final LocalDate endDate) { - this.endDate = endDate; - return this; - } + public Builder endDate(final LocalDate endDate) { + this.endDate = endDate; + return this; + } - public Builder projectId(final Long projectId) { - this.projectId = projectId; - return this; - } + public Builder projectId(final Long projectId) { + this.projectId = projectId; + return this; + } - public Builder versionId(final Long versionId) { - this.versionId = versionId; - return this; - } + public Builder versionId(final Long versionId) { + this.versionId = versionId; + return this; + } - public CycleLightDto build() { - return new CycleLightDto(this); - } + public CycleLightDto build() { + return new CycleLightDto(this); } + } } diff --git a/src/main/java/com/frameworkium/core/common/reporting/jira/dto/cycle/CycleListDto.java b/src/main/java/com/frameworkium/core/common/reporting/jira/dto/cycle/CycleListDto.java index fdc85dc2..c28b60cd 100644 --- a/src/main/java/com/frameworkium/core/common/reporting/jira/dto/cycle/CycleListDto.java +++ b/src/main/java/com/frameworkium/core/common/reporting/jira/dto/cycle/CycleListDto.java @@ -1,27 +1,29 @@ package com.frameworkium.core.common.reporting.jira.dto.cycle; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; import com.frameworkium.core.api.dto.AbstractDTO; - import java.util.HashMap; import java.util.Map; public class CycleListDto extends AbstractDTO { - public Map map = new HashMap<>(); - public Long recordsCount; + public Map map = new HashMap<>(); + public Long recordsCount; - @JsonCreator - public CycleListDto(@JsonProperty("recordsCount") Long recordsCount) { - this.recordsCount = recordsCount; - } + @JsonCreator + public CycleListDto(@JsonProperty("recordsCount") Long recordsCount) { + this.recordsCount = recordsCount; + } - @JsonAnySetter - public void setMap(String key, CycleDto cycleDto) { - map.put(key, cycleDto); - } + @JsonAnySetter + public void setMap(String key, CycleDto cycleDto) { + map.put(key, cycleDto); + } - @JsonAnyGetter - public Map getMap() { - return map; - } + @JsonAnyGetter + public Map getMap() { + return map; + } } diff --git a/src/main/java/com/frameworkium/core/common/reporting/jira/dto/execution/AddTestToCycleOperationDto.java b/src/main/java/com/frameworkium/core/common/reporting/jira/dto/execution/AddTestToCycleOperationDto.java index 22f8b53e..3c6e86a8 100644 --- a/src/main/java/com/frameworkium/core/common/reporting/jira/dto/execution/AddTestToCycleOperationDto.java +++ b/src/main/java/com/frameworkium/core/common/reporting/jira/dto/execution/AddTestToCycleOperationDto.java @@ -1,79 +1,81 @@ package com.frameworkium.core.common.reporting.jira.dto.execution; -import com.fasterxml.jackson.databind.annotation.*; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import com.frameworkium.core.api.dto.AbstractDTO; - import java.util.List; @JsonDeserialize(builder = AddTestToCycleOperationDto.Builder.class) public class AddTestToCycleOperationDto extends AbstractDTO { - public String cycleId; - public List issues; - public String searchId; - public String method; - @JsonSerialize(using = ToStringSerializer.class) - public Long projectId; - @JsonSerialize(using = ToStringSerializer.class) - public Long versionId; + public String cycleId; + public List issues; + public String searchId; + public String method; + @JsonSerialize(using = ToStringSerializer.class) + public Long projectId; + @JsonSerialize(using = ToStringSerializer.class) + public Long versionId; - private AddTestToCycleOperationDto(final Builder builder) { - cycleId = builder.cycleId; - issues = builder.issues; - searchId = builder.searchId; - method = builder.method; - projectId = builder.projectId; - versionId = builder.versionId; - } + private AddTestToCycleOperationDto(final Builder builder) { + cycleId = builder.cycleId; + issues = builder.issues; + searchId = builder.searchId; + method = builder.method; + projectId = builder.projectId; + versionId = builder.versionId; + } - public static Builder newBuilder() { - return new Builder(); - } + public static Builder newBuilder() { + return new Builder(); + } - @JsonPOJOBuilder(withPrefix = "") - public static final class Builder { - private String cycleId; - private List issues; - private String searchId; - private String method; - private Long projectId; - private Long versionId; + @JsonPOJOBuilder(withPrefix = "") + public static final class Builder { + private String cycleId; + private List issues; + private String searchId; + private String method; + private Long projectId; + private Long versionId; - private Builder() {} + private Builder() { + } - public Builder cycleId(final String cycleId) { - this.cycleId = cycleId; - return this; - } + public Builder cycleId(final String cycleId) { + this.cycleId = cycleId; + return this; + } - public Builder issues(final List issues) { - this.issues = issues; - return this; - } + public Builder issues(final List issues) { + this.issues = issues; + return this; + } - public Builder searchId(final String searchId) { - this.searchId = searchId; - return this; - } + public Builder searchId(final String searchId) { + this.searchId = searchId; + return this; + } - public Builder method(final String method) { - this.method = method; - return this; - } + public Builder method(final String method) { + this.method = method; + return this; + } - public Builder projectId(final Long projectId) { - this.projectId = projectId; - return this; - } + public Builder projectId(final Long projectId) { + this.projectId = projectId; + return this; + } - public Builder versionId(final Long versionId) { - this.versionId = versionId; - return this; - } + public Builder versionId(final Long versionId) { + this.versionId = versionId; + return this; + } - public AddTestToCycleOperationDto build() { - return new AddTestToCycleOperationDto(this); - } + public AddTestToCycleOperationDto build() { + return new AddTestToCycleOperationDto(this); } + } } diff --git a/src/main/java/com/frameworkium/core/common/reporting/jira/dto/execution/ExecutionDto.java b/src/main/java/com/frameworkium/core/common/reporting/jira/dto/execution/ExecutionDto.java index 4a8bd1bc..996d3933 100755 --- a/src/main/java/com/frameworkium/core/common/reporting/jira/dto/execution/ExecutionDto.java +++ b/src/main/java/com/frameworkium/core/common/reporting/jira/dto/execution/ExecutionDto.java @@ -7,86 +7,87 @@ @JsonDeserialize(builder = ExecutionDto.Builder.class) public class ExecutionDto extends AbstractDTO { - @JsonUnwrapped - public ExecutionLightDto executionLightDto; - public String executionStatus; - public String createdBy; - public String modifiedBy; - public Long issueId; - public String summary; - public String label; - public String component; + @JsonUnwrapped + public ExecutionLightDto executionLightDto; + public String executionStatus; + public String createdBy; + public String modifiedBy; + public Long issueId; + public String summary; + public String label; + public String component; - private ExecutionDto(Builder builder) { - this.executionLightDto = builder.executionLightDto; - this.executionStatus = builder.executionStatus; - this.createdBy = builder.createdBy; - this.modifiedBy = builder.modifiedBy; - this.issueId = builder.issueId; - this.summary = builder.summary; - this.label = builder.label; - this.component = builder.component; - } + private ExecutionDto(Builder builder) { + this.executionLightDto = builder.executionLightDto; + this.executionStatus = builder.executionStatus; + this.createdBy = builder.createdBy; + this.modifiedBy = builder.modifiedBy; + this.issueId = builder.issueId; + this.summary = builder.summary; + this.label = builder.label; + this.component = builder.component; + } - public static ExecutionDto.Builder newBuilder() { - return new ExecutionDto.Builder(); - } + public static ExecutionDto.Builder newBuilder() { + return new ExecutionDto.Builder(); + } - @JsonPOJOBuilder(withPrefix = "") - public static final class Builder { - private ExecutionLightDto executionLightDto; - private String executionStatus; - private String createdBy; - private String modifiedBy; - private Long issueId; - private String summary; - private String label; - private String component; + @JsonPOJOBuilder(withPrefix = "") + public static final class Builder { + private ExecutionLightDto executionLightDto; + private String executionStatus; + private String createdBy; + private String modifiedBy; + private Long issueId; + private String summary; + private String label; + private String component; - private Builder() {} + private Builder() { + } - public Builder executionLightDto(ExecutionLightDto executionLightDto) { - this.executionLightDto = executionLightDto; - return this; - } + public Builder executionLightDto(ExecutionLightDto executionLightDto) { + this.executionLightDto = executionLightDto; + return this; + } - public Builder executionStatus(String executionStatus) { - this.executionStatus = executionStatus; - return this; - } + public Builder executionStatus(String executionStatus) { + this.executionStatus = executionStatus; + return this; + } - public Builder createdBy(String createdBy) { - this.createdBy = createdBy; - return this; - } + public Builder createdBy(String createdBy) { + this.createdBy = createdBy; + return this; + } - public Builder modifiedBy(String modifiedBy) { - this.modifiedBy = modifiedBy; - return this; - } + public Builder modifiedBy(String modifiedBy) { + this.modifiedBy = modifiedBy; + return this; + } - public Builder issueId(Long issueId) { - this.issueId = issueId; - return this; - } + public Builder issueId(Long issueId) { + this.issueId = issueId; + return this; + } - public Builder summary(String summary) { - this.summary = summary; - return this; - } + public Builder summary(String summary) { + this.summary = summary; + return this; + } - public Builder label(String label) { - this.label = label; - return this; - } + public Builder label(String label) { + this.label = label; + return this; + } - public Builder component(String component) { - this.component = component; - return this; - } + public Builder component(String component) { + this.component = component; + return this; + } - public ExecutionDto build() { - return new ExecutionDto(this); - } + public ExecutionDto build() { + return new ExecutionDto(this); } + } } diff --git a/src/main/java/com/frameworkium/core/common/reporting/jira/dto/execution/ExecutionLightDto.java b/src/main/java/com/frameworkium/core/common/reporting/jira/dto/execution/ExecutionLightDto.java index 4a0086d8..4d2ca409 100755 --- a/src/main/java/com/frameworkium/core/common/reporting/jira/dto/execution/ExecutionLightDto.java +++ b/src/main/java/com/frameworkium/core/common/reporting/jira/dto/execution/ExecutionLightDto.java @@ -6,109 +6,110 @@ @JsonDeserialize(builder = ExecutionLightDto.Builder.class) public class ExecutionLightDto extends AbstractDTO { - public Long id; - public Long orderId; - public String comment; - public String htmlComment; - public Long cycleId; - public String cycleName; - public Long versionId; - public String versionName; - public Long projectId; - public String issueKey; - public String projectKey; - - public ExecutionLightDto(Builder builder) { - this.id = builder.id; - this.orderId = builder.orderId; - this.comment = builder.comment; - this.htmlComment = builder.htmlComment; - this.cycleId = builder.cycleId; - this.cycleName = builder.cycleName; - this.versionId = builder.versionId; - this.versionName = builder.versionName; - this.projectId = builder.projectId; - this.issueKey = builder.issueKey; - this.projectKey = builder.projectKey; + public Long id; + public Long orderId; + public String comment; + public String htmlComment; + public Long cycleId; + public String cycleName; + public Long versionId; + public String versionName; + public Long projectId; + public String issueKey; + public String projectKey; + + public ExecutionLightDto(Builder builder) { + this.id = builder.id; + this.orderId = builder.orderId; + this.comment = builder.comment; + this.htmlComment = builder.htmlComment; + this.cycleId = builder.cycleId; + this.cycleName = builder.cycleName; + this.versionId = builder.versionId; + this.versionName = builder.versionName; + this.projectId = builder.projectId; + this.issueKey = builder.issueKey; + this.projectKey = builder.projectKey; + } + + public static ExecutionLightDto.Builder newBuilder() { + return new ExecutionLightDto.Builder(); + } + + @JsonPOJOBuilder(withPrefix = "") + public static final class Builder { + private Long id; + private Long orderId; + private String comment; + private String htmlComment; + private Long cycleId; + private String cycleName; + private Long versionId; + private String versionName; + private Long projectId; + private String issueKey; + private String projectKey; + + private Builder() { } - public static ExecutionLightDto.Builder newBuilder() { - return new ExecutionLightDto.Builder(); + public Builder id(Long id) { + this.id = id; + return this; } - @JsonPOJOBuilder(withPrefix = "") - public static final class Builder { - private Long id; - private Long orderId; - private String comment; - private String htmlComment; - private Long cycleId; - private String cycleName; - private Long versionId; - private String versionName; - private Long projectId; - private String issueKey; - private String projectKey; - - private Builder() {} - - public Builder id(Long id) { - this.id = id; - return this; - } - - public Builder orderId(Long orderId) { - this.orderId = orderId; - return this; - } - - public Builder comment(String comment) { - this.comment = comment; - return this; - } - - public Builder htmlComment(String htmlComment) { - this.htmlComment = htmlComment; - return this; - } - - public Builder cycleId(Long cycleId) { - this.cycleId = cycleId; - return this; - } - - public Builder cycleName(String cycleName) { - this.cycleName = cycleName; - return this; - } - - public Builder versionId(Long versionId) { - this.versionId = versionId; - return this; - } - - public Builder versionName(String versionName) { - this.versionName = versionName; - return this; - } - - public Builder projectId(Long projectId) { - this.projectId = projectId; - return this; - } - - public Builder issueKey(String issueKey) { - this.issueKey = issueKey; - return this; - } - - public Builder projectKey(String projectKey) { - this.projectKey = projectKey; - return this; - } - - public ExecutionLightDto build() { - return new ExecutionLightDto(this); - } + public Builder orderId(Long orderId) { + this.orderId = orderId; + return this; } + + public Builder comment(String comment) { + this.comment = comment; + return this; + } + + public Builder htmlComment(String htmlComment) { + this.htmlComment = htmlComment; + return this; + } + + public Builder cycleId(Long cycleId) { + this.cycleId = cycleId; + return this; + } + + public Builder cycleName(String cycleName) { + this.cycleName = cycleName; + return this; + } + + public Builder versionId(Long versionId) { + this.versionId = versionId; + return this; + } + + public Builder versionName(String versionName) { + this.versionName = versionName; + return this; + } + + public Builder projectId(Long projectId) { + this.projectId = projectId; + return this; + } + + public Builder issueKey(String issueKey) { + this.issueKey = issueKey; + return this; + } + + public Builder projectKey(String projectKey) { + this.projectKey = projectKey; + return this; + } + + public ExecutionLightDto build() { + return new ExecutionLightDto(this); + } + } } diff --git a/src/main/java/com/frameworkium/core/common/reporting/jira/dto/execution/UpdateExecutionOperationDto.java b/src/main/java/com/frameworkium/core/common/reporting/jira/dto/execution/UpdateExecutionOperationDto.java index 8f7f8262..1d32e35f 100755 --- a/src/main/java/com/frameworkium/core/common/reporting/jira/dto/execution/UpdateExecutionOperationDto.java +++ b/src/main/java/com/frameworkium/core/common/reporting/jira/dto/execution/UpdateExecutionOperationDto.java @@ -7,62 +7,63 @@ @JsonDeserialize(builder = UpdateExecutionOperationDto.Builder.class) public class UpdateExecutionOperationDto extends AbstractDTO { - @JsonUnwrapped - public ExecutionDto executionDto; - public String executedOn; - public String executionBy; - public String executedByDisplay; - public Integer status; + @JsonUnwrapped + public ExecutionDto executionDto; + public String executedOn; + public String executionBy; + public String executedByDisplay; + public Integer status; - private UpdateExecutionOperationDto(Builder builder) { - this.executionBy = builder.executionBy; - this.executionDto = builder.executionDto; - this.executedOn = builder.executedOn; - this.executedByDisplay = builder.executedByDisplay; - this.status = builder.status; - } + private UpdateExecutionOperationDto(Builder builder) { + this.executionBy = builder.executionBy; + this.executionDto = builder.executionDto; + this.executedOn = builder.executedOn; + this.executedByDisplay = builder.executedByDisplay; + this.status = builder.status; + } - public static UpdateExecutionOperationDto.Builder newBuilder() { - return new UpdateExecutionOperationDto.Builder(); - } + public static UpdateExecutionOperationDto.Builder newBuilder() { + return new UpdateExecutionOperationDto.Builder(); + } - @JsonPOJOBuilder(withPrefix = "") - public static final class Builder { - private ExecutionDto executionDto; - private String executedOn; - private String executionBy; - private String executedByDisplay; - private Integer status; + @JsonPOJOBuilder(withPrefix = "") + public static final class Builder { + private ExecutionDto executionDto; + private String executedOn; + private String executionBy; + private String executedByDisplay; + private Integer status; - private Builder() {} + private Builder() { + } - public Builder executionDto(ExecutionDto executionDto) { - this.executionDto = executionDto; - return this; - } + public Builder executionDto(ExecutionDto executionDto) { + this.executionDto = executionDto; + return this; + } - public Builder executedOn(String executedOn) { - this.executedOn = executedOn; - return this; - } + public Builder executedOn(String executedOn) { + this.executedOn = executedOn; + return this; + } - public Builder executionBy(String executionBy) { - this.executionBy = executionBy; - return this; - } + public Builder executionBy(String executionBy) { + this.executionBy = executionBy; + return this; + } - public Builder executedByDisplay(String executedByDisplay) { - this.executedByDisplay = executedByDisplay; - return this; - } + public Builder executedByDisplay(String executedByDisplay) { + this.executedByDisplay = executedByDisplay; + return this; + } - public Builder status(Integer status) { - this.status = status; - return this; - } + public Builder status(Integer status) { + this.status = status; + return this; + } - public UpdateExecutionOperationDto build() { - return new UpdateExecutionOperationDto(this); - } + public UpdateExecutionOperationDto build() { + return new UpdateExecutionOperationDto(this); } + } } diff --git a/src/main/java/com/frameworkium/core/common/reporting/jira/dto/executionsearch/ExecutionSearchDto.java b/src/main/java/com/frameworkium/core/common/reporting/jira/dto/executionsearch/ExecutionSearchDto.java index c223afae..4592185a 100755 --- a/src/main/java/com/frameworkium/core/common/reporting/jira/dto/executionsearch/ExecutionSearchDto.java +++ b/src/main/java/com/frameworkium/core/common/reporting/jira/dto/executionsearch/ExecutionSearchDto.java @@ -5,35 +5,34 @@ import com.frameworkium.core.api.dto.AbstractDTO; import com.frameworkium.core.common.reporting.jira.dto.execution.ExecutionLightDto; import com.frameworkium.core.common.reporting.jira.dto.status.StatusDto; - import java.time.LocalDate; import java.util.List; public class ExecutionSearchDto extends AbstractDTO { - @JsonUnwrapped - public ExecutionLightDto executionLightDto; - public String issueId; - public String issueSummary; - public List labels; - public String issueDescription; - public String project; - public Long projectAvatarId; - public String priority; - public List components; - public StatusDto status; - @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yy/MMM/dd") - public LocalDate executedOn; - @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yy/MMM/dd") - public LocalDate creationDate; - public String executedBy; - public String executedByUserName; - public List executionDefects; - public List stepDefects; - public Long executionDefectCount; - public Long stepDefectCount; - public Long totalDefectCount; - public String executedByDisplay; - public String assignee; - public String assigneeUserName; - public String assigneeDisplay; + @JsonUnwrapped + public ExecutionLightDto executionLightDto; + public String issueId; + public String issueSummary; + public List labels; + public String issueDescription; + public String project; + public Long projectAvatarId; + public String priority; + public List components; + public StatusDto status; + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yy/MMM/dd") + public LocalDate executedOn; + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yy/MMM/dd") + public LocalDate creationDate; + public String executedBy; + public String executedByUserName; + public List executionDefects; + public List stepDefects; + public Long executionDefectCount; + public Long stepDefectCount; + public Long totalDefectCount; + public String executedByDisplay; + public String assignee; + public String assigneeUserName; + public String assigneeDisplay; } diff --git a/src/main/java/com/frameworkium/core/common/reporting/jira/dto/executionsearch/ExecutionSearchListDto.java b/src/main/java/com/frameworkium/core/common/reporting/jira/dto/executionsearch/ExecutionSearchListDto.java index 1dc695d1..3c6083d1 100755 --- a/src/main/java/com/frameworkium/core/common/reporting/jira/dto/executionsearch/ExecutionSearchListDto.java +++ b/src/main/java/com/frameworkium/core/common/reporting/jira/dto/executionsearch/ExecutionSearchListDto.java @@ -3,72 +3,71 @@ import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; import com.frameworkium.core.api.dto.AbstractDTO; - import java.util.List; @JsonDeserialize(builder = ExecutionSearchListDto.Builder.class) public class ExecutionSearchListDto extends AbstractDTO { - public List executions; - public Long currentIndex; - public Long maxResultAllowed; - public List linksNew; - public Long totalCount; - public List executionIds; + public List executions; + public Long currentIndex; + public Long maxResultAllowed; + public List linksNew; + public Long totalCount; + public List executionIds; - public ExecutionSearchListDto(Builder builder) { - this.executions = builder.executions; - this.currentIndex = builder.currentIndex; - this.maxResultAllowed = builder.maxResultAllowed; - this.linksNew = builder.linksNew; - this.totalCount = builder.totalCount; - this.executionIds = builder.executionIds; - } + public ExecutionSearchListDto(Builder builder) { + this.executions = builder.executions; + this.currentIndex = builder.currentIndex; + this.maxResultAllowed = builder.maxResultAllowed; + this.linksNew = builder.linksNew; + this.totalCount = builder.totalCount; + this.executionIds = builder.executionIds; + } - public static ExecutionSearchListDto.Builder newBuilder() { - return new ExecutionSearchListDto.Builder(); - } + public static ExecutionSearchListDto.Builder newBuilder() { + return new ExecutionSearchListDto.Builder(); + } - @JsonPOJOBuilder(withPrefix = "") - public static final class Builder { - private List executions; - private Long currentIndex; - private Long maxResultAllowed; - private List linksNew; - private Long totalCount; - private List executionIds; + @JsonPOJOBuilder(withPrefix = "") + public static final class Builder { + private List executions; + private Long currentIndex; + private Long maxResultAllowed; + private List linksNew; + private Long totalCount; + private List executionIds; - public Builder executions(final List executions) { - this.executions = executions; - return this; - } + public Builder executions(final List executions) { + this.executions = executions; + return this; + } - public Builder currentIndex(final Long currentIndex) { - this.currentIndex = currentIndex; - return this; - } + public Builder currentIndex(final Long currentIndex) { + this.currentIndex = currentIndex; + return this; + } - public Builder maxResultAllowed(final Long maxResultAllowed) { - this.maxResultAllowed = maxResultAllowed; - return this; - } + public Builder maxResultAllowed(final Long maxResultAllowed) { + this.maxResultAllowed = maxResultAllowed; + return this; + } - public Builder linksNew(final List linksNew) { - this.linksNew = linksNew; - return this; - } + public Builder linksNew(final List linksNew) { + this.linksNew = linksNew; + return this; + } - public Builder totalCount(final Long totalCount) { - this.totalCount = totalCount; - return this; - } + public Builder totalCount(final Long totalCount) { + this.totalCount = totalCount; + return this; + } - public Builder executionIds(final List executionIds) { - this.executionIds = executionIds; - return this; - } + public Builder executionIds(final List executionIds) { + this.executionIds = executionIds; + return this; + } - public ExecutionSearchListDto build() { - return new ExecutionSearchListDto(this); - } + public ExecutionSearchListDto build() { + return new ExecutionSearchListDto(this); } + } } diff --git a/src/main/java/com/frameworkium/core/common/reporting/jira/dto/project/ProjectDto.java b/src/main/java/com/frameworkium/core/common/reporting/jira/dto/project/ProjectDto.java index 96f3734c..405aaddf 100644 --- a/src/main/java/com/frameworkium/core/common/reporting/jira/dto/project/ProjectDto.java +++ b/src/main/java/com/frameworkium/core/common/reporting/jira/dto/project/ProjectDto.java @@ -5,7 +5,7 @@ import com.frameworkium.core.api.dto.AbstractDTO; public class ProjectDto extends AbstractDTO { - @JsonSerialize(using = ToStringSerializer.class) - public Long id; - public String key; + @JsonSerialize(using = ToStringSerializer.class) + public Long id; + public String key; } diff --git a/src/main/java/com/frameworkium/core/common/reporting/jira/dto/status/StatusDto.java b/src/main/java/com/frameworkium/core/common/reporting/jira/dto/status/StatusDto.java index 0825b4b3..32ce7c0c 100755 --- a/src/main/java/com/frameworkium/core/common/reporting/jira/dto/status/StatusDto.java +++ b/src/main/java/com/frameworkium/core/common/reporting/jira/dto/status/StatusDto.java @@ -3,9 +3,9 @@ import com.frameworkium.core.api.dto.AbstractDTO; public class StatusDto extends AbstractDTO { - public Long id; - public String name; - public String description; - public String color; - public Long type; + public Long id; + public String name; + public String description; + public String color; + public Long type; } diff --git a/src/main/java/com/frameworkium/core/common/reporting/jira/dto/version/VersionDto.java b/src/main/java/com/frameworkium/core/common/reporting/jira/dto/version/VersionDto.java index dc9e1892..505469eb 100644 --- a/src/main/java/com/frameworkium/core/common/reporting/jira/dto/version/VersionDto.java +++ b/src/main/java/com/frameworkium/core/common/reporting/jira/dto/version/VersionDto.java @@ -1,120 +1,122 @@ package com.frameworkium.core.common.reporting.jira.dto.version; import com.fasterxml.jackson.annotation.JsonFormat; -import com.fasterxml.jackson.databind.annotation.*; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.frameworkium.core.api.dto.AbstractDTO; - import java.time.LocalDate; @JsonDeserialize(builder = VersionDto.Builder.class) public class VersionDto extends AbstractDTO { - public final String self; - public final Long id; - public final String description; - public final String name; - public final Boolean archived; - @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd") - public final LocalDate releaseDate; - public final Boolean released; - public final Boolean overdue; - public final LocalDate userReleaseDate; - public final String project; - public final Long projectId; - - private VersionDto(final Builder builder) { - self = builder.self; - id = builder.id; - description = builder.description; - name = builder.name; - archived = builder.archived; - released = builder.released; - releaseDate = builder.releaseDate; - overdue = builder.overdue; - userReleaseDate = builder.userReleaseDate; - project = builder.project; - projectId = builder.projectId; + public final String self; + public final Long id; + public final String description; + public final String name; + public final Boolean archived; + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd") + public final LocalDate releaseDate; + public final Boolean released; + public final Boolean overdue; + public final LocalDate userReleaseDate; + public final String project; + public final Long projectId; + + private VersionDto(final Builder builder) { + self = builder.self; + id = builder.id; + description = builder.description; + name = builder.name; + archived = builder.archived; + released = builder.released; + releaseDate = builder.releaseDate; + overdue = builder.overdue; + userReleaseDate = builder.userReleaseDate; + project = builder.project; + projectId = builder.projectId; + } + + public static Builder newBuilder() { + return new Builder(); + } + + @JsonPOJOBuilder(withPrefix = "") + public static final class Builder { + private String self; + @JsonSerialize(as = String.class) + private Long id; + private String description; + private String name; + private Boolean archived; + private Boolean released; + private LocalDate releaseDate; + private Boolean overdue; + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd/MMM/yy", + with = JsonFormat.Feature.ACCEPT_CASE_INSENSITIVE_VALUES) + private LocalDate userReleaseDate; + private String project; + private Long projectId; + + private Builder() { + } + + public Builder self(final String self) { + this.self = self; + return this; + } + + public Builder id(final Long id) { + this.id = id; + return this; + } + + public Builder description(final String description) { + this.description = description; + return this; + } + + public Builder name(final String name) { + this.name = name; + return this; + } + + public Builder archived(final Boolean archived) { + this.archived = archived; + return this; + } + + public Builder released(final Boolean released) { + this.released = released; + return this; + } + + public Builder releaseDate(final LocalDate releaseDate) { + this.releaseDate = releaseDate; + return this; + } + + public Builder overdue(final Boolean overdue) { + this.overdue = overdue; + return this; + } + + public Builder userReleaseDate(final LocalDate userReleaseDate) { + this.userReleaseDate = userReleaseDate; + return this; + } + + public Builder project(final String project) { + this.project = project; + return this; } - public static Builder newBuilder() { - return new Builder(); + public Builder projectId(final Long projectId) { + this.projectId = projectId; + return this; } - @JsonPOJOBuilder(withPrefix = "") - public static final class Builder { - private String self; - @JsonSerialize(as = String.class) - private Long id; - private String description; - private String name; - private Boolean archived; - private Boolean released; - private LocalDate releaseDate; - private Boolean overdue; - @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd/MMM/yy", - with = JsonFormat.Feature.ACCEPT_CASE_INSENSITIVE_VALUES) - private LocalDate userReleaseDate; - private String project; - private Long projectId; - - private Builder() {} - - public Builder self(final String self) { - this.self = self; - return this; - } - - public Builder id(final Long id) { - this.id = id; - return this; - } - - public Builder description(final String description) { - this.description = description; - return this; - } - - public Builder name(final String name) { - this.name = name; - return this; - } - - public Builder archived(final Boolean archived) { - this.archived = archived; - return this; - } - - public Builder released(final Boolean released) { - this.released = released; - return this; - } - - public Builder releaseDate(final LocalDate releaseDate) { - this.releaseDate = releaseDate; - return this; - } - - public Builder overdue(final Boolean overdue) { - this.overdue = overdue; - return this; - } - - public Builder userReleaseDate(final LocalDate userReleaseDate) { - this.userReleaseDate = userReleaseDate; - return this; - } - - public Builder project(final String project) { - this.project = project; - return this; - } - - public Builder projectId(final Long projectId) { - this.projectId = projectId; - return this; - } - - public VersionDto build() { - return new VersionDto(this); - } + public VersionDto build() { + return new VersionDto(this); } + } } diff --git a/src/main/java/com/frameworkium/core/common/reporting/jira/endpoint/JiraEndpoint.java b/src/main/java/com/frameworkium/core/common/reporting/jira/endpoint/JiraEndpoint.java index 94b6488e..85fa3f1a 100755 --- a/src/main/java/com/frameworkium/core/common/reporting/jira/endpoint/JiraEndpoint.java +++ b/src/main/java/com/frameworkium/core/common/reporting/jira/endpoint/JiraEndpoint.java @@ -4,32 +4,32 @@ import com.frameworkium.core.common.properties.Property; public enum JiraEndpoint implements Endpoint { - BASE_URI(Property.JIRA_URL.getValue()), - REST_API_PATH("/rest/api/2"), - PROJECT("/project"), - SEARCH("/search"), - ISSUE("/issue"), - ISSUELINK("/issueLink"), - FIELD("/field"), - VERSION("/version"); + BASE_URI(Property.JIRA_URL.getValue()), + REST_API_PATH("/rest/api/2"), + PROJECT("/project"), + SEARCH("/search"), + ISSUE("/issue"), + ISSUELINK("/issueLink"), + FIELD("/field"), + VERSION("/version"); - JiraEndpoint(String url) { - this.url = url; - } + private final String url; - private final String url; + JiraEndpoint(String url) { + this.url = url; + } - /** - * @param params Arguments referenced by the format specifiers in the url. - * @return A formatted String representing the URL of the given constant. - */ - @Override - public String getUrl(Object... params) { - if (url.equals(REST_API_PATH.url) || url.equals(BASE_URI.url)) { - return String.format(url, params); - } - // returns with the rest API path e.g. /rest/api/2/issue - String urlWithRestAPIPath = REST_API_PATH.url + url; - return String.format(urlWithRestAPIPath, params); + /** + * @param params Arguments referenced by the format specifiers in the url. + * @return A formatted String representing the URL of the given constant. + */ + @Override + public String getUrl(Object... params) { + if (url.equals(REST_API_PATH.url) || url.equals(BASE_URI.url)) { + return String.format(url, params); } + // returns with the rest API path e.g. /rest/api/2/issue + String urlWithRestAPIPath = REST_API_PATH.url + url; + return String.format(urlWithRestAPIPath, params); + } } diff --git a/src/main/java/com/frameworkium/core/common/reporting/jira/endpoint/ZephyrEndpoint.java b/src/main/java/com/frameworkium/core/common/reporting/jira/endpoint/ZephyrEndpoint.java index 1fd0a80d..1fd405d7 100755 --- a/src/main/java/com/frameworkium/core/common/reporting/jira/endpoint/ZephyrEndpoint.java +++ b/src/main/java/com/frameworkium/core/common/reporting/jira/endpoint/ZephyrEndpoint.java @@ -4,33 +4,33 @@ import com.frameworkium.core.common.properties.Property; public enum ZephyrEndpoint implements Endpoint { - BASE_URI(Property.JIRA_URL.getValue()), - REST_API_PATH("/rest/zapi/latest"), - EXECUTION("/execution"), - ADD_TEST_TO_EXECUTION("/execution/addTestsToCycle"), - EXECUTE_SEARCH("/zql/executeSearch"), - CYCLE("/cycle"), - ATTACHMENT("/attachment"), - ATTACHMENT_BY_ENTITY("/attachment/attachmentsByEntity"); + BASE_URI(Property.JIRA_URL.getValue()), + REST_API_PATH("/rest/zapi/latest"), + EXECUTION("/execution"), + ADD_TEST_TO_EXECUTION("/execution/addTestsToCycle"), + EXECUTE_SEARCH("/zql/executeSearch"), + CYCLE("/cycle"), + ATTACHMENT("/attachment"), + ATTACHMENT_BY_ENTITY("/attachment/attachmentsByEntity"); - private final String url; + private final String url; - ZephyrEndpoint(final String url) { - this.url = url; - } + ZephyrEndpoint(final String url) { + this.url = url; + } - /** - * @param params Arguments referenced by the format specifiers in the url. - * @return A formatted String representing the URL of the given constant. - */ - @Override - public String getUrl(Object... params) { - if (url.equals(REST_API_PATH.url) || url.equals(BASE_URI.url)) { - return url; - } - // returns with the rest API path e.g. /rest/api/2/issue - String urlWithRestAPIPath = REST_API_PATH.url + url; - return String.format(urlWithRestAPIPath, params); + /** + * @param params Arguments referenced by the format specifiers in the url. + * @return A formatted String representing the URL of the given constant. + */ + @Override + public String getUrl(Object... params) { + if (url.equals(REST_API_PATH.url) || url.equals(BASE_URI.url)) { + return url; } + // returns with the rest API path e.g. /rest/api/2/issue + String urlWithRestAPIPath = REST_API_PATH.url + url; + return String.format(urlWithRestAPIPath, params); + } } diff --git a/src/main/java/com/frameworkium/core/common/reporting/jira/service/AbstractJiraService.java b/src/main/java/com/frameworkium/core/common/reporting/jira/service/AbstractJiraService.java index 765fd484..d5456172 100644 --- a/src/main/java/com/frameworkium/core/common/reporting/jira/service/AbstractJiraService.java +++ b/src/main/java/com/frameworkium/core/common/reporting/jira/service/AbstractJiraService.java @@ -1,6 +1,8 @@ package com.frameworkium.core.common.reporting.jira.service; -import com.fasterxml.jackson.annotation.*; +import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.PropertyAccessor; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; @@ -14,37 +16,37 @@ import io.restassured.specification.ResponseSpecification; public abstract class AbstractJiraService extends BaseService { - @Override - protected RequestSpecification getRequestSpec() { - return RestAssured.given().log().ifValidationFails() - .baseUri(JiraEndpoint.BASE_URI.getUrl()) - .config(config()) - .relaxedHTTPSValidation() - .auth().preemptive().basic( - Property.JIRA_USERNAME.getValue(), - Property.JIRA_PASSWORD.getValue()); - } + @Override + protected RequestSpecification getRequestSpec() { + return RestAssured.given().log().ifValidationFails() + .baseUri(JiraEndpoint.BASE_URI.getUrl()) + .config(config()) + .relaxedHTTPSValidation() + .auth().preemptive().basic( + Property.JIRA_USERNAME.getValue(), + Property.JIRA_PASSWORD.getValue()); + } - @Override - protected ResponseSpecification getResponseSpec() { - throw new UnsupportedOperationException("Unimplemented"); - } + @Override + protected ResponseSpecification getResponseSpec() { + throw new UnsupportedOperationException("Unimplemented"); + } - private RestAssuredConfig config() { - return RestAssuredConfig.config().objectMapperConfig( - ObjectMapperConfig.objectMapperConfig().jackson2ObjectMapperFactory( - (type, s) -> { - final ObjectMapper objectMapper = new ObjectMapper(); - objectMapper.registerModule(new JavaTimeModule()); - objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); - objectMapper.setVisibility(PropertyAccessor.GETTER, JsonAutoDetect.Visibility.NONE); - objectMapper.setVisibility(PropertyAccessor.SETTER, JsonAutoDetect.Visibility.NONE); - objectMapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY); - objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); - return objectMapper; - } - ) - ); - } + private RestAssuredConfig config() { + return RestAssuredConfig.config().objectMapperConfig( + ObjectMapperConfig.objectMapperConfig().jackson2ObjectMapperFactory( + (type, s) -> { + final ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.registerModule(new JavaTimeModule()); + objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + objectMapper.setVisibility(PropertyAccessor.GETTER, JsonAutoDetect.Visibility.NONE); + objectMapper.setVisibility(PropertyAccessor.SETTER, JsonAutoDetect.Visibility.NONE); + objectMapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY); + objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); + return objectMapper; + } + ) + ); + } } diff --git a/src/main/java/com/frameworkium/core/common/reporting/jira/service/Attachment.java b/src/main/java/com/frameworkium/core/common/reporting/jira/service/Attachment.java index 2b3f223f..e906fafa 100755 --- a/src/main/java/com/frameworkium/core/common/reporting/jira/service/Attachment.java +++ b/src/main/java/com/frameworkium/core/common/reporting/jira/service/Attachment.java @@ -3,17 +3,17 @@ import java.util.List; public class Attachment extends AbstractJiraService { - private final Issue issue; + private final Issue issue; - public Attachment(Issue issue) { - this.issue = issue; - } + public Attachment(Issue issue) { + this.issue = issue; + } - /** - * Returns list of attachment IDs. - */ - public List getIds() { - return issue.getIssue().getList("fields.attachment.id"); - } + /** + * Returns list of attachment IDs. + */ + public List getIds() { + return issue.getIssue().getList("fields.attachment.id"); + } } diff --git a/src/main/java/com/frameworkium/core/common/reporting/jira/service/Issue.java b/src/main/java/com/frameworkium/core/common/reporting/jira/service/Issue.java index a56b9437..8a8e917f 100755 --- a/src/main/java/com/frameworkium/core/common/reporting/jira/service/Issue.java +++ b/src/main/java/com/frameworkium/core/common/reporting/jira/service/Issue.java @@ -1,160 +1,163 @@ package com.frameworkium.core.common.reporting.jira.service; +import static java.text.MessageFormat.format; + import com.frameworkium.core.common.reporting.jira.endpoint.JiraEndpoint; import io.restassured.http.ContentType; import io.restassured.path.json.JsonPath; +import java.io.File; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.json.*; - -import java.io.File; - -import static java.text.MessageFormat.format; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; public class Issue extends AbstractJiraService { - private static final Logger logger = LogManager.getLogger(); - public final String issueKey; - private static final String ISSUE_KEY = "issueKey"; - - public Issue(String issueKey) { - this.issueKey = issueKey; - } - - /** - * Returns a full representation of the issue for the given issue key. - * - * @return the full representation of the issue as JsonPath - */ - public JsonPath getIssue() { - return getRequestSpec().log().ifValidationFails() - .basePath(JiraEndpoint.ISSUE.getUrl()) - .when() - .get(issueKey) - .then().log().ifValidationFails() - .extract().jsonPath(); - } - - /** - * Edit a field in a JIRA issue - * - * @param fieldToUpdate the issue's field to update. Only editable field can be updated. - * Use /rest/api/2/issue/{issueIdOrKey}/editmeta to find out which - * @param resultValue the desired field value - */ - public void editField(String fieldToUpdate, String resultValue) { - JSONObject obj = new JSONObject(); - JSONObject fieldObj = new JSONObject(); - JSONArray setArr = new JSONArray(); - JSONObject setObj = new JSONObject(); - - try { - obj.put("update", fieldObj); - fieldObj.put(getFieldId(fieldToUpdate), setArr); - setArr.put(setObj); - setObj.put("set", resultValue); - - getRequestSpec().log().ifValidationFails() - .basePath(JiraEndpoint.ISSUE.getUrl()) - .contentType(ContentType.JSON).and() - .body(obj.toString()) - .when() - .put(issueKey) - .then().log().ifValidationFails(); - } catch (JSONException e) { - logger.error("Can't create JSON Object for test case result update", e); - } - } - - private String getFieldId(String fieldName) { - return getRequestSpec().log().ifValidationFails() - .basePath(JiraEndpoint.FIELD.getUrl()) - .contentType(ContentType.JSON).and() - .when() - .get() - .then().log().ifValidationFails() - .extract().jsonPath() - .getString(String.format("find {it.name == '%s'}.id", fieldName)); + private static final Logger logger = LogManager.getLogger(); + private static final String ISSUE_KEY = "issueKey"; + public final String issueKey; + + public Issue(String issueKey) { + this.issueKey = issueKey; + } + + /** + * Returns a full representation of the issue for the given issue key. + * + * @return the full representation of the issue as JsonPath + */ + public JsonPath getIssue() { + return getRequestSpec().log().ifValidationFails() + .basePath(JiraEndpoint.ISSUE.getUrl()) + .when() + .get(issueKey) + .then().log().ifValidationFails() + .extract().jsonPath(); + } + + /** + * Edit a field in a JIRA issue + * + * @param fieldToUpdate the issue's field to update. Only editable field can be updated. + * Use /rest/api/2/issue/{issueIdOrKey}/editmeta to find out which + * @param resultValue the desired field value + */ + public void editField(String fieldToUpdate, String resultValue) { + JSONObject obj = new JSONObject(); + JSONObject fieldObj = new JSONObject(); + JSONArray setArr = new JSONArray(); + JSONObject setObj = new JSONObject(); + + try { + obj.put("update", fieldObj); + fieldObj.put(getFieldId(fieldToUpdate), setArr); + setArr.put(setObj); + setObj.put("set", resultValue); + + getRequestSpec().log().ifValidationFails() + .basePath(JiraEndpoint.ISSUE.getUrl()) + .contentType(ContentType.JSON).and() + .body(obj.toString()) + .when() + .put(issueKey) + .then().log().ifValidationFails(); + } catch (JSONException e) { + logger.error("Can't create JSON Object for test case result update", e); } - - /** - * Add comment into a JIRA issue - * - * @param commentToAdd the comment to add - */ - public void addComment(String commentToAdd) { - JSONObject obj = new JSONObject(); - - try { - obj.put("body", commentToAdd); - getRequestSpec().log().ifValidationFails() - .basePath(JiraEndpoint.ISSUE.getUrl()) - .contentType(ContentType.JSON) - .pathParam(ISSUE_KEY, issueKey) - .body(obj.toString()) - .when() - .post("/{issueKey}/comment"); - } catch (JSONException e) { - logger.error("Can't create JSON Object for comment update", e); - } - } - - /** - * Perform a transition on an issue. When performing the transition you can update or set other issue fields. - * - * @param transitionName the name of the transition to perform on - */ - public void transition(String transitionName) { - logger.debug(() -> format("Transitioning - {0}", transitionName)); - transitionById(getTransitionId(transitionName)); + } + + private String getFieldId(String fieldName) { + return getRequestSpec().log().ifValidationFails() + .basePath(JiraEndpoint.FIELD.getUrl()) + .contentType(ContentType.JSON).and() + .when() + .get() + .then().log().ifValidationFails() + .extract().jsonPath() + .getString(String.format("find {it.name == '%s'}.id", fieldName)); + } + + /** + * Add comment into a JIRA issue + * + * @param commentToAdd the comment to add + */ + public void addComment(String commentToAdd) { + JSONObject obj = new JSONObject(); + + try { + obj.put("body", commentToAdd); + getRequestSpec().log().ifValidationFails() + .basePath(JiraEndpoint.ISSUE.getUrl()) + .contentType(ContentType.JSON) + .pathParam(ISSUE_KEY, issueKey) + .body(obj.toString()) + .when() + .post("/{issueKey}/comment"); + } catch (JSONException e) { + logger.error("Can't create JSON Object for comment update", e); } - - private void transitionById(String transitionId) { - JSONObject obj = new JSONObject(); - JSONObject idObj = new JSONObject(); - - try { - obj.put("transition", idObj); - idObj.put("id", transitionId); - logger.debug(() -> format("Transitioning using body - {0}", obj.toString())); - getRequestSpec().log().ifValidationFails() - .basePath(JiraEndpoint.ISSUE.getUrl()) - .contentType(ContentType.JSON).and() - .pathParam(ISSUE_KEY, issueKey) - .body(obj.toString()) - .when() - .post("/{issueKey}/transitions"); - } catch (JSONException e) { - logger.error("Can't create JSON Object for transition change", e); - } - } - - private String getTransitionId(String transitionName) { - String transitionId = getRequestSpec().log().ifValidationFails() - .basePath(JiraEndpoint.ISSUE.getUrl()) - .pathParam(ISSUE_KEY, issueKey) - .queryParam("expand", "transitions.fields") - .get("/{issueKey}/transitions").then().log().ifValidationFails() - .extract().jsonPath() - .getString(String.format( - "transitions.find {it -> it.name == '%s'}.id", transitionName)); - logger.debug(() -> format("Found id for transition named {1} - {0}", transitionId, transitionName)); - return transitionId; - } - - /** - * Add one or more attachments to an issue. - * - * @param attachment The file to attach - */ - public void addAttachment(File attachment) { - getRequestSpec().log().ifValidationFails() - .basePath(JiraEndpoint.ISSUE.getUrl()) - .pathParam(ISSUE_KEY, issueKey) - .header("X-Atlassian-Token", "nocheck") - .multiPart(attachment).and() - .when() - .post("/{issueKey}/attachments").then().log().ifValidationFails() - .extract().statusLine(); + } + + /** + * Perform a transition on an issue. When performing the transition you can update + * or set other issue fields. + * + * @param transitionName the name of the transition to perform on + */ + public void transition(String transitionName) { + logger.debug(() -> format("Transitioning - {0}", transitionName)); + transitionById(getTransitionId(transitionName)); + } + + private void transitionById(String transitionId) { + JSONObject obj = new JSONObject(); + JSONObject idObj = new JSONObject(); + + try { + obj.put("transition", idObj); + idObj.put("id", transitionId); + logger.debug(() -> format("Transitioning using body - {0}", obj.toString())); + getRequestSpec().log().ifValidationFails() + .basePath(JiraEndpoint.ISSUE.getUrl()) + .contentType(ContentType.JSON).and() + .pathParam(ISSUE_KEY, issueKey) + .body(obj.toString()) + .when() + .post("/{issueKey}/transitions"); + } catch (JSONException e) { + logger.error("Can't create JSON Object for transition change", e); } + } + + private String getTransitionId(String transitionName) { + String transitionId = getRequestSpec().log().ifValidationFails() + .basePath(JiraEndpoint.ISSUE.getUrl()) + .pathParam(ISSUE_KEY, issueKey) + .queryParam("expand", "transitions.fields") + .get("/{issueKey}/transitions").then().log().ifValidationFails() + .extract().jsonPath() + .getString(String.format( + "transitions.find {it -> it.name == '%s'}.id", transitionName)); + logger.debug( + () -> format("Found id for transition named {1} - {0}", transitionId, transitionName)); + return transitionId; + } + + /** + * Add one or more attachments to an issue. + * + * @param attachment The file to attach + */ + public void addAttachment(File attachment) { + getRequestSpec().log().ifValidationFails() + .basePath(JiraEndpoint.ISSUE.getUrl()) + .pathParam(ISSUE_KEY, issueKey) + .header("X-Atlassian-Token", "nocheck") + .multiPart(attachment).and() + .when() + .post("/{issueKey}/attachments").then().log().ifValidationFails() + .extract().statusLine(); + } } diff --git a/src/main/java/com/frameworkium/core/common/reporting/jira/service/IssueLink.java b/src/main/java/com/frameworkium/core/common/reporting/jira/service/IssueLink.java index 718baf17..b26a64d4 100755 --- a/src/main/java/com/frameworkium/core/common/reporting/jira/service/IssueLink.java +++ b/src/main/java/com/frameworkium/core/common/reporting/jira/service/IssueLink.java @@ -6,35 +6,35 @@ import org.json.JSONObject; public class IssueLink extends AbstractJiraService { - /** - * Creates an issue link between two issues. - * - * @param type name of issue - * @param inwardIssue inward issue key - * @param outwardIssue outward issue key - */ - public void linkIssues(String type, String inwardIssue, String outwardIssue) { - JSONObject obj = new JSONObject(); - JSONObject typeObj = new JSONObject(); - JSONObject inwardIssueObj = new JSONObject(); - JSONObject outwardIssueObj = new JSONObject(); + /** + * Creates an issue link between two issues. + * + * @param type name of issue + * @param inwardIssue inward issue key + * @param outwardIssue outward issue key + */ + public void linkIssues(String type, String inwardIssue, String outwardIssue) { + JSONObject obj = new JSONObject(); + JSONObject typeObj = new JSONObject(); + JSONObject inwardIssueObj = new JSONObject(); + JSONObject outwardIssueObj = new JSONObject(); - try { - obj.put("type", typeObj); - typeObj.put("name", type); - obj.put("inwardIssue", inwardIssueObj); - inwardIssueObj.put("key", inwardIssue); - obj.put("outwardIssue", outwardIssueObj); - outwardIssueObj.put("key", outwardIssue); - } catch (JSONException e) { - logger.error("Can't create JSON Object for linkIssues", e); - } - - getRequestSpec().log().ifValidationFails() - .basePath(JiraEndpoint.ISSUELINK.getUrl()) - .contentType(ContentType.JSON) - .body(obj.toString()) - .when() - .post(); + try { + obj.put("type", typeObj); + typeObj.put("name", type); + obj.put("inwardIssue", inwardIssueObj); + inwardIssueObj.put("key", inwardIssue); + obj.put("outwardIssue", outwardIssueObj); + outwardIssueObj.put("key", outwardIssue); + } catch (JSONException e) { + logger.error("Can't create JSON Object for linkIssues", e); } + + getRequestSpec().log().ifValidationFails() + .basePath(JiraEndpoint.ISSUELINK.getUrl()) + .contentType(ContentType.JSON) + .body(obj.toString()) + .when() + .post(); + } } diff --git a/src/main/java/com/frameworkium/core/common/reporting/jira/service/Project.java b/src/main/java/com/frameworkium/core/common/reporting/jira/service/Project.java index ab8feebe..0141b7b6 100644 --- a/src/main/java/com/frameworkium/core/common/reporting/jira/service/Project.java +++ b/src/main/java/com/frameworkium/core/common/reporting/jira/service/Project.java @@ -1,38 +1,37 @@ package com.frameworkium.core.common.reporting.jira.service; +import static org.apache.http.HttpStatus.SC_OK; + import com.frameworkium.core.common.reporting.jira.dto.project.ProjectDto; import com.frameworkium.core.common.reporting.jira.dto.version.VersionDto; import com.frameworkium.core.common.reporting.jira.endpoint.JiraEndpoint; import io.restassured.http.ContentType; - import java.util.List; -import static org.apache.http.HttpStatus.SC_OK; - public class Project extends AbstractJiraService { - public ProjectDto getProject(String projectIdOrKey) { - return getRequestSpec() - .basePath(JiraEndpoint.PROJECT.getUrl()) - .pathParam("projectIdOrKey", projectIdOrKey) - .contentType(ContentType.JSON) - .get("/{projectIdOrKey}") - .then() - .log().ifValidationFails() - .statusCode(SC_OK) - .extract() - .as(ProjectDto.class); - } + public ProjectDto getProject(String projectIdOrKey) { + return getRequestSpec() + .basePath(JiraEndpoint.PROJECT.getUrl()) + .pathParam("projectIdOrKey", projectIdOrKey) + .contentType(ContentType.JSON) + .get("/{projectIdOrKey}") + .then() + .log().ifValidationFails() + .statusCode(SC_OK) + .extract() + .as(ProjectDto.class); + } - public List getProjectVersions(String projectIdOrKey) { - return getRequestSpec() - .basePath(JiraEndpoint.PROJECT.getUrl()) - .pathParam("projectIdOrKey", projectIdOrKey) - .get("/{projectIdOrKey}/versions") - .then() - .log().ifValidationFails() - .statusCode(SC_OK) - .extract() - .body().jsonPath() - .getList("", VersionDto.class); - } + public List getProjectVersions(String projectIdOrKey) { + return getRequestSpec() + .basePath(JiraEndpoint.PROJECT.getUrl()) + .pathParam("projectIdOrKey", projectIdOrKey) + .get("/{projectIdOrKey}/versions") + .then() + .log().ifValidationFails() + .statusCode(SC_OK) + .extract() + .body().jsonPath() + .getList("", VersionDto.class); + } } diff --git a/src/main/java/com/frameworkium/core/common/reporting/jira/service/Search.java b/src/main/java/com/frameworkium/core/common/reporting/jira/service/Search.java index a91ecb2a..075c49db 100755 --- a/src/main/java/com/frameworkium/core/common/reporting/jira/service/Search.java +++ b/src/main/java/com/frameworkium/core/common/reporting/jira/service/Search.java @@ -2,34 +2,33 @@ import com.frameworkium.core.common.reporting.jira.endpoint.JiraEndpoint; import io.restassured.path.json.JsonPath; - import java.util.List; public class Search extends AbstractJiraService { - private static final int MAX_SEARCH_RESULTS = 1000; - protected JsonPath searchResults; + private static final int MAX_SEARCH_RESULTS = 1000; + protected JsonPath searchResults; - public Search(final String query) { - this(query, 0, MAX_SEARCH_RESULTS); - } + public Search(final String query) { + this(query, 0, MAX_SEARCH_RESULTS); + } - public Search(final String query, final int startAt, final int maxSearchResults) { - try { - this.searchResults = getRequestSpec().log().ifValidationFails() - .basePath(JiraEndpoint.SEARCH.getUrl()) - .param("jql", query) - .param("startAt", startAt) - .param("maxResults", maxSearchResults) - .when() - .get() - .then().log().ifValidationFails() - .extract().jsonPath(); - } catch (Exception e) { - logger.error("Unable to search for JIRA issue", e); - } + public Search(final String query, final int startAt, final int maxSearchResults) { + try { + this.searchResults = getRequestSpec().log().ifValidationFails() + .basePath(JiraEndpoint.SEARCH.getUrl()) + .param("jql", query) + .param("startAt", startAt) + .param("maxResults", maxSearchResults) + .when() + .get() + .then().log().ifValidationFails() + .extract().jsonPath(); + } catch (Exception e) { + logger.error("Unable to search for JIRA issue", e); } + } - public List getKeys() { - return searchResults.getList("issues.key"); - } + public List getKeys() { + return searchResults.getList("issues.key"); + } } diff --git a/src/main/java/com/frameworkium/core/common/reporting/jira/service/Version.java b/src/main/java/com/frameworkium/core/common/reporting/jira/service/Version.java index 3dce6a40..320c4fad 100644 --- a/src/main/java/com/frameworkium/core/common/reporting/jira/service/Version.java +++ b/src/main/java/com/frameworkium/core/common/reporting/jira/service/Version.java @@ -1,33 +1,33 @@ package com.frameworkium.core.common.reporting.jira.service; -import com.frameworkium.core.common.reporting.jira.dto.version.VersionDto; -import com.frameworkium.core.common.reporting.jira.endpoint.JiraEndpoint; - import static org.apache.http.HttpStatus.SC_CREATED; import static org.apache.http.HttpStatus.SC_OK; +import com.frameworkium.core.common.reporting.jira.dto.version.VersionDto; +import com.frameworkium.core.common.reporting.jira.endpoint.JiraEndpoint; + public class Version extends AbstractJiraService { - public VersionDto getVersion(String versionId) { - return getRequestSpec() - .basePath(JiraEndpoint.VERSION.getUrl()) - .pathParam("id", versionId) - .get("/{id}") - .then() - .log().ifValidationFails() - .statusCode(SC_OK) - .extract() - .as(VersionDto.class); - } + public VersionDto getVersion(String versionId) { + return getRequestSpec() + .basePath(JiraEndpoint.VERSION.getUrl()) + .pathParam("id", versionId) + .get("/{id}") + .then() + .log().ifValidationFails() + .statusCode(SC_OK) + .extract() + .as(VersionDto.class); + } - public VersionDto createVersion(VersionDto versionDto) { - return getRequestSpec() - .basePath(JiraEndpoint.VERSION.getUrl()) - .body(versionDto) - .post() - .then() - .log().ifValidationFails() - .statusCode(SC_CREATED) - .extract() - .as(VersionDto.class); - } + public VersionDto createVersion(VersionDto versionDto) { + return getRequestSpec() + .basePath(JiraEndpoint.VERSION.getUrl()) + .body(versionDto) + .post() + .then() + .log().ifValidationFails() + .statusCode(SC_CREATED) + .extract() + .as(VersionDto.class); + } } diff --git a/src/main/java/com/frameworkium/core/common/reporting/jira/util/ExecutionSearchUtil.java b/src/main/java/com/frameworkium/core/common/reporting/jira/util/ExecutionSearchUtil.java index a6cfab82..b6a5da0d 100755 --- a/src/main/java/com/frameworkium/core/common/reporting/jira/util/ExecutionSearchUtil.java +++ b/src/main/java/com/frameworkium/core/common/reporting/jira/util/ExecutionSearchUtil.java @@ -4,50 +4,49 @@ import com.frameworkium.core.common.reporting.jira.dto.executionsearch.ExecutionSearchDto; import com.frameworkium.core.common.reporting.jira.dto.executionsearch.ExecutionSearchListDto; import com.frameworkium.core.common.reporting.jira.zapi.ExecutionSearch; -import org.apache.commons.lang.StringUtils; - import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; +import org.apache.commons.lang.StringUtils; public class ExecutionSearchUtil { - private final ExecutionSearchListDto result; - - public ExecutionSearchUtil(String query) { - this(new ExecutionSearch(), query); - } - - public ExecutionSearchUtil(ExecutionSearch executionSearch, String query) { - this.result = executionSearch.search(query); - } - - /** - * Get a list of execution Ids optionally filtered by Property.ZAPI_CYCLE_REGEX - * - * @return a list of execution Ids - */ - public List getExecutionIdsByZAPICycleRegex() { - return getExecutionStream() - .map(e -> e.executionLightDto.id.intValue()) - .collect(Collectors.toList()); - } - - /** - * Get a list of execution status Ids optionally filtered by Property.ZAPI_CYCLE_REGEX - * - * @return a list of execution status Ids - */ - public List getExecutionStatusesByZAPICycleRegex() { - return getExecutionStream() - .map(e -> e.status.id.intValue()) - .collect(Collectors.toList()); - } - - private Stream getExecutionStream() { - if (StringUtils.isNotEmpty(Property.ZAPI_CYCLE_REGEX.getValue())) { - return result.executions.stream() - .filter(e -> e.executionLightDto.cycleName.equals(Property.ZAPI_CYCLE_REGEX.getValue())); - } - return result.executions.stream(); + private final ExecutionSearchListDto result; + + public ExecutionSearchUtil(String query) { + this(new ExecutionSearch(), query); + } + + public ExecutionSearchUtil(ExecutionSearch executionSearch, String query) { + this.result = executionSearch.search(query); + } + + /** + * Get a list of execution Ids optionally filtered by Property.ZAPI_CYCLE_REGEX + * + * @return a list of execution Ids + */ + public List getExecutionIdsByZAPICycleRegex() { + return getExecutionStream() + .map(e -> e.executionLightDto.id.intValue()) + .collect(Collectors.toList()); + } + + /** + * Get a list of execution status Ids optionally filtered by Property.ZAPI_CYCLE_REGEX + * + * @return a list of execution status Ids + */ + public List getExecutionStatusesByZAPICycleRegex() { + return getExecutionStream() + .map(e -> e.status.id.intValue()) + .collect(Collectors.toList()); + } + + private Stream getExecutionStream() { + if (StringUtils.isNotEmpty(Property.ZAPI_CYCLE_REGEX.getValue())) { + return result.executions.stream() + .filter(e -> e.executionLightDto.cycleName.equals(Property.ZAPI_CYCLE_REGEX.getValue())); } + return result.executions.stream(); + } } diff --git a/src/main/java/com/frameworkium/core/common/reporting/jira/util/ExecutionUtil.java b/src/main/java/com/frameworkium/core/common/reporting/jira/util/ExecutionUtil.java index 12ffd98b..d227dbcf 100755 --- a/src/main/java/com/frameworkium/core/common/reporting/jira/util/ExecutionUtil.java +++ b/src/main/java/com/frameworkium/core/common/reporting/jira/util/ExecutionUtil.java @@ -1,166 +1,171 @@ package com.frameworkium.core.common.reporting.jira.util; +import static org.apache.commons.lang3.StringUtils.isBlank; + import com.frameworkium.core.common.properties.Property; import com.frameworkium.core.common.reporting.jira.JiraConfig; import com.frameworkium.core.common.reporting.jira.dto.attachment.AttachmentListDto; -import com.frameworkium.core.common.reporting.jira.dto.execution.*; +import com.frameworkium.core.common.reporting.jira.dto.execution.ExecutionDto; +import com.frameworkium.core.common.reporting.jira.dto.execution.ExecutionLightDto; +import com.frameworkium.core.common.reporting.jira.dto.execution.UpdateExecutionOperationDto; import com.frameworkium.core.common.reporting.jira.zapi.Attachment; import com.frameworkium.core.common.reporting.jira.zapi.Execution; +import java.io.File; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; import org.apache.commons.lang3.StringUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.json.JSONException; import org.testng.ITestResult; -import java.io.File; -import java.util.*; - -import static org.apache.commons.lang3.StringUtils.isBlank; - public class ExecutionUtil { - private static final Logger logger = LogManager.getLogger(); - - private final String version; - private final String issue; - private List idList; - private int currentStatus; - private final ExecutionSearchUtil executionSearchUtil; - private final Execution execution; - private final Attachment attachment; - - /** - * Constructor that links an execution to an issue with default version - * from {@link com.frameworkium.core.common.properties.Property#RESULT_VERSION}. - * - * @param issue the target Issue to do operations on - */ - public ExecutionUtil(String issue) { - this(issue, Property.RESULT_VERSION.getValue()); - } - - /** - * Constructor that links an execution to an issue - * - * @param issue the target Issue to do operations on - * @param version the target Jira fixVersion to filter Issues with - */ - public ExecutionUtil(String issue, String version) { - this(new ExecutionSearchUtil(String.format( - "issue='%s' and fixVersion='%s'", issue, version)), - new Execution(), - new Attachment(), - issue, - version - ); + private static final Logger logger = LogManager.getLogger(); + + private final String version; + private final String issue; + private final ExecutionSearchUtil executionSearchUtil; + private final Execution execution; + private final Attachment attachment; + private List idList; + private int currentStatus; + + /** + * Constructor that links an execution to an issue with default version + * from {@link com.frameworkium.core.common.properties.Property#RESULT_VERSION}. + * + * @param issue the target Issue to do operations on + */ + public ExecutionUtil(String issue) { + this(issue, Property.RESULT_VERSION.getValue()); + } + + /** + * Constructor that links an execution to an issue + * + * @param issue the target Issue to do operations on + * @param version the target Jira fixVersion to filter Issues with + */ + public ExecutionUtil(String issue, String version) { + this(new ExecutionSearchUtil(String.format( + "issue='%s' and fixVersion='%s'", issue, version)), + new Execution(), + new Attachment(), + issue, + version + ); + } + + /** + * Constructor that links an execution to an issue + * + * @param executionSearchUtil a Jira Execution Search Utility instance + * @param execution a ZAPI execution instance + * @param attachment a ZAPI attachment instance + * @param issue the target Issue to do operations on + * @param version the target Jira fixVersion to filter Issues with + */ + public ExecutionUtil(final ExecutionSearchUtil executionSearchUtil, + final Execution execution, final Attachment attachment, + final String issue, final String version) { + this.executionSearchUtil = executionSearchUtil; + this.execution = execution; + this.attachment = attachment; + this.issue = issue; + this.version = version; + initExecutionIdsAndCurrentStatus(); + } + + /** + * Gets the ZAPI status of the TestNG status. + * + * @return ZAPI execution status from the ITestResult status + */ + public static int getZAPIStatus(int status) { + switch (status) { + case ITestResult.SUCCESS: + return JiraConfig.ZapiStatus.ZAPI_STATUS_PASS; + case ITestResult.FAILURE: + return JiraConfig.ZapiStatus.ZAPI_STATUS_FAIL; + case ITestResult.SKIP: + return JiraConfig.ZapiStatus.ZAPI_STATUS_BLOCKED; + default: + return JiraConfig.ZapiStatus.ZAPI_STATUS_FAIL; } + } - /** - * Constructor that links an execution to an issue - * - * @param executionSearchUtil a Jira Execution Search Utility instance - * @param execution a ZAPI execution instance - * @param attachment a ZAPI attachment instance - * @param issue the target Issue to do operations on - * @param version the target Jira fixVersion to filter Issues with - */ - public ExecutionUtil(final ExecutionSearchUtil executionSearchUtil, - final Execution execution, final Attachment attachment, - final String issue, final String version) { - this.executionSearchUtil = executionSearchUtil; - this.execution = execution; - this.attachment = attachment; - this.issue = issue; - this.version = version; - initExecutionIdsAndCurrentStatus(); + private void initExecutionIdsAndCurrentStatus() { + if (isBlank(version) || isBlank(issue)) { + return; } + idList = executionSearchUtil.getExecutionIdsByZAPICycleRegex(); - private void initExecutionIdsAndCurrentStatus() { - if (isBlank(version) || isBlank(issue)) { - return; - } - idList = executionSearchUtil.getExecutionIdsByZAPICycleRegex(); - - List statusList = executionSearchUtil.getExecutionStatusesByZAPICycleRegex(); - if (!statusList.isEmpty()) { - currentStatus = statusList.get(0); - } + List statusList = executionSearchUtil.getExecutionStatusesByZAPICycleRegex(); + if (!statusList.isEmpty()) { + currentStatus = statusList.get(0); } - - /** - * Gets the ZAPI status of the TestNG status. - * - * @return ZAPI execution status from the ITestResult status - */ - public static int getZAPIStatus(int status) { - switch (status) { - case ITestResult.SUCCESS: - return JiraConfig.ZapiStatus.ZAPI_STATUS_PASS; - case ITestResult.FAILURE: - return JiraConfig.ZapiStatus.ZAPI_STATUS_FAIL; - case ITestResult.SKIP: - return JiraConfig.ZapiStatus.ZAPI_STATUS_BLOCKED; - default: - return JiraConfig.ZapiStatus.ZAPI_STATUS_FAIL; - } + } + + public int getExecutionStatus() { + return currentStatus; + } + + /** + * Update issue with a comment and attachments. + */ + public void update(int status, String comment, String... attachments) { + if (idList == null) { + return; } + for (Integer executionId : idList) { + updateStatusAndComment(executionId, status, comment); + replaceExistingAttachments(executionId, attachments); - public int getExecutionStatus() { - return currentStatus; + logger.debug("ZAPI Updater - Updated {} to status {}", issue, status); } - - /** - * Update issue with a comment and attachments. - */ - public void update(int status, String comment, String... attachments) { - if (idList == null) { - return; - } - for (Integer executionId : idList) { - updateStatusAndComment(executionId, status, comment); - replaceExistingAttachments(executionId, attachments); - - logger.debug("ZAPI Updater - Updated {} to status {}", issue, status); - } - } - - private void updateStatusAndComment(Integer executionId, int status, String comment) { - try { - int commentMaxLen = 750; - final UpdateExecutionOperationDto updateExecutionOperationDto = UpdateExecutionOperationDto.newBuilder() - .status(status) - .executionDto(ExecutionDto.newBuilder() - .executionLightDto(ExecutionLightDto.newBuilder() - .comment(StringUtils.abbreviate(comment, commentMaxLen)) - .build()) - .build()) - .build(); - execution.updateExecutionDetails(updateExecutionOperationDto, executionId); - } catch (JSONException e) { - logger.error("Update status and comment failed", e); - } - } - - private void replaceExistingAttachments(Integer executionId, String... attachments) { - if (attachments != null) { - deleteExistingAttachments(executionId); - addAttachments(executionId, attachments); - } - } - - private void deleteExistingAttachments(Integer executionId) { - final AttachmentListDto executionListDto = attachment.getAttachmentByEntity(executionId, "EXECUTION"); - executionListDto.data.stream() - .map(a -> a.fileId) - .map(Long::parseLong) - .forEach(attachment::deleteAttachment); + } + + private void updateStatusAndComment(Integer executionId, int status, String comment) { + try { + int commentMaxLen = 750; + final UpdateExecutionOperationDto updateExecutionOperationDto = + UpdateExecutionOperationDto.newBuilder() + .status(status) + .executionDto(ExecutionDto.newBuilder() + .executionLightDto(ExecutionLightDto.newBuilder() + .comment(StringUtils.abbreviate(comment, commentMaxLen)) + .build()) + .build()) + .build(); + execution.updateExecutionDetails(updateExecutionOperationDto, executionId); + } catch (JSONException e) { + logger.error("Update status and comment failed", e); } + } - private void addAttachments(Integer executionId, String... attachments) { - Arrays.stream(attachments) - .filter(Objects::nonNull) - .map(File::new) - .forEach(file -> - attachment.addAttachments(executionId, "EXECUTION", file)); + private void replaceExistingAttachments(Integer executionId, String... attachments) { + if (attachments != null) { + deleteExistingAttachments(executionId); + addAttachments(executionId, attachments); } + } + + private void deleteExistingAttachments(Integer executionId) { + final AttachmentListDto executionListDto = + attachment.getAttachmentByEntity(executionId, "EXECUTION"); + executionListDto.data.stream() + .map(a -> a.fileId) + .map(Long::parseLong) + .forEach(attachment::deleteAttachment); + } + + private void addAttachments(Integer executionId, String... attachments) { + Arrays.stream(attachments) + .filter(Objects::nonNull) + .map(File::new) + .forEach(file -> + attachment.addAttachments(executionId, "EXECUTION", file)); + } } diff --git a/src/main/java/com/frameworkium/core/common/reporting/jira/zapi/Attachment.java b/src/main/java/com/frameworkium/core/common/reporting/jira/zapi/Attachment.java index 8301066d..5a160b17 100755 --- a/src/main/java/com/frameworkium/core/common/reporting/jira/zapi/Attachment.java +++ b/src/main/java/com/frameworkium/core/common/reporting/jira/zapi/Attachment.java @@ -1,46 +1,45 @@ package com.frameworkium.core.common.reporting.jira.zapi; +import static org.apache.http.HttpStatus.SC_OK; + import com.frameworkium.core.common.reporting.jira.dto.attachment.AttachmentListDto; import com.frameworkium.core.common.reporting.jira.endpoint.ZephyrEndpoint; import com.frameworkium.core.common.reporting.jira.service.AbstractJiraService; - import java.io.File; -import static org.apache.http.HttpStatus.SC_OK; - public class Attachment extends AbstractJiraService { - public AttachmentListDto getAttachmentByEntity(Integer entityId, String entityType) { - return getRequestSpec() - .basePath(ZephyrEndpoint.ATTACHMENT_BY_ENTITY.getUrl()) - .queryParam("entityId", entityId) - .queryParam("entityType", entityType) - .when() - .get() - .then().log().ifValidationFails() - .extract() - .as(AttachmentListDto.class); - } + public AttachmentListDto getAttachmentByEntity(Integer entityId, String entityType) { + return getRequestSpec() + .basePath(ZephyrEndpoint.ATTACHMENT_BY_ENTITY.getUrl()) + .queryParam("entityId", entityId) + .queryParam("entityType", entityType) + .when() + .get() + .then().log().ifValidationFails() + .extract() + .as(AttachmentListDto.class); + } - public void deleteAttachment(Long id) { - getRequestSpec() - .basePath(ZephyrEndpoint.ATTACHMENT.getUrl()) - .pathParam("id", id) - .when() - .delete("/{id}") - .then().log().ifValidationFails() - .statusCode(SC_OK); - } + public void deleteAttachment(Long id) { + getRequestSpec() + .basePath(ZephyrEndpoint.ATTACHMENT.getUrl()) + .pathParam("id", id) + .when() + .delete("/{id}") + .then().log().ifValidationFails() + .statusCode(SC_OK); + } - public void addAttachments(Integer entityId, String entityType, File file) { - getRequestSpec() - .basePath(ZephyrEndpoint.ATTACHMENT.getUrl()) - .queryParam("entityId", entityId) - .queryParam("entityType", entityType) - .header("X-Atlassian-Token", "nocheck") - .multiPart(file) - .when() - .post() - .then().log().ifValidationFails() - .statusCode(SC_OK); - } + public void addAttachments(Integer entityId, String entityType, File file) { + getRequestSpec() + .basePath(ZephyrEndpoint.ATTACHMENT.getUrl()) + .queryParam("entityId", entityId) + .queryParam("entityType", entityType) + .header("X-Atlassian-Token", "nocheck") + .multiPart(file) + .when() + .post() + .then().log().ifValidationFails() + .statusCode(SC_OK); + } } diff --git a/src/main/java/com/frameworkium/core/common/reporting/jira/zapi/Cycle.java b/src/main/java/com/frameworkium/core/common/reporting/jira/zapi/Cycle.java index 66f35361..390a5361 100644 --- a/src/main/java/com/frameworkium/core/common/reporting/jira/zapi/Cycle.java +++ b/src/main/java/com/frameworkium/core/common/reporting/jira/zapi/Cycle.java @@ -1,33 +1,35 @@ package com.frameworkium.core.common.reporting.jira.zapi; -import com.frameworkium.core.common.reporting.jira.dto.cycle.*; +import static org.apache.http.HttpStatus.SC_OK; + +import com.frameworkium.core.common.reporting.jira.dto.cycle.CreateCycleSuccessDto; +import com.frameworkium.core.common.reporting.jira.dto.cycle.CreateNewCycleDto; +import com.frameworkium.core.common.reporting.jira.dto.cycle.CycleListDto; import com.frameworkium.core.common.reporting.jira.endpoint.ZephyrEndpoint; import com.frameworkium.core.common.reporting.jira.service.AbstractJiraService; -import static org.apache.http.HttpStatus.SC_OK; - public class Cycle extends AbstractJiraService { - public CycleListDto getListOfCycle(Long projectId, Long versionId) { - return getRequestSpec() - .basePath(ZephyrEndpoint.CYCLE.getUrl()) - .queryParam("projectId", projectId) - .queryParam("versionId", versionId) - .get() - .then() - .log().ifValidationFails() - .statusCode(SC_OK) - .extract().body() - .as(CycleListDto.class); - } + public CycleListDto getListOfCycle(Long projectId, Long versionId) { + return getRequestSpec() + .basePath(ZephyrEndpoint.CYCLE.getUrl()) + .queryParam("projectId", projectId) + .queryParam("versionId", versionId) + .get() + .then() + .log().ifValidationFails() + .statusCode(SC_OK) + .extract().body() + .as(CycleListDto.class); + } - public CreateCycleSuccessDto createNewCycle(CreateNewCycleDto createNewCycleDto) { - return getRequestSpec() - .basePath(ZephyrEndpoint.CYCLE.getUrl()) - .body(createNewCycleDto) - .post() - .then() - .log().ifValidationFails() - .extract() - .as(CreateCycleSuccessDto.class); - } + public CreateCycleSuccessDto createNewCycle(CreateNewCycleDto createNewCycleDto) { + return getRequestSpec() + .basePath(ZephyrEndpoint.CYCLE.getUrl()) + .body(createNewCycleDto) + .post() + .then() + .log().ifValidationFails() + .extract() + .as(CreateCycleSuccessDto.class); + } } diff --git a/src/main/java/com/frameworkium/core/common/reporting/jira/zapi/Execution.java b/src/main/java/com/frameworkium/core/common/reporting/jira/zapi/Execution.java index 01a10a7a..05113d25 100644 --- a/src/main/java/com/frameworkium/core/common/reporting/jira/zapi/Execution.java +++ b/src/main/java/com/frameworkium/core/common/reporting/jira/zapi/Execution.java @@ -1,35 +1,36 @@ package com.frameworkium.core.common.reporting.jira.zapi; +import static org.apache.http.HttpStatus.SC_OK; + import com.frameworkium.core.common.reporting.jira.dto.execution.AddTestToCycleOperationDto; import com.frameworkium.core.common.reporting.jira.dto.execution.UpdateExecutionOperationDto; import com.frameworkium.core.common.reporting.jira.endpoint.ZephyrEndpoint; import com.frameworkium.core.common.reporting.jira.service.AbstractJiraService; -import static org.apache.http.HttpStatus.SC_OK; - public class Execution extends AbstractJiraService { - public String addTestsToCycle(AddTestToCycleOperationDto addTestToCycleOperationDto) { - return getRequestSpec() - .basePath(ZephyrEndpoint.ADD_TEST_TO_EXECUTION.getUrl()) - .body(addTestToCycleOperationDto) - .post() - .then() - .log().ifValidationFails() - .statusCode(SC_OK) - .extract() - .asString(); //gets a jobprogresstoken - } + public String addTestsToCycle(AddTestToCycleOperationDto addTestToCycleOperationDto) { + return getRequestSpec() + .basePath(ZephyrEndpoint.ADD_TEST_TO_EXECUTION.getUrl()) + .body(addTestToCycleOperationDto) + .post() + .then() + .log().ifValidationFails() + .statusCode(SC_OK) + .extract() + .asString(); //gets a jobprogresstoken + } - public String updateExecutionDetails(UpdateExecutionOperationDto updateExecutionOperationDto, Integer id) { - return getRequestSpec() - .basePath(ZephyrEndpoint.EXECUTION.getUrl()) - .pathParam("id", id) - .body(updateExecutionOperationDto) - .put("/{id}/execute") - .then() - .log().ifValidationFails() - .statusCode(SC_OK) - .extract() - .asString(); // get a success token - } + public String updateExecutionDetails(UpdateExecutionOperationDto updateExecutionOperationDto, + Integer id) { + return getRequestSpec() + .basePath(ZephyrEndpoint.EXECUTION.getUrl()) + .pathParam("id", id) + .body(updateExecutionOperationDto) + .put("/{id}/execute") + .then() + .log().ifValidationFails() + .statusCode(SC_OK) + .extract() + .asString(); // get a success token + } } diff --git a/src/main/java/com/frameworkium/core/common/reporting/jira/zapi/ExecutionSearch.java b/src/main/java/com/frameworkium/core/common/reporting/jira/zapi/ExecutionSearch.java index deff3adb..b8a11f53 100755 --- a/src/main/java/com/frameworkium/core/common/reporting/jira/zapi/ExecutionSearch.java +++ b/src/main/java/com/frameworkium/core/common/reporting/jira/zapi/ExecutionSearch.java @@ -6,32 +6,32 @@ import io.restassured.specification.RequestSpecification; public class ExecutionSearch extends AbstractJiraService { - public ExecutionSearchListDto search(String zqlQuery) { - return search(zqlQuery, null, null, null, null); - } - - public ExecutionSearchListDto search( - String zqlQuery, Integer filterId, Integer offset, Integer maxRecords, String expand) { - RequestSpecification reqspec = getRequestSpec() - .basePath(ZephyrEndpoint.EXECUTE_SEARCH.getUrl()) - .queryParam("zqlQuery", zqlQuery); + public ExecutionSearchListDto search(String zqlQuery) { + return search(zqlQuery, null, null, null, null); + } - if (filterId != null) { - reqspec.queryParam("filterId", filterId); - } - if (offset != null) { - reqspec.queryParam("offset", offset); - } - if (maxRecords != null) { - reqspec.queryParam("maxRecords", maxRecords); - } - if (expand != null) { - reqspec.queryParam("expand", expand); - } + public ExecutionSearchListDto search( + String zqlQuery, Integer filterId, Integer offset, Integer maxRecords, String expand) { + RequestSpecification reqspec = getRequestSpec() + .basePath(ZephyrEndpoint.EXECUTE_SEARCH.getUrl()) + .queryParam("zqlQuery", zqlQuery); - return reqspec.when() - .get().then().log().ifValidationFails() - .extract() - .as(ExecutionSearchListDto.class); + if (filterId != null) { + reqspec.queryParam("filterId", filterId); + } + if (offset != null) { + reqspec.queryParam("offset", offset); } + if (maxRecords != null) { + reqspec.queryParam("maxRecords", maxRecords); + } + if (expand != null) { + reqspec.queryParam("expand", expand); + } + + return reqspec.when() + .get().then().log().ifValidationFails() + .extract() + .as(ExecutionSearchListDto.class); + } } diff --git a/src/main/java/com/frameworkium/core/common/reporting/spira/SpiraConfig.java b/src/main/java/com/frameworkium/core/common/reporting/spira/SpiraConfig.java index c430063c..b16e115a 100644 --- a/src/main/java/com/frameworkium/core/common/reporting/spira/SpiraConfig.java +++ b/src/main/java/com/frameworkium/core/common/reporting/spira/SpiraConfig.java @@ -2,17 +2,18 @@ public class SpiraConfig { - public static final String USERNAME = "administrator"; - public static final String API_KEY = "{750AE393-737C-434E-A3AB-0FF2D0476E3C}"; - public static final String REST_PATH = "/Services/v4_0/RestService.svc/projects/2"; + public static final String USERNAME = "administrator"; + public static final String API_KEY = "{750AE393-737C-434E-A3AB-0FF2D0476E3C}"; + public static final String REST_PATH = "/Services/v4_0/RestService.svc/projects/2"; - public static class SpiraStatus { - public static final int SPIRA_STATUS_PASS = 2; - public static final int SPIRA_STATUS_FAIL = 1; - public static final int SPIRA_STATUS_WIP = 4; - public static final int SPIRA_STATUS_BLOCKED = 5; - } + private SpiraConfig() { + } - private SpiraConfig() {} + public static class SpiraStatus { + public static final int SPIRA_STATUS_PASS = 2; + public static final int SPIRA_STATUS_FAIL = 1; + public static final int SPIRA_STATUS_WIP = 4; + public static final int SPIRA_STATUS_BLOCKED = 5; + } } diff --git a/src/main/java/com/frameworkium/core/common/reporting/spira/SpiraExecution.java b/src/main/java/com/frameworkium/core/common/reporting/spira/SpiraExecution.java index 12d9ca7d..5714b7be 100644 --- a/src/main/java/com/frameworkium/core/common/reporting/spira/SpiraExecution.java +++ b/src/main/java/com/frameworkium/core/common/reporting/spira/SpiraExecution.java @@ -1,7 +1,11 @@ package com.frameworkium.core.common.reporting.spira; +import static io.restassured.RestAssured.given; + import com.frameworkium.core.common.properties.Property; import io.restassured.RestAssured; +import java.io.IOException; +import java.io.UnsupportedEncodingException; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.CloseableHttpClient; @@ -12,84 +16,79 @@ import org.json.JSONObject; import org.testng.ITestResult; -import java.io.IOException; -import java.io.UnsupportedEncodingException; - -import static io.restassured.RestAssured.given; - public class SpiraExecution { - private static final Logger logger = LogManager.getLogger(); + private static final Logger logger = LogManager.getLogger(); - private static final String SPIRA_URI = - Property.SPIRA_URL.getValue() + SpiraConfig.REST_PATH; + private static final String SPIRA_URI = + Property.SPIRA_URL.getValue() + SpiraConfig.REST_PATH; - /** - * Record test result. - */ - public void recordTestResult(String issue, int resultId, String comment, ITestResult result) { + /** + * Record test result. + */ + public void recordTestResult(String issue, int resultId, String comment, ITestResult result) { - JSONObject obj = new JSONObject(); - try { - obj.put("ExecutionStatusId", 0); - obj.put("StartDate", "\\/Date(" + result.getStartMillis() + ")\\/"); - obj.put("TestCaseId", issue.replaceAll("[^0-9]", "")); - obj.put("TestRunTypeId", 0); - obj.put("TestRunFormatId", 0); - obj.put("ExecutionStatusId", resultId); - obj.put("RunnerName", "Frameworkium"); - obj.put("RunnerTestName", result.getMethod().getMethodName()); - obj.put("RunnerStackTrace", comment); + JSONObject obj = new JSONObject(); + try { + obj.put("ExecutionStatusId", 0); + obj.put("StartDate", "\\/Date(" + result.getStartMillis() + ")\\/"); + obj.put("TestCaseId", issue.replaceAll("[^0-9]", "")); + obj.put("TestRunTypeId", 0); + obj.put("TestRunFormatId", 0); + obj.put("ExecutionStatusId", resultId); + obj.put("RunnerName", "Frameworkium"); + obj.put("RunnerTestName", result.getMethod().getMethodName()); + obj.put("RunnerStackTrace", comment); - if (Property.RESULT_VERSION.isSpecified()) { - obj.put("ReleaseId", getReleaseId(Property.RESULT_VERSION.getValue())); - } - //"Name":null, - //"BuildId":null, - //"RunnerMessage":null, - } catch (JSONException e) { - logger.error("Update status and comment failed", e); - } + if (Property.RESULT_VERSION.isSpecified()) { + obj.put("ReleaseId", getReleaseId(Property.RESULT_VERSION.getValue())); + } + //"Name":null, + //"BuildId":null, + //"RunnerMessage":null, + } catch (JSONException e) { + logger.error("Update status and comment failed", e); + } - //JSONObject auto-escapes the backslash, so we need to unescape it! - String json = obj.toString().replace("\\\\", "\\"); + //JSONObject auto-escapes the backslash, so we need to unescape it! + String json = obj.toString().replace("\\\\", "\\"); - // TODO: use RestAssured - CloseableHttpClient httpClient = HttpClientBuilder.create().build(); - HttpPost request = new HttpPost(SPIRA_URI + "/test-runs/record?" - + "username=" + SpiraConfig.USERNAME + "&" - + "api-key=" + SpiraConfig.API_KEY.replace("{", "%7B").replace("}", "%7D")); - StringEntity jsonBody; - try { - jsonBody = new StringEntity(json); - request.addHeader("content-type", "application/json"); - request.setEntity(jsonBody); - } catch (UnsupportedEncodingException e) { - logger.warn(e); - } + // TODO: use RestAssured + CloseableHttpClient httpClient = HttpClientBuilder.create().build(); + HttpPost request = new HttpPost(SPIRA_URI + "/test-runs/record?" + + "username=" + SpiraConfig.USERNAME + "&" + + "api-key=" + SpiraConfig.API_KEY.replace("{", "%7B").replace("}", "%7D")); + StringEntity jsonBody; + try { + jsonBody = new StringEntity(json); + request.addHeader("content-type", "application/json"); + request.setEntity(jsonBody); + } catch (UnsupportedEncodingException e) { + logger.warn(e); + } - try { - httpClient.execute(request); - } catch (IOException e) { - logger.warn(e); - } + try { + httpClient.execute(request); + } catch (IOException e) { + logger.warn(e); } + } - /** - * Get release ID. - */ - public String getReleaseId(String releaseName) { - RestAssured.baseURI = SPIRA_URI; - String path = String.format( - "find {it.FullName == '%s'}.ReleaseId", releaseName); + /** + * Get release ID. + */ + public String getReleaseId(String releaseName) { + RestAssured.baseURI = SPIRA_URI; + String path = String.format( + "find {it.FullName == '%s'}.ReleaseId", releaseName); - return given().contentType("application/json") - .param("username", SpiraConfig.USERNAME) - .param("api-key", SpiraConfig.API_KEY) - .when() - .get("/releases") - .thenReturn().jsonPath() - .getString(path); - } + return given().contentType("application/json") + .param("username", SpiraConfig.USERNAME) + .param("api-key", SpiraConfig.API_KEY) + .when() + .get("/releases") + .thenReturn().jsonPath() + .getString(path); + } } diff --git a/src/main/java/com/frameworkium/core/common/retry/RetryFlakyTest.java b/src/main/java/com/frameworkium/core/common/retry/RetryFlakyTest.java index ff5ea79a..1f5ed845 100644 --- a/src/main/java/com/frameworkium/core/common/retry/RetryFlakyTest.java +++ b/src/main/java/com/frameworkium/core/common/retry/RetryFlakyTest.java @@ -6,14 +6,16 @@ public class RetryFlakyTest implements IRetryAnalyzer { - /** Maximum retry count of failed tests, defaults to 1. */ - static final int MAX_RETRY_COUNT = - Property.MAX_RETRY_COUNT.getIntWithDefault(1); + /** + * Maximum retry count of failed tests, defaults to 1. + */ + static final int MAX_RETRY_COUNT = + Property.MAX_RETRY_COUNT.getIntWithDefault(1); - private int retryCount = 0; + private int retryCount = 0; - @Override - public boolean retry(ITestResult result) { - return retryCount++ < MAX_RETRY_COUNT; - } + @Override + public boolean retry(ITestResult result) { + return retryCount++ < MAX_RETRY_COUNT; + } } \ No newline at end of file diff --git a/src/main/java/com/frameworkium/core/htmlelements/annotations/Timeout.java b/src/main/java/com/frameworkium/core/htmlelements/annotations/Timeout.java index 7826a269..2abb246d 100755 --- a/src/main/java/com/frameworkium/core/htmlelements/annotations/Timeout.java +++ b/src/main/java/com/frameworkium/core/htmlelements/annotations/Timeout.java @@ -1,6 +1,9 @@ package com.frameworkium.core.htmlelements.annotations; -import java.lang.annotation.*; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; /** * Annotation that is used for setting waiting timeout value, @@ -23,5 +26,5 @@ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE, ElementType.FIELD}) public @interface Timeout { - int value(); + int value(); } diff --git a/src/main/java/com/frameworkium/core/htmlelements/element/Button.java b/src/main/java/com/frameworkium/core/htmlelements/element/Button.java index 16e353d7..0ed7170c 100755 --- a/src/main/java/com/frameworkium/core/htmlelements/element/Button.java +++ b/src/main/java/com/frameworkium/core/htmlelements/element/Button.java @@ -2,15 +2,17 @@ import org.openqa.selenium.WebElement; -/** Represents web page button control. */ +/** + * Represents web page button control. + */ public class Button extends TypifiedElement { - /** - * Specifies wrapped {@link WebElement}. - * - * @param wrappedElement {@code WebElement} to wrap. - */ - public Button(WebElement wrappedElement) { - super(wrappedElement); - } + /** + * Specifies wrapped {@link WebElement}. + * + * @param wrappedElement {@code WebElement} to wrap. + */ + public Button(WebElement wrappedElement) { + super(wrappedElement); + } } diff --git a/src/main/java/com/frameworkium/core/htmlelements/element/CheckBox.java b/src/main/java/com/frameworkium/core/htmlelements/element/CheckBox.java index 7de94dd1..0fb083fc 100755 --- a/src/main/java/com/frameworkium/core/htmlelements/element/CheckBox.java +++ b/src/main/java/com/frameworkium/core/htmlelements/element/CheckBox.java @@ -1,72 +1,81 @@ package com.frameworkium.core.htmlelements.element; -import org.openqa.selenium.*; - import java.util.Optional; +import org.openqa.selenium.By; +import org.openqa.selenium.NoSuchElementException; +import org.openqa.selenium.WebElement; -/** Represents checkbox control. */ +/** + * Represents checkbox control. + */ public class CheckBox extends TypifiedElement { - /** - * Specifies wrapped {@link WebElement}. - * - * @param wrappedElement {@code WebElement} to wrap. - */ - public CheckBox(WebElement wrappedElement) { - super(wrappedElement); - } + /** + * Specifies wrapped {@link WebElement}. + * + * @param wrappedElement {@code WebElement} to wrap. + */ + public CheckBox(WebElement wrappedElement) { + super(wrappedElement); + } - /** - * Finds label corresponding to this checkbox using "following-sibling::label" xpath. - * - * @return Optional of the {@code WebElement} representing label - */ - public Optional getLabel() { - try { - return Optional.of(getWrappedElement().findElement(By.xpath("following-sibling::label"))); - } catch (NoSuchElementException e) { - return Optional.empty(); - } + /** + * Finds label corresponding to this checkbox using "following-sibling::label" xpath. + * + * @return Optional of the {@code WebElement} representing label + */ + public Optional getLabel() { + try { + return Optional.of(getWrappedElement().findElement(By.xpath("following-sibling::label"))); + } catch (NoSuchElementException e) { + return Optional.empty(); } + } - /** - * Finds the text of the checkbox label. - * - * @return Optional of the label text - */ - public Optional getLabelText() { - return getLabel().map(WebElement::getText); - } + /** + * Finds the text of the checkbox label. + * + * @return Optional of the label text + */ + public Optional getLabelText() { + return getLabel().map(WebElement::getText); + } - /** - * The same as {@link #getLabelText()}. - * - * @return Text of the checkbox label or {@code null} if no label has been found. - */ - public String getText() { - return getLabelText().orElse(""); - } + /** + * The same as {@link #getLabelText()}. + * + * @return Text of the checkbox label or {@code null} if no label has been found. + */ + public String getText() { + return getLabelText().orElse(""); + } - /** Selects checkbox if it is not already selected. */ - public void select() { - if (!isSelected()) { - getWrappedElement().click(); - } + /** + * Selects checkbox if it is not already selected. + */ + public void select() { + if (!isSelected()) { + getWrappedElement().click(); } + } - /** Deselects checkbox if it is not already deselected. */ - public void deselect() { - if (isSelected()) { - getWrappedElement().click(); - } + /** + * Deselects checkbox if it is not already deselected. + */ + public void deselect() { + if (isSelected()) { + getWrappedElement().click(); } + } - /** Selects checkbox if passed value is {@code true} and deselects otherwise. */ - public void set(boolean value) { - if (value) { - select(); - } else { - deselect(); - } + /** + * Selects checkbox if passed value is {@code true} and deselects otherwise. + */ + public void set(boolean value) { + if (value) { + select(); + } else { + deselect(); } + } } diff --git a/src/main/java/com/frameworkium/core/htmlelements/element/FileInput.java b/src/main/java/com/frameworkium/core/htmlelements/element/FileInput.java index 9135d873..2b20773c 100755 --- a/src/main/java/com/frameworkium/core/htmlelements/element/FileInput.java +++ b/src/main/java/com/frameworkium/core/htmlelements/element/FileInput.java @@ -1,101 +1,107 @@ package com.frameworkium.core.htmlelements.element; +import static com.frameworkium.core.htmlelements.utils.HtmlElementUtils.existsInClasspath; +import static com.frameworkium.core.htmlelements.utils.HtmlElementUtils.getResourceFromClasspath; + import com.frameworkium.core.common.properties.Property; import com.frameworkium.core.ui.UITestLifecycle; -import org.openqa.selenium.*; -import org.openqa.selenium.remote.*; -import org.openqa.selenium.support.events.EventFiringWebDriver; - import java.io.File; import java.util.List; import java.util.stream.Collectors; +import org.openqa.selenium.By; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.remote.LocalFileDetector; +import org.openqa.selenium.remote.RemoteWebDriver; +import org.openqa.selenium.remote.RemoteWebElement; +import org.openqa.selenium.support.events.EventFiringWebDriver; -import static com.frameworkium.core.htmlelements.utils.HtmlElementUtils.*; - -/** Represents web page file upload element. */ +/** + * Represents web page file upload element. + */ public class FileInput extends TypifiedElement { - /** - * Specifies wrapped {@link WebElement}. - * - * @param wrappedElement {@code WebElement} to wrap. - */ - public FileInput(WebElement wrappedElement) { - super(wrappedElement); - } - - /** - * Sets a file to be uploaded. - *

- * File is searched in the following way: if a resource with a specified name exists in classpath, - * then this resource will be used, otherwise file will be searched on file system. - * - * @param fileName Name of a file or a resource to be uploaded. - */ - public void setFileToUpload(final String fileName) { - // Set local file detector in case of remote driver usage - setLocalFileDetectorIfRequired(); - - String filePath = getFilePath(fileName); - sendKeys(filePath); - } - - /** - * Sets multiple files to be uploaded. - *

- * Files are searched in the following way: - * if a resource with a specified name exists in classpath, - * then this resource will be used, otherwise file will be searched on file system. - * - * @param fileNames a list of file Names to be uploaded. - */ - public void setFilesToUpload(List fileNames) { - // Set local file detector in case of remote driver usage - setLocalFileDetectorIfRequired(); - - String filePaths = fileNames.stream() - .map(this::getFilePath) - .collect(Collectors.joining("\n")); - sendKeys(filePaths); + /** + * Specifies wrapped {@link WebElement}. + * + * @param wrappedElement {@code WebElement} to wrap. + */ + public FileInput(WebElement wrappedElement) { + super(wrappedElement); + } + + /** + * Sets a file to be uploaded. + *

+ * File is searched in the following way: if a resource with a specified name exists in classpath, + * then this resource will be used, otherwise file will be searched on file system. + * + * @param fileName Name of a file or a resource to be uploaded. + */ + public void setFileToUpload(final String fileName) { + // Set local file detector in case of remote driver usage + setLocalFileDetectorIfRequired(); + + String filePath = getFilePath(fileName); + sendKeys(filePath); + } + + /** + * Sets multiple files to be uploaded. + *

+ * Files are searched in the following way: + * if a resource with a specified name exists in classpath, + * then this resource will be used, otherwise file will be searched on file system. + * + * @param fileNames a list of file Names to be uploaded. + */ + public void setFilesToUpload(List fileNames) { + // Set local file detector in case of remote driver usage + setLocalFileDetectorIfRequired(); + + String filePaths = fileNames.stream() + .map(this::getFilePath) + .collect(Collectors.joining("\n")); + sendKeys(filePaths); + } + + private void setLocalFileDetectorIfRequired() { + if (Property.GRID_URL.isSpecified()) { + WebDriver webDriver = UITestLifecycle.get().getWebDriver(); + EventFiringWebDriver efDriver = (EventFiringWebDriver) webDriver; + RemoteWebDriver remoteDriver = (RemoteWebDriver) efDriver.getWrappedDriver(); + remoteDriver.setFileDetector(new LocalFileDetector()); } - - private void setLocalFileDetectorIfRequired() { - if (Property.GRID_URL.isSpecified()) { - WebDriver webDriver = UITestLifecycle.get().getWebDriver(); - EventFiringWebDriver efDriver = (EventFiringWebDriver) webDriver; - RemoteWebDriver remoteDriver = (RemoteWebDriver) efDriver.getWrappedDriver(); - remoteDriver.setFileDetector(new LocalFileDetector()); - } - } - - /** - * Submits selected file by simply submitting the whole form, which contains this file input. - */ - public void submit() { - getWrappedElement().submit(); + } + + /** + * Submits selected file by simply submitting the whole form, which contains this file input. + */ + public void submit() { + getWrappedElement().submit(); + } + + private WebElement getNotProxiedInputElement() { + return getWrappedElement().findElement(By.xpath(".")); + } + + private void setLocalFileDetector(RemoteWebElement element) { + element.setFileDetector(new LocalFileDetector()); + } + + private String getFilePath(final String fileName) { + if (existsInClasspath(fileName)) { + return getPathForResource(fileName); } + return getPathForSystemFile(fileName); + } - private WebElement getNotProxiedInputElement() { - return getWrappedElement().findElement(By.xpath(".")); - } - - private void setLocalFileDetector(RemoteWebElement element) { - element.setFileDetector(new LocalFileDetector()); - } + private String getPathForResource(final String fileName) { + return getResourceFromClasspath(fileName).getPath(); + } - private String getFilePath(final String fileName) { - if (existsInClasspath(fileName)) { - return getPathForResource(fileName); - } - return getPathForSystemFile(fileName); - } - - private String getPathForResource(final String fileName) { - return getResourceFromClasspath(fileName).getPath(); - } - - private String getPathForSystemFile(final String fileName) { - File file = new File(fileName); - return file.getPath(); - } + private String getPathForSystemFile(final String fileName) { + File file = new File(fileName); + return file.getPath(); + } } diff --git a/src/main/java/com/frameworkium/core/htmlelements/element/Form.java b/src/main/java/com/frameworkium/core/htmlelements/element/Form.java index 75318a08..02e0d9b5 100755 --- a/src/main/java/com/frameworkium/core/htmlelements/element/Form.java +++ b/src/main/java/com/frameworkium/core/htmlelements/element/Form.java @@ -1,115 +1,117 @@ package com.frameworkium.core.htmlelements.element; +import static java.util.Objects.isNull; + +import java.util.AbstractMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; import org.openqa.selenium.By; import org.openqa.selenium.WebElement; -import java.util.*; - -import static java.util.Objects.isNull; - /** * Represents web page form tag. * Provides handy way of filling form with data and submitting it. */ public class Form extends TypifiedElement { - private static final String CHECKBOX_FIELD = "checkbox"; - private static final String RADIO_FIELD = "radio"; - private static final String SELECT_FIELD = "select"; - private static final String INPUT_FIELD = "input"; - private static final String FILE_FIELD = "file"; - - /** - * Specifies {@link WebElement} representing form tag. - * - * @param wrappedElement {@code WebElement} to wrap. - */ - public Form(WebElement wrappedElement) { - super(wrappedElement); - } - - /** - * Fills form with data contained in passed map. - * For each map entry if an input with a name coincident with entry key exists - * it is filled with string representation of entry value. - * If an input with such a name is not found the corresponding entry is skipped. - * - * @param data Map containing data to fill form inputs with. - */ - public void fill(Map data) { - data.entrySet().stream() - .map(e -> new AbstractMap.SimpleEntry<>( - findElementByKey(e.getKey()), - Objects.toString(e.getValue(), ""))) - .filter(e -> !isNull(e.getKey())) - .forEach(e -> fillElement(e.getKey(), e.getValue())); - } - - protected WebElement findElementByKey(String key) { - List elements = getWrappedElement().findElements(By.name(key)); - if (elements.isEmpty()) { - return null; - } else { - return elements.get(0); - } + private static final String CHECKBOX_FIELD = "checkbox"; + private static final String RADIO_FIELD = "radio"; + private static final String SELECT_FIELD = "select"; + private static final String INPUT_FIELD = "input"; + private static final String FILE_FIELD = "file"; + + /** + * Specifies {@link WebElement} representing form tag. + * + * @param wrappedElement {@code WebElement} to wrap. + */ + public Form(WebElement wrappedElement) { + super(wrappedElement); + } + + /** + * Fills form with data contained in passed map. + * For each map entry if an input with a name coincident with entry key exists + * it is filled with string representation of entry value. + * If an input with such a name is not found the corresponding entry is skipped. + * + * @param data Map containing data to fill form inputs with. + */ + public void fill(Map data) { + data.entrySet().stream() + .map(e -> new AbstractMap.SimpleEntry<>( + findElementByKey(e.getKey()), + Objects.toString(e.getValue(), ""))) + .filter(e -> !isNull(e.getKey())) + .forEach(e -> fillElement(e.getKey(), e.getValue())); + } + + protected WebElement findElementByKey(String key) { + List elements = getWrappedElement().findElements(By.name(key)); + if (elements.isEmpty()) { + return null; + } else { + return elements.get(0); } - - protected void fillElement(WebElement element, String value) { - String elementType = getElementType(element); - - if (CHECKBOX_FIELD.equals(elementType)) { - fillCheckBox(element, value); - } else if (RADIO_FIELD.equals(elementType)) { - fillRadio(element, value); - } else if (INPUT_FIELD.equals(elementType)) { - fillInput(element, value); - } else if (SELECT_FIELD.equals(elementType)) { - fillSelect(element, value); - } else if (FILE_FIELD.equals(elementType)) { - fillFile(element, value); - } + } + + protected void fillElement(WebElement element, String value) { + String elementType = getElementType(element); + + if (CHECKBOX_FIELD.equals(elementType)) { + fillCheckBox(element, value); + } else if (RADIO_FIELD.equals(elementType)) { + fillRadio(element, value); + } else if (INPUT_FIELD.equals(elementType)) { + fillInput(element, value); + } else if (SELECT_FIELD.equals(elementType)) { + fillSelect(element, value); + } else if (FILE_FIELD.equals(elementType)) { + fillFile(element, value); } - - protected String getElementType(WebElement element) { - String tagName = element.getTagName(); - if ("input".equals(tagName)) { - String type = element.getAttribute("type"); - if ("checkbox".equals(type)) { - return CHECKBOX_FIELD; - } else if ("radio".equals(type)) { - return RADIO_FIELD; - } else if ("file".equals(type)) { - return FILE_FIELD; - } else { - return INPUT_FIELD; - } - } else if ("select".equals(tagName)) { - return SELECT_FIELD; - } else if ("textarea".equals(tagName)) { - return INPUT_FIELD; - } else { - return null; - } + } + + protected String getElementType(WebElement element) { + String tagName = element.getTagName(); + if ("input".equals(tagName)) { + String type = element.getAttribute("type"); + if ("checkbox".equals(type)) { + return CHECKBOX_FIELD; + } else if ("radio".equals(type)) { + return RADIO_FIELD; + } else if ("file".equals(type)) { + return FILE_FIELD; + } else { + return INPUT_FIELD; + } + } else if ("select".equals(tagName)) { + return SELECT_FIELD; + } else if ("textarea".equals(tagName)) { + return INPUT_FIELD; + } else { + return null; } + } - protected void fillCheckBox(WebElement element, String value) { - new CheckBox(element).set(Boolean.parseBoolean(value)); - } + protected void fillCheckBox(WebElement element, String value) { + new CheckBox(element).set(Boolean.parseBoolean(value)); + } - protected void fillRadio(WebElement element, String value) { - new Radio(element).selectByValue(value); - } + protected void fillRadio(WebElement element, String value) { + new Radio(element).selectByValue(value); + } - protected void fillInput(WebElement element, String value) { - TextInput input = new TextInput(element); - input.sendKeys(input.getClearCharSequence() + value); - } + protected void fillInput(WebElement element, String value) { + TextInput input = new TextInput(element); + input.sendKeys(input.getClearCharSequence() + value); + } - protected void fillSelect(WebElement element, String value) { - new Select(element).selectByValue(value); - } + protected void fillSelect(WebElement element, String value) { + new Select(element).selectByValue(value); + } - protected void fillFile(WebElement element, String value) { - new FileInput(element).setFileToUpload(value); - } + protected void fillFile(WebElement element, String value) { + new FileInput(element).setFileToUpload(value); + } } diff --git a/src/main/java/com/frameworkium/core/htmlelements/element/HtmlElement.java b/src/main/java/com/frameworkium/core/htmlelements/element/HtmlElement.java index 2b2da1e4..30de1085 100755 --- a/src/main/java/com/frameworkium/core/htmlelements/element/HtmlElement.java +++ b/src/main/java/com/frameworkium/core/htmlelements/element/HtmlElement.java @@ -1,8 +1,15 @@ package com.frameworkium.core.htmlelements.element; -import org.openqa.selenium.*; - import java.util.List; +import org.openqa.selenium.By; +import org.openqa.selenium.Dimension; +import org.openqa.selenium.NoSuchElementException; +import org.openqa.selenium.OutputType; +import org.openqa.selenium.Point; +import org.openqa.selenium.Rectangle; +import org.openqa.selenium.WebDriverException; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.WrapsElement; /** * The base class to be used for making blocks of elements. @@ -41,125 +48,125 @@ * {@code WebElements} where necessary. */ public class HtmlElement implements WebElement, WrapsElement { - private WebElement wrappedElement; - - @Override - public WebElement getWrappedElement() { - return wrappedElement; - } - - /** - * Sets the wrapped {@code WebElement}. This method is used by - * initialization mechanism and is not intended to be used directly. - * - * @param wrappedElement {@code WebElement} to wrap. - */ - public void setWrappedElement(WebElement wrappedElement) { - this.wrappedElement = wrappedElement; - } - - /** - * Determines whether or not this element exists on page. - * - * @return True if the element exists on page, false otherwise. - */ - public boolean exists() { - try { - getWrappedElement().isDisplayed(); - } catch (NoSuchElementException ignored) { - return false; - } - return true; - } - - @Override - public void click() { - wrappedElement.click(); - } - - /** - * If this element is a form, or an element within a form, then this will - * submit this form to the remote server. - * - * @see WebElement#submit() - */ - @Override - public void submit() { - wrappedElement.submit(); - } - - @Override - public void sendKeys(CharSequence... charSequences) { - wrappedElement.sendKeys(charSequences); - } - - @Override - public void clear() { - wrappedElement.clear(); - } - - @Override - public String getTagName() { - return wrappedElement.getTagName(); - } - - @Override - public String getAttribute(String name) { - return wrappedElement.getAttribute(name); - } - - @Override - public boolean isSelected() { - return wrappedElement.isSelected(); - } - - @Override - public boolean isEnabled() { - return wrappedElement.isEnabled(); - } - - @Override - public String getText() { - return wrappedElement.getText(); - } - - @Override - public List findElements(By by) { - return wrappedElement.findElements(by); - } - - @Override - public WebElement findElement(By by) { - return wrappedElement.findElement(by); - } - - @Override - public boolean isDisplayed() { - return wrappedElement.isDisplayed(); - } - - @Override - public Point getLocation() { - return wrappedElement.getLocation(); - } - - @Override - public Dimension getSize() { - return wrappedElement.getSize(); - } - - @Override - public Rectangle getRect() { - return wrappedElement.getRect(); - } - - @Override - public String getCssValue(String name) { - return wrappedElement.getCssValue(name); - } - - @Override - public X getScreenshotAs(OutputType outputType) throws WebDriverException { - return wrappedElement.getScreenshotAs(outputType); - } + private WebElement wrappedElement; + + @Override + public WebElement getWrappedElement() { + return wrappedElement; + } + + /** + * Sets the wrapped {@code WebElement}. This method is used by + * initialization mechanism and is not intended to be used directly. + * + * @param wrappedElement {@code WebElement} to wrap. + */ + public void setWrappedElement(WebElement wrappedElement) { + this.wrappedElement = wrappedElement; + } + + /** + * Determines whether or not this element exists on page. + * + * @return True if the element exists on page, false otherwise. + */ + public boolean exists() { + try { + getWrappedElement().isDisplayed(); + } catch (NoSuchElementException ignored) { + return false; + } + return true; + } + + @Override + public void click() { + wrappedElement.click(); + } + + /** + * If this element is a form, or an element within a form, then this will + * submit this form to the remote server. + * + * @see WebElement#submit() + */ + @Override + public void submit() { + wrappedElement.submit(); + } + + @Override + public void sendKeys(CharSequence... charSequences) { + wrappedElement.sendKeys(charSequences); + } + + @Override + public void clear() { + wrappedElement.clear(); + } + + @Override + public String getTagName() { + return wrappedElement.getTagName(); + } + + @Override + public String getAttribute(String name) { + return wrappedElement.getAttribute(name); + } + + @Override + public boolean isSelected() { + return wrappedElement.isSelected(); + } + + @Override + public boolean isEnabled() { + return wrappedElement.isEnabled(); + } + + @Override + public String getText() { + return wrappedElement.getText(); + } + + @Override + public List findElements(By by) { + return wrappedElement.findElements(by); + } + + @Override + public WebElement findElement(By by) { + return wrappedElement.findElement(by); + } + + @Override + public boolean isDisplayed() { + return wrappedElement.isDisplayed(); + } + + @Override + public Point getLocation() { + return wrappedElement.getLocation(); + } + + @Override + public Dimension getSize() { + return wrappedElement.getSize(); + } + + @Override + public Rectangle getRect() { + return wrappedElement.getRect(); + } + + @Override + public String getCssValue(String name) { + return wrappedElement.getCssValue(name); + } + + @Override + public X getScreenshotAs(OutputType outputType) throws WebDriverException { + return wrappedElement.getScreenshotAs(outputType); + } } diff --git a/src/main/java/com/frameworkium/core/htmlelements/element/Image.java b/src/main/java/com/frameworkium/core/htmlelements/element/Image.java index bfd64010..85ef555d 100755 --- a/src/main/java/com/frameworkium/core/htmlelements/element/Image.java +++ b/src/main/java/com/frameworkium/core/htmlelements/element/Image.java @@ -2,29 +2,31 @@ import org.openqa.selenium.WebElement; -/** Represents an image {@code } */ +/** + * Represents an image {@code } + */ public class Image extends TypifiedElement { - public Image(WebElement wrappedElement) { - super(wrappedElement); - } + public Image(WebElement wrappedElement) { + super(wrappedElement); + } - /** - * Retrieves path to image from "src" attribute - * - * @return Path to the image - */ - public String getSource() { - return getWrappedElement().getAttribute("src"); - } + /** + * Retrieves path to image from "src" attribute + * + * @return Path to the image + */ + public String getSource() { + return getWrappedElement().getAttribute("src"); + } - /** - * Retrieves alternative text from "alt" attribute - * - * @return alternative text for image - */ - public String getAlt() { - return getWrappedElement().getAttribute("alt"); - } + /** + * Retrieves alternative text from "alt" attribute + * + * @return alternative text for image + */ + public String getAlt() { + return getWrappedElement().getAttribute("alt"); + } } diff --git a/src/main/java/com/frameworkium/core/htmlelements/element/Link.java b/src/main/java/com/frameworkium/core/htmlelements/element/Link.java index 9147f247..986bc9aa 100755 --- a/src/main/java/com/frameworkium/core/htmlelements/element/Link.java +++ b/src/main/java/com/frameworkium/core/htmlelements/element/Link.java @@ -2,19 +2,21 @@ import org.openqa.selenium.WebElement; -/** Represents an anchor tag/hyperlink. */ +/** + * Represents an anchor tag/hyperlink. + */ public class Link extends TypifiedElement { - public Link(WebElement wrappedElement) { - super(wrappedElement); - } + public Link(WebElement wrappedElement) { + super(wrappedElement); + } - /** - * Retrieves reference from "href" attribute. - * - * @return Reference associated with hyperlink. - */ - public String getReference() { - return getWrappedElement().getAttribute("href"); - } + /** + * Retrieves reference from "href" attribute. + * + * @return Reference associated with hyperlink. + */ + public String getReference() { + return getWrappedElement().getAttribute("href"); + } } diff --git a/src/main/java/com/frameworkium/core/htmlelements/element/Radio.java b/src/main/java/com/frameworkium/core/htmlelements/element/Radio.java index e96781de..1ae8f24b 100755 --- a/src/main/java/com/frameworkium/core/htmlelements/element/Radio.java +++ b/src/main/java/com/frameworkium/core/htmlelements/element/Radio.java @@ -1,97 +1,100 @@ package com.frameworkium.core.htmlelements.element; -import org.openqa.selenium.*; - import java.util.List; import java.util.Optional; +import org.openqa.selenium.By; +import org.openqa.selenium.NoSuchElementException; +import org.openqa.selenium.WebElement; -/** Represents a group of radio buttons. */ +/** + * Represents a group of radio buttons. + */ public class Radio extends TypifiedElement { - /** - * Specifies a radio button of a radio button group that will be used - * to find all other buttons of this group. - * - * @param wrappedElement {@code WebElement} representing radio button. - */ - public Radio(WebElement wrappedElement) { - super(wrappedElement); - } - - /** - * Returns all radio buttons belonging to this group. - * - * @return A list of {@code WebElements} representing radio buttons. - */ - public List getButtons() { - String radioName = getWrappedElement().getAttribute("name"); + /** + * Specifies a radio button of a radio button group that will be used + * to find all other buttons of this group. + * + * @param wrappedElement {@code WebElement} representing radio button. + */ + public Radio(WebElement wrappedElement) { + super(wrappedElement); + } - String xpath; - if (radioName == null) { - xpath = "self::* | following::input[@type = 'radio'] | preceding::input[@type = 'radio']"; - } else { - xpath = String.format( - "self::* | following::input[@type = 'radio' and @name = '%s'] | " - + "preceding::input[@type = 'radio' and @name = '%s']", - radioName, radioName); - } + /** + * Returns all radio buttons belonging to this group. + * + * @return A list of {@code WebElements} representing radio buttons. + */ + public List getButtons() { + String radioName = getWrappedElement().getAttribute("name"); - return getWrappedElement().findElements(By.xpath(xpath)); + String xpath; + if (radioName == null) { + xpath = "self::* | following::input[@type = 'radio'] | preceding::input[@type = 'radio']"; + } else { + xpath = String.format( + "self::* | following::input[@type = 'radio' and @name = '%s'] | " + + "preceding::input[@type = 'radio' and @name = '%s']", + radioName, radioName); } - /** - * Returns selected radio button. - * - * @return Optional {@code WebElement} representing selected radio button. - */ - public Optional getSelectedButton() { - return getButtons().stream() - .filter(WebElement::isSelected) - .findAny(); - } + return getWrappedElement().findElements(By.xpath(xpath)); + } - /** - * Indicates if radio group has selected button. - * - * @return {@code true} if radio has selected button and {@code false} otherwise. - */ - public boolean hasSelectedButton() { - return getButtons().stream() - .anyMatch(WebElement::isSelected); - } + /** + * Returns selected radio button. + * + * @return Optional {@code WebElement} representing selected radio button. + */ + public Optional getSelectedButton() { + return getButtons().stream() + .filter(WebElement::isSelected) + .findAny(); + } - /** - * Selects first radio button that has a value matching the specified argument. - * - * @param value The value to match against. - */ - public void selectByValue(String value) { - WebElement matchingButton = getButtons().stream() - .filter(b -> value.equals(b.getAttribute("value"))) - .findFirst() - .orElseThrow(() -> new NoSuchElementException( - String.format("Cannot locate radio button with value: %s", value))); + /** + * Indicates if radio group has selected button. + * + * @return {@code true} if radio has selected button and {@code false} otherwise. + */ + public boolean hasSelectedButton() { + return getButtons().stream() + .anyMatch(WebElement::isSelected); + } - selectButton(matchingButton); - } + /** + * Selects first radio button that has a value matching the specified argument. + * + * @param value The value to match against. + */ + public void selectByValue(String value) { + WebElement matchingButton = getButtons().stream() + .filter(b -> value.equals(b.getAttribute("value"))) + .findFirst() + .orElseThrow(() -> new NoSuchElementException( + String.format("Cannot locate radio button with value: %s", value))); - /** - * Selects a radio button by the given index. - * - * @param index Index of a radio button to be selected. - */ - public void selectByIndex(int index) { - selectButton(getButtons().get(index)); - } + selectButton(matchingButton); + } + + /** + * Selects a radio button by the given index. + * + * @param index Index of a radio button to be selected. + */ + public void selectByIndex(int index) { + selectButton(getButtons().get(index)); + } - /** - * Selects a radio button if it's not already selected. - * - * @param button {@code WebElement} representing radio button to be selected. - */ - private void selectButton(WebElement button) { - if (!button.isSelected()) { - button.click(); - } + /** + * Selects a radio button if it's not already selected. + * + * @param button {@code WebElement} representing radio button to be selected. + */ + private void selectButton(WebElement button) { + if (!button.isSelected()) { + button.click(); } + } } diff --git a/src/main/java/com/frameworkium/core/htmlelements/element/Select.java b/src/main/java/com/frameworkium/core/htmlelements/element/Select.java index 31e52e88..902cc381 100755 --- a/src/main/java/com/frameworkium/core/htmlelements/element/Select.java +++ b/src/main/java/com/frameworkium/core/htmlelements/element/Select.java @@ -1,10 +1,9 @@ package com.frameworkium.core.htmlelements.element; +import java.util.List; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.ui.ISelect; -import java.util.List; - /** * Represents a select control. *

@@ -17,77 +16,77 @@ */ public class Select extends TypifiedElement implements ISelect { - /** - * Specifies wrapped {@link WebElement}. - * Performs no checks unlike {@link org.openqa.selenium.support.ui.Select}. - * All checks are made later in {@link #getSelect()} method. - * - * @param wrappedElement {@code WebElement} to wrap. - */ - public Select(WebElement wrappedElement) { - super(wrappedElement); - } - - /** - * Constructs instance of {@link org.openqa.selenium.support.ui.Select} class. - * - * @return {@link org.openqa.selenium.support.ui.Select} class instance. - */ - private org.openqa.selenium.support.ui.Select getSelect() { - return new org.openqa.selenium.support.ui.Select(getWrappedElement()); - } - - public boolean isMultiple() { - return getSelect().isMultiple(); - } - - public List getOptions() { - return getSelect().getOptions(); - } - - public List getAllSelectedOptions() { - return getSelect().getAllSelectedOptions(); - } - - public WebElement getFirstSelectedOption() { - return getSelect().getFirstSelectedOption(); - } - - /** - * Indicates if select has at least one selected option. - * - * @return {@code true} if select has at least one selected option and - * {@code false} otherwise. - */ - public boolean hasSelectedOption() { - return getOptions().stream().anyMatch(WebElement::isSelected); - } - - public void selectByVisibleText(String text) { - getSelect().selectByVisibleText(text); - } - - public void selectByIndex(int index) { - getSelect().selectByIndex(index); - } - - public void selectByValue(String value) { - getSelect().selectByValue(value); - } - - public void deselectAll() { - getSelect().deselectAll(); - } - - public void deselectByValue(String value) { - getSelect().deselectByValue(value); - } - - public void deselectByIndex(int index) { - getSelect().deselectByIndex(index); - } - - public void deselectByVisibleText(String text) { - getSelect().deselectByVisibleText(text); - } + /** + * Specifies wrapped {@link WebElement}. + * Performs no checks unlike {@link org.openqa.selenium.support.ui.Select}. + * All checks are made later in {@link #getSelect()} method. + * + * @param wrappedElement {@code WebElement} to wrap. + */ + public Select(WebElement wrappedElement) { + super(wrappedElement); + } + + /** + * Constructs instance of {@link org.openqa.selenium.support.ui.Select} class. + * + * @return {@link org.openqa.selenium.support.ui.Select} class instance. + */ + private org.openqa.selenium.support.ui.Select getSelect() { + return new org.openqa.selenium.support.ui.Select(getWrappedElement()); + } + + public boolean isMultiple() { + return getSelect().isMultiple(); + } + + public List getOptions() { + return getSelect().getOptions(); + } + + public List getAllSelectedOptions() { + return getSelect().getAllSelectedOptions(); + } + + public WebElement getFirstSelectedOption() { + return getSelect().getFirstSelectedOption(); + } + + /** + * Indicates if select has at least one selected option. + * + * @return {@code true} if select has at least one selected option and + * {@code false} otherwise. + */ + public boolean hasSelectedOption() { + return getOptions().stream().anyMatch(WebElement::isSelected); + } + + public void selectByVisibleText(String text) { + getSelect().selectByVisibleText(text); + } + + public void selectByIndex(int index) { + getSelect().selectByIndex(index); + } + + public void selectByValue(String value) { + getSelect().selectByValue(value); + } + + public void deselectAll() { + getSelect().deselectAll(); + } + + public void deselectByValue(String value) { + getSelect().deselectByValue(value); + } + + public void deselectByIndex(int index) { + getSelect().deselectByIndex(index); + } + + public void deselectByVisibleText(String text) { + getSelect().deselectByVisibleText(text); + } } diff --git a/src/main/java/com/frameworkium/core/htmlelements/element/Table.java b/src/main/java/com/frameworkium/core/htmlelements/element/Table.java index 7a0f7ce7..48e543e7 100755 --- a/src/main/java/com/frameworkium/core/htmlelements/element/Table.java +++ b/src/main/java/com/frameworkium/core/htmlelements/element/Table.java @@ -1,14 +1,15 @@ package com.frameworkium.core.htmlelements.element; -import org.openqa.selenium.By; -import org.openqa.selenium.WebElement; - -import java.util.*; - import static java.util.function.Function.identity; import static java.util.stream.Collectors.toList; import static java.util.stream.Collectors.toMap; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import org.openqa.selenium.By; +import org.openqa.selenium.WebElement; + /** * Represents a simple table element. * Provides convenient ways of retrieving data stored in it. @@ -19,167 +20,167 @@ */ public class Table extends TypifiedElement { - /** - * Specifies {@link WebElement} representing table tag. - * - * @param wrappedElement {@code WebElement} to wrap. - */ - public Table(WebElement wrappedElement) { - super(wrappedElement); - } - - /** - * Returns a list of table heading elements ({@code }). - *

- * Multiple rows of heading elements, ({@code }), are flattened - * i.e. the second row, ({@code }), will follow the first, which can be - * misleading when the table uses {@code colspan} and {@code rowspan}. - * - * @return List with table heading elements. - */ - public List getHeadings() { - return getWrappedElement().findElements(By.xpath(".//th")); - } - - /** - * Returns text values of table heading elements (contained in "th" tags). - * - * @return List with text values of table heading elements. - */ - public List getHeadingsAsString() { - return getHeadings().stream() - .map(WebElement::getText) - .collect(toList()); - } - - /** - * Returns table cell elements ({@code }), grouped by rows. - * - * @return List where each item is a table row. - */ - public List> getRows() { - return getWrappedElement() - .findElements(By.xpath(".//tr")) - .stream() - .map(rowElement -> rowElement.findElements(By.xpath(".//td"))) - .filter(row -> row.size() > 0) // ignore rows with no tags - .collect(toList()); - } - - /** - * Returns text values of table cell elements ({@code }), grouped by rows. - * - * @return List where each item is text values of a table row. - */ - public List> getRowsAsString() { - return getRows().stream() - .map(row -> row.stream() - .map(WebElement::getText) - .collect(toList())) - .collect(toList()); + /** + * Specifies {@link WebElement} representing table tag. + * + * @param wrappedElement {@code WebElement} to wrap. + */ + public Table(WebElement wrappedElement) { + super(wrappedElement); + } + + /** + * Returns a list of table heading elements ({@code }). + *

+ * Multiple rows of heading elements, ({@code }), are flattened + * i.e. the second row, ({@code }), will follow the first, which can be + * misleading when the table uses {@code colspan} and {@code rowspan}. + * + * @return List with table heading elements. + */ + public List getHeadings() { + return getWrappedElement().findElements(By.xpath(".//th")); + } + + /** + * Returns text values of table heading elements (contained in "th" tags). + * + * @return List with text values of table heading elements. + */ + public List getHeadingsAsString() { + return getHeadings().stream() + .map(WebElement::getText) + .collect(toList()); + } + + /** + * Returns table cell elements ({@code }), grouped by rows. + * + * @return List where each item is a table row. + */ + public List> getRows() { + return getWrappedElement() + .findElements(By.xpath(".//tr")) + .stream() + .map(rowElement -> rowElement.findElements(By.xpath(".//td"))) + .filter(row -> row.size() > 0) // ignore rows with no tags + .collect(toList()); + } + + /** + * Returns text values of table cell elements ({@code }), grouped by rows. + * + * @return List where each item is text values of a table row. + */ + public List> getRowsAsString() { + return getRows().stream() + .map(row -> row.stream() + .map(WebElement::getText) + .collect(toList())) + .collect(toList()); + } + + /** + * Returns table cell elements ({@code }), grouped by columns. + * + * @return List where each item is a table column. + */ + public List> getColumns() { + List> columns = new ArrayList<>(); + List> rows = getRows(); + + if (rows.isEmpty()) { + return columns; } - /** - * Returns table cell elements ({@code }), grouped by columns. - * - * @return List where each item is a table column. - */ - public List> getColumns() { - List> columns = new ArrayList<>(); - List> rows = getRows(); - - if (rows.isEmpty()) { - return columns; - } - - int columnCount = rows.get(0).size(); - for (int i = 0; i < columnCount; i++) { - List column = new ArrayList<>(); - for (List row : rows) { - column.add(row.get(i)); - } - columns.add(column); - } - - return columns; + int columnCount = rows.get(0).size(); + for (int i = 0; i < columnCount; i++) { + List column = new ArrayList<>(); + for (List row : rows) { + column.add(row.get(i)); + } + columns.add(column); } - /** - * Returns table cell elements ({@code }), of a particular column. - * - * @param index the 1-based index of the desired column - * @return List where each item is a cell of a particular column. - */ - public List getColumnByIndex(int index) { - return getWrappedElement().findElements( - By.cssSelector(String.format("tr > td:nth-of-type(%d)", index))); - } - - /** - * Returns text values of table cell elements ({@code }), grouped by columns. - * - * @return List where each item is text values of a table column. - */ - public List> getColumnsAsString() { - return getColumns().stream() - .map(row -> row.stream() - .map(WebElement::getText) - .collect(toList())) - .collect(toList()); - } - - /** - * Returns table cell element ({@code }), at i-th row and j-th column. - * - * @param i Row number - * @param j Column number - * @return Cell element at i-th row and j-th column. - */ - public WebElement getCellAt(int i, int j) { - return getRows().get(i).get(j); - } - - /** - * Returns list of maps where keys are table headings and values are table row elements ({@code }). - */ - public List> getRowsMappedToHeadings() { - List headingsAsString = getHeadingsAsString(); - return getRows().stream() - .map(row -> row.stream() - .collect(toMap(e -> headingsAsString.get(row.indexOf(e)), identity()))) - .collect(toList()); - } - - /** - * Returns list of maps where keys are passed headings and values are table row elements ({@code }),. - * - * @param headings List containing strings to be used as table headings. - */ - public List> getRowsMappedToHeadings(List headings) { - return getRowsMappedToHeadings().stream() - .map(e -> e.entrySet().stream().filter(m -> headings.contains(m.getKey())) - .collect(toMap(Map.Entry::getKey, Map.Entry::getValue))) - .collect(toList()); - } - - /** - * Same as {@link #getRowsMappedToHeadings()} but retrieves text from row elements ({@code }). - */ - public List> getRowsAsStringMappedToHeadings() { - return getRowsMappedToHeadings().stream() - .map(m -> m.entrySet().stream() - .collect(toMap(Map.Entry::getKey, e -> e.getValue().getText()))) - .collect(toList()); - - } - - /** - * Same as {@link #getRowsMappedToHeadings(List)} but retrieves text from row elements ({@code }). - */ - public List> getRowsAsStringMappedToHeadings(List headings) { - return getRowsMappedToHeadings(headings).stream() - .map(m -> m.entrySet().stream() - .collect(toMap(Map.Entry::getKey, e -> e.getValue().getText()))) - .collect(toList()); - } + return columns; + } + + /** + * Returns table cell elements ({@code }), of a particular column. + * + * @param index the 1-based index of the desired column + * @return List where each item is a cell of a particular column. + */ + public List getColumnByIndex(int index) { + return getWrappedElement().findElements( + By.cssSelector(String.format("tr > td:nth-of-type(%d)", index))); + } + + /** + * Returns text values of table cell elements ({@code }), grouped by columns. + * + * @return List where each item is text values of a table column. + */ + public List> getColumnsAsString() { + return getColumns().stream() + .map(row -> row.stream() + .map(WebElement::getText) + .collect(toList())) + .collect(toList()); + } + + /** + * Returns table cell element ({@code }), at i-th row and j-th column. + * + * @param i Row number + * @param j Column number + * @return Cell element at i-th row and j-th column. + */ + public WebElement getCellAt(int i, int j) { + return getRows().get(i).get(j); + } + + /** + * Returns list of maps where keys are table headings and values are table row elements ({@code }). + */ + public List> getRowsMappedToHeadings() { + List headingsAsString = getHeadingsAsString(); + return getRows().stream() + .map(row -> row.stream() + .collect(toMap(e -> headingsAsString.get(row.indexOf(e)), identity()))) + .collect(toList()); + } + + /** + * Returns list of maps where keys are passed headings and values are table row elements ({@code }),. + * + * @param headings List containing strings to be used as table headings. + */ + public List> getRowsMappedToHeadings(List headings) { + return getRowsMappedToHeadings().stream() + .map(e -> e.entrySet().stream().filter(m -> headings.contains(m.getKey())) + .collect(toMap(Map.Entry::getKey, Map.Entry::getValue))) + .collect(toList()); + } + + /** + * Same as {@link #getRowsMappedToHeadings()} but retrieves text from row elements ({@code }). + */ + public List> getRowsAsStringMappedToHeadings() { + return getRowsMappedToHeadings().stream() + .map(m -> m.entrySet().stream() + .collect(toMap(Map.Entry::getKey, e -> e.getValue().getText()))) + .collect(toList()); + + } + + /** + * Same as {@link #getRowsMappedToHeadings(List)} but retrieves text from row elements ({@code }). + */ + public List> getRowsAsStringMappedToHeadings(List headings) { + return getRowsMappedToHeadings(headings).stream() + .map(m -> m.entrySet().stream() + .collect(toMap(Map.Entry::getKey, e -> e.getValue().getText()))) + .collect(toList()); + } } diff --git a/src/main/java/com/frameworkium/core/htmlelements/element/TextBlock.java b/src/main/java/com/frameworkium/core/htmlelements/element/TextBlock.java index eaa31a24..05116577 100755 --- a/src/main/java/com/frameworkium/core/htmlelements/element/TextBlock.java +++ b/src/main/java/com/frameworkium/core/htmlelements/element/TextBlock.java @@ -2,9 +2,11 @@ import org.openqa.selenium.WebElement; -/** Represents text block on a web page. */ +/** + * Represents text block on a web page. + */ public class TextBlock extends TypifiedElement { - public TextBlock(WebElement wrappedElement) { - super(wrappedElement); - } + public TextBlock(WebElement wrappedElement) { + super(wrappedElement); + } } diff --git a/src/main/java/com/frameworkium/core/htmlelements/element/TextInput.java b/src/main/java/com/frameworkium/core/htmlelements/element/TextInput.java index ef805efa..028f4d2d 100755 --- a/src/main/java/com/frameworkium/core/htmlelements/element/TextInput.java +++ b/src/main/java/com/frameworkium/core/htmlelements/element/TextInput.java @@ -1,61 +1,60 @@ package com.frameworkium.core.htmlelements.element; +import java.util.Optional; import org.apache.commons.lang3.StringUtils; import org.openqa.selenium.Keys; import org.openqa.selenium.WebElement; -import java.util.Optional; - /** * Represents text input control * (such as <input type="text"/> or <textarea/>). */ public class TextInput extends TypifiedElement { - /** - * Specifies wrapped {@link WebElement}. - * - * @param wrappedElement {@code WebElement} to wrap. - */ - public TextInput(WebElement wrappedElement) { - super(wrappedElement); + /** + * Specifies wrapped {@link WebElement}. + * + * @param wrappedElement {@code WebElement} to wrap. + */ + public TextInput(WebElement wrappedElement) { + super(wrappedElement); + } + + /** + * Retrieves the text entered into this text input. + * + * @return Text entered into the text input. + */ + @Override + public String getText() { + if ("textarea".equals(getWrappedElement().getTagName())) { + return getWrappedElement().getText(); } - /** - * Retrieves the text entered into this text input. - * - * @return Text entered into the text input. - */ - @Override - public String getText() { - if ("textarea".equals(getWrappedElement().getTagName())) { - return getWrappedElement().getText(); - } - - return Optional - .ofNullable(getWrappedElement().getAttribute("value")) - .orElse(""); - } - - /** - * Sets the text of this Input. This is different to - * {@link #sendKeys(CharSequence...)} because it will delete any existing - * text first. - *

- * {@code text} will equal {@link #getText()} after calling this method. - * - * @param text the text to set - */ - public void setText(CharSequence text) { - getWrappedElement().sendKeys(getClearCharSequence() + text); - } - - /** - * Returns sequence of backspaces and deletes that will clear element. - * clear() can't be used because generates separate onchange event - * See https://github.com/yandex-qatools/htmlelements/issues/65 - */ - public String getClearCharSequence() { - return StringUtils.repeat(Keys.DELETE.toString() + Keys.BACK_SPACE, getText().length()); - } + return Optional + .ofNullable(getWrappedElement().getAttribute("value")) + .orElse(""); + } + + /** + * Sets the text of this Input. This is different to + * {@link #sendKeys(CharSequence...)} because it will delete any existing + * text first. + *

+ * {@code text} will equal {@link #getText()} after calling this method. + * + * @param text the text to set + */ + public void setText(CharSequence text) { + getWrappedElement().sendKeys(getClearCharSequence() + text); + } + + /** + * Returns sequence of backspaces and deletes that will clear element. + * clear() can't be used because generates separate onchange event + * See https://github.com/yandex-qatools/htmlelements/issues/65 + */ + public String getClearCharSequence() { + return StringUtils.repeat(Keys.DELETE.toString() + Keys.BACK_SPACE, getText().length()); + } } diff --git a/src/main/java/com/frameworkium/core/htmlelements/element/TypifiedElement.java b/src/main/java/com/frameworkium/core/htmlelements/element/TypifiedElement.java index f8252900..1d75757d 100755 --- a/src/main/java/com/frameworkium/core/htmlelements/element/TypifiedElement.java +++ b/src/main/java/com/frameworkium/core/htmlelements/element/TypifiedElement.java @@ -1,8 +1,14 @@ package com.frameworkium.core.htmlelements.element; -import org.openqa.selenium.*; - import java.util.List; +import org.openqa.selenium.By; +import org.openqa.selenium.Dimension; +import org.openqa.selenium.NoSuchElementException; +import org.openqa.selenium.OutputType; +import org.openqa.selenium.Point; +import org.openqa.selenium.Rectangle; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.WrapsElement; /** * The base class to be used for making classes representing typified elements @@ -24,118 +30,118 @@ * */ public abstract class TypifiedElement implements WrapsElement, WebElement { - private final WebElement wrappedElement; - - /** - * Specifies wrapped {@link WebElement}. - * - * @param wrappedElement {@code WebElement} to wrap. - */ - protected TypifiedElement(WebElement wrappedElement) { - this.wrappedElement = wrappedElement; - } - - /** - * Determines whether or not this element exists on page. - * - * @return True if the element exists on page, false otherwise. - */ - public boolean exists() { - try { - getWrappedElement().isDisplayed(); - } catch (NoSuchElementException ignored) { - return false; - } - return true; - } - - @Override - public WebElement getWrappedElement() { - return wrappedElement; - } - - @Override - public void click() { - getWrappedElement().click(); - } - - @Override - public void submit() { - getWrappedElement().submit(); - } - - @Override - public void sendKeys(CharSequence... keysToSend) { - getWrappedElement().sendKeys(keysToSend); - } - - @Override - public void clear() { - getWrappedElement().clear(); - } - - @Override - public String getTagName() { - return getWrappedElement().getTagName(); - } - - @Override - public String getAttribute(String name) { - return getWrappedElement().getAttribute(name); - } - - @Override - public boolean isSelected() { - return getWrappedElement().isSelected(); - } - - @Override - public boolean isEnabled() { - return getWrappedElement().isEnabled(); - } - - @Override - public String getText() { - return getWrappedElement().getText(); - } - - @Override - public List findElements(By by) { - return getWrappedElement().findElements(by); - } - - @Override - public WebElement findElement(By by) { - return getWrappedElement().findElement(by); - } - - @Override - public boolean isDisplayed() { - return getWrappedElement().isDisplayed(); - } - - @Override - public Point getLocation() { - return getWrappedElement().getLocation(); - } - - @Override - public Dimension getSize() { - return getWrappedElement().getSize(); - } - - @Override - public Rectangle getRect() { - return getWrappedElement().getRect(); - } - - @Override - public String getCssValue(String propertyName) { - return getWrappedElement().getCssValue(propertyName); - } - - @Override - public X getScreenshotAs(OutputType target) { - return getWrappedElement().getScreenshotAs(target); - } + private final WebElement wrappedElement; + + /** + * Specifies wrapped {@link WebElement}. + * + * @param wrappedElement {@code WebElement} to wrap. + */ + protected TypifiedElement(WebElement wrappedElement) { + this.wrappedElement = wrappedElement; + } + + /** + * Determines whether or not this element exists on page. + * + * @return True if the element exists on page, false otherwise. + */ + public boolean exists() { + try { + getWrappedElement().isDisplayed(); + } catch (NoSuchElementException ignored) { + return false; + } + return true; + } + + @Override + public WebElement getWrappedElement() { + return wrappedElement; + } + + @Override + public void click() { + getWrappedElement().click(); + } + + @Override + public void submit() { + getWrappedElement().submit(); + } + + @Override + public void sendKeys(CharSequence... keysToSend) { + getWrappedElement().sendKeys(keysToSend); + } + + @Override + public void clear() { + getWrappedElement().clear(); + } + + @Override + public String getTagName() { + return getWrappedElement().getTagName(); + } + + @Override + public String getAttribute(String name) { + return getWrappedElement().getAttribute(name); + } + + @Override + public boolean isSelected() { + return getWrappedElement().isSelected(); + } + + @Override + public boolean isEnabled() { + return getWrappedElement().isEnabled(); + } + + @Override + public String getText() { + return getWrappedElement().getText(); + } + + @Override + public List findElements(By by) { + return getWrappedElement().findElements(by); + } + + @Override + public WebElement findElement(By by) { + return getWrappedElement().findElement(by); + } + + @Override + public boolean isDisplayed() { + return getWrappedElement().isDisplayed(); + } + + @Override + public Point getLocation() { + return getWrappedElement().getLocation(); + } + + @Override + public Dimension getSize() { + return getWrappedElement().getSize(); + } + + @Override + public Rectangle getRect() { + return getWrappedElement().getRect(); + } + + @Override + public String getCssValue(String propertyName) { + return getWrappedElement().getCssValue(propertyName); + } + + @Override + public X getScreenshotAs(OutputType target) { + return getWrappedElement().getScreenshotAs(target); + } } diff --git a/src/main/java/com/frameworkium/core/htmlelements/exceptions/HtmlElementsException.java b/src/main/java/com/frameworkium/core/htmlelements/exceptions/HtmlElementsException.java index 098f0abc..cab458a2 100755 --- a/src/main/java/com/frameworkium/core/htmlelements/exceptions/HtmlElementsException.java +++ b/src/main/java/com/frameworkium/core/htmlelements/exceptions/HtmlElementsException.java @@ -6,21 +6,21 @@ */ public class HtmlElementsException extends RuntimeException { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 1L; - public HtmlElementsException() { - super(); - } + public HtmlElementsException() { + super(); + } - public HtmlElementsException(String message) { - super(message); - } + public HtmlElementsException(String message) { + super(message); + } - public HtmlElementsException(String message, Throwable cause) { - super(message, cause); - } + public HtmlElementsException(String message, Throwable cause) { + super(message, cause); + } - public HtmlElementsException(Throwable cause) { - super(cause); - } + public HtmlElementsException(Throwable cause) { + super(cause); + } } diff --git a/src/main/java/com/frameworkium/core/htmlelements/loader/HtmlElementLoader.java b/src/main/java/com/frameworkium/core/htmlelements/loader/HtmlElementLoader.java index a61704b6..0165e6a3 100755 --- a/src/main/java/com/frameworkium/core/htmlelements/loader/HtmlElementLoader.java +++ b/src/main/java/com/frameworkium/core/htmlelements/loader/HtmlElementLoader.java @@ -1,6 +1,10 @@ package com.frameworkium.core.htmlelements.loader; +import static com.frameworkium.core.htmlelements.loader.decorator.ProxyFactory.createWebElementProxy; +import static com.frameworkium.core.htmlelements.utils.HtmlElementUtils.getElementName; +import static com.frameworkium.core.htmlelements.utils.HtmlElementUtils.newInstance; + import com.frameworkium.core.htmlelements.element.HtmlElement; import com.frameworkium.core.htmlelements.element.TypifiedElement; import com.frameworkium.core.htmlelements.exceptions.HtmlElementsException; @@ -8,122 +12,122 @@ import com.frameworkium.core.htmlelements.loader.decorator.HtmlElementLocatorFactory; import com.frameworkium.core.htmlelements.loader.decorator.proxyhandlers.WebElementNamedProxyHandler; import com.frameworkium.core.htmlelements.pagefactory.CustomElementLocatorFactory; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.InvocationTargetException; import org.openqa.selenium.SearchContext; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.PageFactory; import org.openqa.selenium.support.pagefactory.ElementLocator; -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.InvocationTargetException; - -import static com.frameworkium.core.htmlelements.loader.decorator.ProxyFactory.createWebElementProxy; -import static com.frameworkium.core.htmlelements.utils.HtmlElementUtils.*; -import static com.frameworkium.core.htmlelements.utils.HtmlElementUtils.getElementName; - - -/** Initialises blocks of elements and page objects. */ +/** + * Initialises blocks of elements and page objects. + */ public class HtmlElementLoader { - /** - * Creates an instance of the given class representing a block of elements and initializes its fields - * with lazy proxies. - *

- * Processes annotation of the given class - * to set the way of locating the block itself and {@link org.openqa.selenium.support.FindBy}, - * {@link org.openqa.selenium.support.FindBys} and {@link org.openqa.selenium.support.FindAll} - * annotations of its fields for setting the way of locating elements of the block. - *

- * Fields to be proxied: - *

- *

    - *
  • {@code WebElement}
  • - *
  • List of {@code WebElements}
  • - *
  • Block of elements ({@link HtmlElement} and its successors)
  • - *
  • List of blocks
  • - *
  • Typified element ({@link com.frameworkium.core.htmlelements.element.TypifiedElement} successors)
  • - *
  • List of typified elements
  • - *
- * - * @param clazz A class to be instantiated and initialized. - * @param searchContext {@code SearchContext} that will be used to look up the elements. - * @return Initialized instance of the specified class. - */ - public static T createHtmlElement(Class clazz, SearchContext searchContext) { - ElementLocator locator = new HtmlElementLocatorFactory(searchContext).createLocator(clazz); - String elementName = getElementName(clazz); - - InvocationHandler handler = new WebElementNamedProxyHandler(locator, elementName); - WebElement elementToWrap = createWebElementProxy(clazz.getClassLoader(), handler); - return createHtmlElement(clazz, elementToWrap); - } - - public static T createHtmlElement(Class elementClass, WebElement elementToWrap) { - try { - T instance = newInstance(elementClass); - instance.setWrappedElement(elementToWrap); - // Recursively initialize elements of the block - populatePageObject(instance, elementToWrap); - return instance; - } catch (NoSuchMethodException | InstantiationException | IllegalAccessException - | InvocationTargetException e) { - throw new HtmlElementsException(e); - } - } - - public static T createTypifiedElement(Class clazz, SearchContext searchContext) { - ElementLocator locator = new HtmlElementLocatorFactory(searchContext).createLocator(clazz); - String elementName = getElementName(clazz); - - InvocationHandler handler = new WebElementNamedProxyHandler(locator, elementName); - WebElement elementToWrap = createWebElementProxy(clazz.getClassLoader(), handler); - - return createTypifiedElement(clazz, elementToWrap); - } - - public static T createTypifiedElement(Class elementClass, WebElement elementToWrap) { - try { - return newInstance(elementClass, elementToWrap); - } catch (NoSuchMethodException - | InstantiationException - | IllegalAccessException - | InvocationTargetException e) { - throw new HtmlElementsException(e); - } + /** + * Creates an instance of the given class representing a block of elements and initializes its fields + * with lazy proxies. + *

+ * Processes annotation of the given class + * to set the way of locating the block itself and {@link org.openqa.selenium.support.FindBy}, + * {@link org.openqa.selenium.support.FindBys} and {@link org.openqa.selenium.support.FindAll} + * annotations of its fields for setting the way of locating elements of the block. + *

+ * Fields to be proxied: + *

+ *

    + *
  • {@code WebElement}
  • + *
  • List of {@code WebElements}
  • + *
  • Block of elements ({@link HtmlElement} and its successors)
  • + *
  • List of blocks
  • + *
  • Typified element ({@link com.frameworkium.core.htmlelements.element.TypifiedElement} successors)
  • + *
  • List of typified elements
  • + *
+ * + * @param clazz A class to be instantiated and initialized. + * @param searchContext {@code SearchContext} that will be used to look up the elements. + * @return Initialized instance of the specified class. + */ + public static T createHtmlElement(Class clazz, + SearchContext searchContext) { + ElementLocator locator = new HtmlElementLocatorFactory(searchContext).createLocator(clazz); + String elementName = getElementName(clazz); + + InvocationHandler handler = new WebElementNamedProxyHandler(locator, elementName); + WebElement elementToWrap = createWebElementProxy(clazz.getClassLoader(), handler); + return createHtmlElement(clazz, elementToWrap); + } + + public static T createHtmlElement(Class elementClass, + WebElement elementToWrap) { + try { + T instance = newInstance(elementClass); + instance.setWrappedElement(elementToWrap); + // Recursively initialize elements of the block + populatePageObject(instance, elementToWrap); + return instance; + } catch (NoSuchMethodException | InstantiationException | IllegalAccessException + | InvocationTargetException e) { + throw new HtmlElementsException(e); } - - /** - * Initializes fields of the given page object with lazy proxies. - *

- * Processes {@link org.openqa.selenium.support.FindBy}, - * {@link org.openqa.selenium.support.FindBys} and {@link org.openqa.selenium.support.FindAll} - * annotations of the fields for setting the way of locating them. - *

- * Fields to be proxied: - *

- *

    - *
  • {@code WebElement}
  • - *
  • List of {@code WebElements}
  • - *
  • Block of elements ({@link HtmlElement} and its successors)
  • - *
  • List of blocks
  • - *
  • Typified element ({@link com.frameworkium.core.htmlelements.element.TypifiedElement} successors)
  • - *
  • List of typified elements
  • - *
- * - * @param page Page object to be initialized. - * @param searchContext The {@code WebDriver} instance that will be used to look up the elements. - */ - public static void populatePageObject(Object page, SearchContext searchContext) { - populatePageObject(page, new HtmlElementLocatorFactory(searchContext)); - } - - /** - * Initializes fields of the given page object using specified locator factory. - * - * @param page Page object to be initialized. - * @param locatorFactory Locator factory that will be used to locate elements. - */ - public static void populatePageObject(Object page, CustomElementLocatorFactory locatorFactory) { - PageFactory.initElements(new HtmlElementDecorator(locatorFactory), page); + } + + public static T createTypifiedElement(Class clazz, + SearchContext searchContext) { + ElementLocator locator = new HtmlElementLocatorFactory(searchContext).createLocator(clazz); + String elementName = getElementName(clazz); + + InvocationHandler handler = new WebElementNamedProxyHandler(locator, elementName); + WebElement elementToWrap = createWebElementProxy(clazz.getClassLoader(), handler); + + return createTypifiedElement(clazz, elementToWrap); + } + + public static T createTypifiedElement(Class elementClass, + WebElement elementToWrap) { + try { + return newInstance(elementClass, elementToWrap); + } catch (NoSuchMethodException + | InstantiationException + | IllegalAccessException + | InvocationTargetException e) { + throw new HtmlElementsException(e); } + } + + /** + * Initializes fields of the given page object with lazy proxies. + *

+ * Processes {@link org.openqa.selenium.support.FindBy}, + * {@link org.openqa.selenium.support.FindBys} and {@link org.openqa.selenium.support.FindAll} + * annotations of the fields for setting the way of locating them. + *

+ * Fields to be proxied: + *

+ *

    + *
  • {@code WebElement}
  • + *
  • List of {@code WebElements}
  • + *
  • Block of elements ({@link HtmlElement} and its successors)
  • + *
  • List of blocks
  • + *
  • Typified element ({@link com.frameworkium.core.htmlelements.element.TypifiedElement} successors)
  • + *
  • List of typified elements
  • + *
+ * + * @param page Page object to be initialized. + * @param searchContext The {@code WebDriver} instance that will be used to look up the elements. + */ + public static void populatePageObject(Object page, SearchContext searchContext) { + populatePageObject(page, new HtmlElementLocatorFactory(searchContext)); + } + + /** + * Initializes fields of the given page object using specified locator factory. + * + * @param page Page object to be initialized. + * @param locatorFactory Locator factory that will be used to locate elements. + */ + public static void populatePageObject(Object page, CustomElementLocatorFactory locatorFactory) { + PageFactory.initElements(new HtmlElementDecorator(locatorFactory), page); + } } diff --git a/src/main/java/com/frameworkium/core/htmlelements/loader/decorator/HtmlElementClassAnnotationsHandler.java b/src/main/java/com/frameworkium/core/htmlelements/loader/decorator/HtmlElementClassAnnotationsHandler.java index 1b897632..5bc47b75 100755 --- a/src/main/java/com/frameworkium/core/htmlelements/loader/decorator/HtmlElementClassAnnotationsHandler.java +++ b/src/main/java/com/frameworkium/core/htmlelements/loader/decorator/HtmlElementClassAnnotationsHandler.java @@ -7,31 +7,33 @@ import org.openqa.selenium.support.FindBy.FindByBuilder; import org.openqa.selenium.support.pagefactory.AbstractAnnotations; -/** Handles annotation of {@link HtmlElement} and its successors. */ +/** + * Handles annotation of {@link HtmlElement} and its successors. + */ public class HtmlElementClassAnnotationsHandler extends AbstractAnnotations { - private final Class elementClass; + private final Class elementClass; - public HtmlElementClassAnnotationsHandler(Class elementClass) { - this.elementClass = elementClass; - } - - @Override - public By buildBy() { - Class clazz = elementClass; - while (clazz != Object.class) { - if (clazz.isAnnotationPresent(FindBy.class)) { - return new FindByBuilder().buildIt(clazz.getAnnotation(FindBy.class), null); - } - clazz = clazz.getSuperclass(); - } + public HtmlElementClassAnnotationsHandler(Class elementClass) { + this.elementClass = elementClass; + } - throw new HtmlElementsException(String.format( - "Cannot determine how to locate instance of %s", elementClass)); + @Override + public By buildBy() { + Class clazz = elementClass; + while (clazz != Object.class) { + if (clazz.isAnnotationPresent(FindBy.class)) { + return new FindByBuilder().buildIt(clazz.getAnnotation(FindBy.class), null); + } + clazz = clazz.getSuperclass(); } - @Override - public boolean isLookupCached() { - return false; - } + throw new HtmlElementsException(String.format( + "Cannot determine how to locate instance of %s", elementClass)); + } + + @Override + public boolean isLookupCached() { + return false; + } } diff --git a/src/main/java/com/frameworkium/core/htmlelements/loader/decorator/HtmlElementDecorator.java b/src/main/java/com/frameworkium/core/htmlelements/loader/decorator/HtmlElementDecorator.java index 462ab2a1..14d18455 100755 --- a/src/main/java/com/frameworkium/core/htmlelements/loader/decorator/HtmlElementDecorator.java +++ b/src/main/java/com/frameworkium/core/htmlelements/loader/decorator/HtmlElementDecorator.java @@ -1,20 +1,34 @@ package com.frameworkium.core.htmlelements.loader.decorator; +import static com.frameworkium.core.htmlelements.loader.HtmlElementLoader.createHtmlElement; +import static com.frameworkium.core.htmlelements.loader.HtmlElementLoader.createTypifiedElement; +import static com.frameworkium.core.htmlelements.loader.decorator.ProxyFactory.createHtmlElementListProxy; +import static com.frameworkium.core.htmlelements.loader.decorator.ProxyFactory.createTypifiedElementListProxy; +import static com.frameworkium.core.htmlelements.loader.decorator.ProxyFactory.createWebElementListProxy; +import static com.frameworkium.core.htmlelements.loader.decorator.ProxyFactory.createWebElementProxy; +import static com.frameworkium.core.htmlelements.utils.HtmlElementUtils.getElementName; +import static com.frameworkium.core.htmlelements.utils.HtmlElementUtils.getGenericParameterClass; +import static com.frameworkium.core.htmlelements.utils.HtmlElementUtils.isHtmlElement; +import static com.frameworkium.core.htmlelements.utils.HtmlElementUtils.isHtmlElementList; +import static com.frameworkium.core.htmlelements.utils.HtmlElementUtils.isTypifiedElement; +import static com.frameworkium.core.htmlelements.utils.HtmlElementUtils.isTypifiedElementList; +import static com.frameworkium.core.htmlelements.utils.HtmlElementUtils.isWebElement; +import static com.frameworkium.core.htmlelements.utils.HtmlElementUtils.isWebElementList; + import com.frameworkium.core.htmlelements.element.HtmlElement; import com.frameworkium.core.htmlelements.element.TypifiedElement; -import com.frameworkium.core.htmlelements.loader.decorator.proxyhandlers.*; +import com.frameworkium.core.htmlelements.loader.decorator.proxyhandlers.HtmlElementListNamedProxyHandler; +import com.frameworkium.core.htmlelements.loader.decorator.proxyhandlers.TypifiedElementListNamedProxyHandler; +import com.frameworkium.core.htmlelements.loader.decorator.proxyhandlers.WebElementListNamedProxyHandler; +import com.frameworkium.core.htmlelements.loader.decorator.proxyhandlers.WebElementNamedProxyHandler; import com.frameworkium.core.htmlelements.pagefactory.CustomElementLocatorFactory; -import org.openqa.selenium.WebElement; -import org.openqa.selenium.support.pagefactory.*; - import java.lang.reflect.Field; import java.lang.reflect.InvocationHandler; import java.util.List; - -import static com.frameworkium.core.htmlelements.loader.HtmlElementLoader.createHtmlElement; -import static com.frameworkium.core.htmlelements.loader.HtmlElementLoader.createTypifiedElement; -import static com.frameworkium.core.htmlelements.loader.decorator.ProxyFactory.*; -import static com.frameworkium.core.htmlelements.utils.HtmlElementUtils.*; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.support.pagefactory.ElementLocator; +import org.openqa.selenium.support.pagefactory.ElementLocatorFactory; +import org.openqa.selenium.support.pagefactory.FieldDecorator; /** * Decorator which is used to decorate fields of blocks and page objects. @@ -35,85 +49,88 @@ * or {@link org.openqa.selenium.support.FindAll} annotation. */ public class HtmlElementDecorator implements FieldDecorator { - protected ElementLocatorFactory factory; - - public HtmlElementDecorator(CustomElementLocatorFactory factory) { - this.factory = factory; + protected ElementLocatorFactory factory; + + public HtmlElementDecorator(CustomElementLocatorFactory factory) { + this.factory = factory; + } + + public Object decorate(ClassLoader loader, Field field) { + try { + if (isTypifiedElement(field)) { + return decorateTypifiedElement(loader, field); + } + if (isHtmlElement(field)) { + return decorateHtmlElement(loader, field); + } + if (isWebElement(field) && !field.getName().equals("wrappedElement")) { + return decorateWebElement(loader, field); + } + if (isTypifiedElementList(field)) { + return decorateTypifiedElementList(loader, field); + } + if (isHtmlElementList(field)) { + return decorateHtmlElementList(loader, field); + } + if (isWebElementList(field)) { + return decorateWebElementList(loader, field); + } + return null; + } catch (ClassCastException ignore) { + return null; // See bug #94 and NonElementFieldsTest } + } - public Object decorate(ClassLoader loader, Field field) { - try { - if (isTypifiedElement(field)) { - return decorateTypifiedElement(loader, field); - } - if (isHtmlElement(field)) { - return decorateHtmlElement(loader, field); - } - if (isWebElement(field) && !field.getName().equals("wrappedElement")) { - return decorateWebElement(loader, field); - } - if (isTypifiedElementList(field)) { - return decorateTypifiedElementList(loader, field); - } - if (isHtmlElementList(field)) { - return decorateHtmlElementList(loader, field); - } - if (isWebElementList(field)) { - return decorateWebElementList(loader, field); - } - return null; - } catch (ClassCastException ignore) { - return null; // See bug #94 and NonElementFieldsTest - } - } + protected T decorateTypifiedElement(ClassLoader loader, Field field) { + WebElement elementToWrap = decorateWebElement(loader, field); - protected T decorateTypifiedElement(ClassLoader loader, Field field) { - WebElement elementToWrap = decorateWebElement(loader, field); + //noinspection unchecked + return createTypifiedElement((Class) field.getType(), elementToWrap); + } - //noinspection unchecked - return createTypifiedElement((Class) field.getType(), elementToWrap); - } + protected T decorateHtmlElement(ClassLoader loader, Field field) { + WebElement elementToWrap = decorateWebElement(loader, field); - protected T decorateHtmlElement(ClassLoader loader, Field field) { - WebElement elementToWrap = decorateWebElement(loader, field); + //noinspection unchecked + return createHtmlElement((Class) field.getType(), elementToWrap); + } - //noinspection unchecked - return createHtmlElement((Class) field.getType(), elementToWrap); - } + protected WebElement decorateWebElement(ClassLoader loader, Field field) { + ElementLocator locator = factory.createLocator(field); + InvocationHandler handler = new WebElementNamedProxyHandler(locator, getElementName(field)); - protected WebElement decorateWebElement(ClassLoader loader, Field field) { - ElementLocator locator = factory.createLocator(field); - InvocationHandler handler = new WebElementNamedProxyHandler(locator, getElementName(field)); + return createWebElementProxy(loader, handler); + } - return createWebElementProxy(loader, handler); - } + protected List decorateTypifiedElementList(ClassLoader loader, + Field field) { + @SuppressWarnings("unchecked") + Class elementClass = (Class) getGenericParameterClass(field); + ElementLocator locator = factory.createLocator(field); + String name = getElementName(field); - protected List decorateTypifiedElementList(ClassLoader loader, Field field) { - @SuppressWarnings("unchecked") - Class elementClass = (Class) getGenericParameterClass(field); - ElementLocator locator = factory.createLocator(field); - String name = getElementName(field); + InvocationHandler handler = + new TypifiedElementListNamedProxyHandler<>(elementClass, locator, name); - InvocationHandler handler = new TypifiedElementListNamedProxyHandler<>(elementClass, locator, name); + return createTypifiedElementListProxy(loader, handler); + } - return createTypifiedElementListProxy(loader, handler); - } - - protected List decorateHtmlElementList(ClassLoader loader, Field field) { - @SuppressWarnings("unchecked") - Class elementClass = (Class) getGenericParameterClass(field); - ElementLocator locator = factory.createLocator(field); - String name = getElementName(field); + protected List decorateHtmlElementList(ClassLoader loader, + Field field) { + @SuppressWarnings("unchecked") + Class elementClass = (Class) getGenericParameterClass(field); + ElementLocator locator = factory.createLocator(field); + String name = getElementName(field); - InvocationHandler handler = new HtmlElementListNamedProxyHandler<>(elementClass, locator, name); + InvocationHandler handler = new HtmlElementListNamedProxyHandler<>(elementClass, locator, name); - return createHtmlElementListProxy(loader, handler); - } + return createHtmlElementListProxy(loader, handler); + } - protected List decorateWebElementList(ClassLoader loader, Field field) { - ElementLocator locator = factory.createLocator(field); - InvocationHandler handler = new WebElementListNamedProxyHandler(locator, getElementName(field)); + protected List decorateWebElementList(ClassLoader loader, Field field) { + ElementLocator locator = factory.createLocator(field); + InvocationHandler handler = new WebElementListNamedProxyHandler(locator, getElementName(field)); - return createWebElementListProxy(loader, handler); - } + return createWebElementListProxy(loader, handler); + } } diff --git a/src/main/java/com/frameworkium/core/htmlelements/loader/decorator/HtmlElementFieldAnnotationsHandler.java b/src/main/java/com/frameworkium/core/htmlelements/loader/decorator/HtmlElementFieldAnnotationsHandler.java index 53452a70..cdbf30fb 100755 --- a/src/main/java/com/frameworkium/core/htmlelements/loader/decorator/HtmlElementFieldAnnotationsHandler.java +++ b/src/main/java/com/frameworkium/core/htmlelements/loader/decorator/HtmlElementFieldAnnotationsHandler.java @@ -1,90 +1,95 @@ package com.frameworkium.core.htmlelements.loader.decorator; +import static com.frameworkium.core.htmlelements.utils.HtmlElementUtils.getGenericParameterClass; +import static com.frameworkium.core.htmlelements.utils.HtmlElementUtils.isHtmlElement; +import static com.frameworkium.core.htmlelements.utils.HtmlElementUtils.isHtmlElementList; +import static com.frameworkium.core.htmlelements.utils.HtmlElementUtils.isTypifiedElement; +import static com.frameworkium.core.htmlelements.utils.HtmlElementUtils.isTypifiedElementList; + import com.frameworkium.core.htmlelements.exceptions.HtmlElementsException; +import java.lang.reflect.Field; import org.openqa.selenium.By; -import org.openqa.selenium.support.*; +import org.openqa.selenium.support.FindAll; +import org.openqa.selenium.support.FindBy; +import org.openqa.selenium.support.FindBys; import org.openqa.selenium.support.pagefactory.Annotations; -import java.lang.reflect.Field; - -import static com.frameworkium.core.htmlelements.utils.HtmlElementUtils.*; - /** * Extends default field annotations handling mechanism with processing * annotation for blocks and lists of blocks. */ public class HtmlElementFieldAnnotationsHandler extends Annotations { - public HtmlElementFieldAnnotationsHandler(Field field) { - super(field); + public HtmlElementFieldAnnotationsHandler(Field field) { + super(field); + } + + @Override + public By buildBy() { + if (isHtmlElement(getField()) || isTypifiedElement(getField())) { + return buildByFromHtmlElementAnnotations(); } - - @Override - public By buildBy() { - if (isHtmlElement(getField()) || isTypifiedElement(getField())) { - return buildByFromHtmlElementAnnotations(); - } - if (isHtmlElementList(getField()) || isTypifiedElementList(getField())) { - return buildByFromHtmlElementListAnnotations(); - } - return super.buildBy(); + if (isHtmlElementList(getField()) || isTypifiedElementList(getField())) { + return buildByFromHtmlElementListAnnotations(); } + return super.buildBy(); + } - private By buildByFromFindAnnotations() { - if (getField().isAnnotationPresent(FindBys.class)) { - FindBys findBys = getField().getAnnotation(FindBys.class); - return new FindBys.FindByBuilder().buildIt(findBys, null); - } - - if (getField().isAnnotationPresent(FindAll.class)) { - FindAll findAll = getField().getAnnotation(FindAll.class); - return new FindAll.FindByBuilder().buildIt(findAll, null); - } + private By buildByFromFindAnnotations() { + if (getField().isAnnotationPresent(FindBys.class)) { + FindBys findBys = getField().getAnnotation(FindBys.class); + return new FindBys.FindByBuilder().buildIt(findBys, null); + } - if (getField().isAnnotationPresent(FindBy.class)) { - FindBy findBy = getField().getAnnotation(FindBy.class); - return new FindBy.FindByBuilder().buildIt(findBy, null); - } - return null; + if (getField().isAnnotationPresent(FindAll.class)) { + FindAll findAll = getField().getAnnotation(FindAll.class); + return new FindAll.FindByBuilder().buildIt(findAll, null); } - private By buildByFromHtmlElementAnnotations() { - assertValidAnnotations(); + if (getField().isAnnotationPresent(FindBy.class)) { + FindBy findBy = getField().getAnnotation(FindBy.class); + return new FindBy.FindByBuilder().buildIt(findBy, null); + } + return null; + } - By result = buildByFromFindAnnotations(); - if (result != null) { - return result; - } + private By buildByFromHtmlElementAnnotations() { + assertValidAnnotations(); - Class fieldClass = getField().getType(); - while (fieldClass != Object.class) { - if (fieldClass.isAnnotationPresent(FindBy.class)) { - return new FindBy.FindByBuilder() - .buildIt(fieldClass.getAnnotation(FindBy.class), null); - } - fieldClass = fieldClass.getSuperclass(); - } + By result = buildByFromFindAnnotations(); + if (result != null) { + return result; + } - return buildByFromDefault(); + Class fieldClass = getField().getType(); + while (fieldClass != Object.class) { + if (fieldClass.isAnnotationPresent(FindBy.class)) { + return new FindBy.FindByBuilder() + .buildIt(fieldClass.getAnnotation(FindBy.class), null); + } + fieldClass = fieldClass.getSuperclass(); } - private By buildByFromHtmlElementListAnnotations() { - assertValidAnnotations(); + return buildByFromDefault(); + } - By result = buildByFromFindAnnotations(); - if (result != null) { - return result; - } + private By buildByFromHtmlElementListAnnotations() { + assertValidAnnotations(); - Class listParameterClass = getGenericParameterClass(getField()); - while (listParameterClass != Object.class) { - if (listParameterClass.isAnnotationPresent(FindBy.class)) { - return new FindBy.FindByBuilder() - .buildIt(listParameterClass.getAnnotation(FindBy.class), null); - } - listParameterClass = listParameterClass.getSuperclass(); - } + By result = buildByFromFindAnnotations(); + if (result != null) { + return result; + } - throw new HtmlElementsException( - String.format("Cannot determine how to locate element %s", getField())); + Class listParameterClass = getGenericParameterClass(getField()); + while (listParameterClass != Object.class) { + if (listParameterClass.isAnnotationPresent(FindBy.class)) { + return new FindBy.FindByBuilder() + .buildIt(listParameterClass.getAnnotation(FindBy.class), null); + } + listParameterClass = listParameterClass.getSuperclass(); } + + throw new HtmlElementsException( + String.format("Cannot determine how to locate element %s", getField())); + } } diff --git a/src/main/java/com/frameworkium/core/htmlelements/loader/decorator/HtmlElementLocatorFactory.java b/src/main/java/com/frameworkium/core/htmlelements/loader/decorator/HtmlElementLocatorFactory.java index 6672f5d3..03222476 100755 --- a/src/main/java/com/frameworkium/core/htmlelements/loader/decorator/HtmlElementLocatorFactory.java +++ b/src/main/java/com/frameworkium/core/htmlelements/loader/decorator/HtmlElementLocatorFactory.java @@ -3,69 +3,76 @@ import com.frameworkium.core.htmlelements.annotations.Timeout; import com.frameworkium.core.htmlelements.pagefactory.CustomElementLocatorFactory; import com.frameworkium.core.htmlelements.utils.HtmlElementUtils; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.ParameterizedType; import org.openqa.selenium.SearchContext; import org.openqa.selenium.support.pagefactory.AjaxElementLocator; import org.openqa.selenium.support.pagefactory.ElementLocator; -import java.lang.reflect.*; - -/** A factory for producing locator instances. */ +/** + * A factory for producing locator instances. + */ public class HtmlElementLocatorFactory implements CustomElementLocatorFactory { - private final SearchContext searchContext; + private final SearchContext searchContext; - public HtmlElementLocatorFactory(SearchContext searchContext) { - this.searchContext = searchContext; - } + public HtmlElementLocatorFactory(SearchContext searchContext) { + this.searchContext = searchContext; + } - /** - * Creates locator for the given field. Created locator will process {@link org.openqa.selenium.support.FindBy}, - * {@link org.openqa.selenium.support.FindBy}, {@link org.openqa.selenium.support.FindBys}, - * {@link org.openqa.selenium.support.FindAll} and {@link org.openqa.selenium.support.CacheLookup} annotations. - * - * @param field Field for which locator will be created. - */ - public ElementLocator createLocator(Field field) { - return new AjaxElementLocator(searchContext, getTimeOut(field), new HtmlElementFieldAnnotationsHandler(field)); - } + /** + * Creates locator for the given field. Created locator will process {@link org.openqa.selenium.support.FindBy}, + * {@link org.openqa.selenium.support.FindBy}, {@link org.openqa.selenium.support.FindBys}, + * {@link org.openqa.selenium.support.FindAll} and {@link org.openqa.selenium.support.CacheLookup} annotations. + * + * @param field Field for which locator will be created. + */ + public ElementLocator createLocator(Field field) { + return new AjaxElementLocator(searchContext, getTimeOut(field), + new HtmlElementFieldAnnotationsHandler(field)); + } - /** - * Creates locator for the given field. Created locator will process {@link org.openqa.selenium.support.FindBy}, - * {@link org.openqa.selenium.support.FindBy}, {@link org.openqa.selenium.support.FindBys}, - * {@link org.openqa.selenium.support.FindAll} and {@link org.openqa.selenium.support.CacheLookup} annotations. - * - * @param clazz Class for which locator will be created. - */ - @SuppressWarnings("rawtypes") - public ElementLocator createLocator(Class clazz) { - return new AjaxElementLocator(searchContext, getTimeOut(clazz), new HtmlElementClassAnnotationsHandler(clazz)); - } + /** + * Creates locator for the given field. Created locator will process {@link org.openqa.selenium.support.FindBy}, + * {@link org.openqa.selenium.support.FindBy}, {@link org.openqa.selenium.support.FindBys}, + * {@link org.openqa.selenium.support.FindAll} and {@link org.openqa.selenium.support.CacheLookup} annotations. + * + * @param clazz Class for which locator will be created. + */ + @SuppressWarnings("rawtypes") + public ElementLocator createLocator(Class clazz) { + return new AjaxElementLocator(searchContext, getTimeOut(clazz), + new HtmlElementClassAnnotationsHandler(clazz)); + } - public int getTimeOut(Field field) { - if (field.isAnnotationPresent(Timeout.class)) { - return field.getAnnotation(Timeout.class).value(); - } - if (field.getGenericType() instanceof Class) { - return getTimeOut((Class) field.getGenericType()); - } - return getTimeOut((Class) ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0]); + public int getTimeOut(Field field) { + if (field.isAnnotationPresent(Timeout.class)) { + return field.getAnnotation(Timeout.class).value(); + } + if (field.getGenericType() instanceof Class) { + return getTimeOut((Class) field.getGenericType()); } + return getTimeOut( + (Class) ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0]); + } - public int getTimeOut(Class clazz) { - try { - Method method = Timeout.class.getMethod("value"); - do { - if (clazz.isAnnotationPresent(Timeout.class)) { - return (Integer) method.invoke(clazz.getAnnotation(Timeout.class)); - } - clazz = clazz.getSuperclass(); - } - while (clazz != Object.class && clazz != null); - } catch (NoSuchMethodException - | InvocationTargetException - | IllegalAccessException ignored) { + public int getTimeOut(Class clazz) { + try { + Method method = Timeout.class.getMethod("value"); + do { + if (clazz.isAnnotationPresent(Timeout.class)) { + return (Integer) method.invoke(clazz.getAnnotation(Timeout.class)); } - - return HtmlElementUtils.getImplicitTimeoutInSeconds(); + clazz = clazz.getSuperclass(); + } + while (clazz != Object.class && clazz != null); + } catch (NoSuchMethodException + | InvocationTargetException + | IllegalAccessException ignored) { } + + return HtmlElementUtils.getImplicitTimeoutInSeconds(); + } } diff --git a/src/main/java/com/frameworkium/core/htmlelements/loader/decorator/ProxyFactory.java b/src/main/java/com/frameworkium/core/htmlelements/loader/decorator/ProxyFactory.java index 536932bd..03218c9b 100755 --- a/src/main/java/com/frameworkium/core/htmlelements/loader/decorator/ProxyFactory.java +++ b/src/main/java/com/frameworkium/core/htmlelements/loader/decorator/ProxyFactory.java @@ -2,36 +2,37 @@ import com.frameworkium.core.htmlelements.element.HtmlElement; import com.frameworkium.core.htmlelements.element.TypifiedElement; -import org.openqa.selenium.WebElement; -import org.openqa.selenium.WrapsElement; -import org.openqa.selenium.interactions.Locatable; - import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; import java.util.List; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.WrapsElement; +import org.openqa.selenium.interactions.Locatable; /** * Contains factory methods for creating proxy of blocks, typified elements, page objects */ @SuppressWarnings("unchecked") public class ProxyFactory { - public static T createWebElementProxy(ClassLoader loader, InvocationHandler handler) { - Class[] interfaces = new Class[]{WebElement.class, WrapsElement.class, Locatable.class}; - return (T) Proxy.newProxyInstance(loader, interfaces, handler); - } + public static T createWebElementProxy(ClassLoader loader, + InvocationHandler handler) { + Class[] interfaces = new Class[] {WebElement.class, WrapsElement.class, Locatable.class}; + return (T) Proxy.newProxyInstance(loader, interfaces, handler); + } - public static List createWebElementListProxy(ClassLoader loader, - InvocationHandler handler) { - return (List) Proxy.newProxyInstance(loader, new Class[]{List.class}, handler); - } + public static List createWebElementListProxy(ClassLoader loader, + InvocationHandler handler) { + return (List) Proxy.newProxyInstance(loader, new Class[] {List.class}, handler); + } - public static List createTypifiedElementListProxy(ClassLoader loader, - InvocationHandler handler) { - return (List) Proxy.newProxyInstance(loader, new Class[]{List.class}, handler); - } + public static List createTypifiedElementListProxy( + ClassLoader loader, + InvocationHandler handler) { + return (List) Proxy.newProxyInstance(loader, new Class[] {List.class}, handler); + } - public static List createHtmlElementListProxy(ClassLoader loader, - InvocationHandler handler) { - return (List) Proxy.newProxyInstance(loader, new Class[]{List.class}, handler); - } + public static List createHtmlElementListProxy(ClassLoader loader, + InvocationHandler handler) { + return (List) Proxy.newProxyInstance(loader, new Class[] {List.class}, handler); + } } diff --git a/src/main/java/com/frameworkium/core/htmlelements/loader/decorator/proxyhandlers/HtmlElementListNamedProxyHandler.java b/src/main/java/com/frameworkium/core/htmlelements/loader/decorator/proxyhandlers/HtmlElementListNamedProxyHandler.java index 7bbed886..a3070750 100755 --- a/src/main/java/com/frameworkium/core/htmlelements/loader/decorator/proxyhandlers/HtmlElementListNamedProxyHandler.java +++ b/src/main/java/com/frameworkium/core/htmlelements/loader/decorator/proxyhandlers/HtmlElementListNamedProxyHandler.java @@ -1,42 +1,44 @@ package com.frameworkium.core.htmlelements.loader.decorator.proxyhandlers; -import com.frameworkium.core.htmlelements.element.HtmlElement; -import org.openqa.selenium.support.pagefactory.ElementLocator; +import static com.frameworkium.core.htmlelements.loader.HtmlElementLoader.createHtmlElement; -import java.lang.reflect.*; +import com.frameworkium.core.htmlelements.element.HtmlElement; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.util.LinkedList; import java.util.List; import java.util.stream.Collectors; - -import static com.frameworkium.core.htmlelements.loader.HtmlElementLoader.createHtmlElement; +import org.openqa.selenium.support.pagefactory.ElementLocator; public class HtmlElementListNamedProxyHandler implements InvocationHandler { - private final Class elementClass; - private final ElementLocator locator; - private final String name; - - public HtmlElementListNamedProxyHandler(Class elementClass, ElementLocator locator, String name) { - this.elementClass = elementClass; - this.locator = locator; - this.name = name; + private final Class elementClass; + private final ElementLocator locator; + private final String name; + + public HtmlElementListNamedProxyHandler(Class elementClass, ElementLocator locator, + String name) { + this.elementClass = elementClass; + this.locator = locator; + this.name = name; + } + + @Override + public Object invoke(Object o, Method method, Object[] objects) throws Throwable { + if ("toString".equals(method.getName())) { + return name; } - @Override - public Object invoke(Object o, Method method, Object[] objects) throws Throwable { - if ("toString".equals(method.getName())) { - return name; - } - - List elements = locator.findElements().stream() - .map(element -> createHtmlElement(elementClass, element)) - .collect(Collectors.toCollection(LinkedList::new)); - - try { - return method.invoke(elements, objects); - } catch (InvocationTargetException e) { - // Unwrap the underlying exception - throw e.getCause(); - } + List elements = locator.findElements().stream() + .map(element -> createHtmlElement(elementClass, element)) + .collect(Collectors.toCollection(LinkedList::new)); + + try { + return method.invoke(elements, objects); + } catch (InvocationTargetException e) { + // Unwrap the underlying exception + throw e.getCause(); } + } } diff --git a/src/main/java/com/frameworkium/core/htmlelements/loader/decorator/proxyhandlers/TypifiedElementListNamedProxyHandler.java b/src/main/java/com/frameworkium/core/htmlelements/loader/decorator/proxyhandlers/TypifiedElementListNamedProxyHandler.java index 92f17fea..44993686 100755 --- a/src/main/java/com/frameworkium/core/htmlelements/loader/decorator/proxyhandlers/TypifiedElementListNamedProxyHandler.java +++ b/src/main/java/com/frameworkium/core/htmlelements/loader/decorator/proxyhandlers/TypifiedElementListNamedProxyHandler.java @@ -1,42 +1,45 @@ package com.frameworkium.core.htmlelements.loader.decorator.proxyhandlers; -import com.frameworkium.core.htmlelements.element.TypifiedElement; -import org.openqa.selenium.support.pagefactory.ElementLocator; +import static com.frameworkium.core.htmlelements.loader.HtmlElementLoader.createTypifiedElement; -import java.lang.reflect.*; +import com.frameworkium.core.htmlelements.element.TypifiedElement; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.util.LinkedList; import java.util.List; import java.util.stream.Collectors; +import org.openqa.selenium.support.pagefactory.ElementLocator; -import static com.frameworkium.core.htmlelements.loader.HtmlElementLoader.createTypifiedElement; +public class TypifiedElementListNamedProxyHandler + implements InvocationHandler { -public class TypifiedElementListNamedProxyHandler implements InvocationHandler { + private final Class elementClass; + private final ElementLocator locator; + private final String name; - private final Class elementClass; - private final ElementLocator locator; - private final String name; + public TypifiedElementListNamedProxyHandler(Class elementClass, ElementLocator locator, + String name) { + this.elementClass = elementClass; + this.locator = locator; + this.name = name; + } - public TypifiedElementListNamedProxyHandler(Class elementClass, ElementLocator locator, String name) { - this.elementClass = elementClass; - this.locator = locator; - this.name = name; + @Override + public Object invoke(Object o, Method method, Object[] objects) throws Throwable { + if ("toString".equals(method.getName())) { + return name; } - @Override - public Object invoke(Object o, Method method, Object[] objects) throws Throwable { - if ("toString".equals(method.getName())) { - return name; - } - - List elements = locator.findElements().stream() - .map(element -> createTypifiedElement(elementClass, element)) - .collect(Collectors.toCollection(LinkedList::new)); - - try { - return method.invoke(elements, objects); - } catch (InvocationTargetException e) { - // Unwrap the underlying exception - throw e.getCause(); - } + List elements = locator.findElements().stream() + .map(element -> createTypifiedElement(elementClass, element)) + .collect(Collectors.toCollection(LinkedList::new)); + + try { + return method.invoke(elements, objects); + } catch (InvocationTargetException e) { + // Unwrap the underlying exception + throw e.getCause(); } + } } diff --git a/src/main/java/com/frameworkium/core/htmlelements/loader/decorator/proxyhandlers/WebElementListNamedProxyHandler.java b/src/main/java/com/frameworkium/core/htmlelements/loader/decorator/proxyhandlers/WebElementListNamedProxyHandler.java index 27b20e59..5dc27f67 100755 --- a/src/main/java/com/frameworkium/core/htmlelements/loader/decorator/proxyhandlers/WebElementListNamedProxyHandler.java +++ b/src/main/java/com/frameworkium/core/htmlelements/loader/decorator/proxyhandlers/WebElementListNamedProxyHandler.java @@ -1,24 +1,23 @@ package com.frameworkium.core.htmlelements.loader.decorator.proxyhandlers; +import java.lang.reflect.Method; import org.openqa.selenium.support.pagefactory.ElementLocator; import org.openqa.selenium.support.pagefactory.internal.LocatingElementListHandler; -import java.lang.reflect.Method; - public class WebElementListNamedProxyHandler extends LocatingElementListHandler { - private final String name; + private final String name; - public WebElementListNamedProxyHandler(ElementLocator locator, String name) { - super(locator); - this.name = name; - } + public WebElementListNamedProxyHandler(ElementLocator locator, String name) { + super(locator); + this.name = name; + } - @Override - public Object invoke(Object o, Method method, Object[] objects) throws Throwable { - if ("toString".equals(method.getName())) { - return name; - } - return super.invoke(o, method, objects); + @Override + public Object invoke(Object o, Method method, Object[] objects) throws Throwable { + if ("toString".equals(method.getName())) { + return name; } + return super.invoke(o, method, objects); + } } diff --git a/src/main/java/com/frameworkium/core/htmlelements/loader/decorator/proxyhandlers/WebElementNamedProxyHandler.java b/src/main/java/com/frameworkium/core/htmlelements/loader/decorator/proxyhandlers/WebElementNamedProxyHandler.java index a5bc2dd7..48e30f64 100755 --- a/src/main/java/com/frameworkium/core/htmlelements/loader/decorator/proxyhandlers/WebElementNamedProxyHandler.java +++ b/src/main/java/com/frameworkium/core/htmlelements/loader/decorator/proxyhandlers/WebElementNamedProxyHandler.java @@ -1,53 +1,52 @@ package com.frameworkium.core.htmlelements.loader.decorator.proxyhandlers; import com.frameworkium.core.htmlelements.utils.HtmlElementUtils; -import org.openqa.selenium.StaleElementReferenceException; -import org.openqa.selenium.support.pagefactory.ElementLocator; -import org.openqa.selenium.support.pagefactory.internal.LocatingElementHandler; - import java.lang.reflect.Method; import java.time.Clock; import java.util.concurrent.TimeUnit; +import org.openqa.selenium.StaleElementReferenceException; +import org.openqa.selenium.support.pagefactory.ElementLocator; +import org.openqa.selenium.support.pagefactory.internal.LocatingElementHandler; public class WebElementNamedProxyHandler extends LocatingElementHandler { - private final long timeOutInSeconds; - private final Clock clock; - private final String name; - - public WebElementNamedProxyHandler(ElementLocator locator, String name) { - super(locator); - this.name = name; - this.clock = Clock.systemDefaultZone(); - this.timeOutInSeconds = HtmlElementUtils.getImplicitTimeoutInSeconds(); + private final long timeOutInSeconds; + private final Clock clock; + private final String name; + + public WebElementNamedProxyHandler(ElementLocator locator, String name) { + super(locator); + this.name = name; + this.clock = Clock.systemDefaultZone(); + this.timeOutInSeconds = HtmlElementUtils.getImplicitTimeoutInSeconds(); + } + + @Override + public Object invoke(Object o, Method method, Object[] objects) throws Throwable { + if ("toString".equals(method.getName())) { + return name; } - @Override - public Object invoke(Object o, Method method, Object[] objects) throws Throwable { - if ("toString".equals(method.getName())) { - return name; - } - - final long end = this.clock.millis() + TimeUnit.SECONDS.toMillis(this.timeOutInSeconds); - - StaleElementReferenceException lastException; - do { - try { - return super.invoke(o, method, objects); - } catch (StaleElementReferenceException e) { - lastException = e; - this.waitFor(); - } - } - while (this.clock.millis() < end); - throw lastException; - } + final long end = this.clock.millis() + TimeUnit.SECONDS.toMillis(this.timeOutInSeconds); - protected long sleepFor() { - return 500L; + StaleElementReferenceException lastException; + do { + try { + return super.invoke(o, method, objects); + } catch (StaleElementReferenceException e) { + lastException = e; + this.waitFor(); + } } + while (this.clock.millis() < end); + throw lastException; + } - private void waitFor() throws InterruptedException { - Thread.sleep(this.sleepFor()); - } + protected long sleepFor() { + return 500L; + } + + private void waitFor() throws InterruptedException { + Thread.sleep(this.sleepFor()); + } } diff --git a/src/main/java/com/frameworkium/core/htmlelements/pagefactory/CustomElementLocatorFactory.java b/src/main/java/com/frameworkium/core/htmlelements/pagefactory/CustomElementLocatorFactory.java index 5770d9fa..cd48138e 100755 --- a/src/main/java/com/frameworkium/core/htmlelements/pagefactory/CustomElementLocatorFactory.java +++ b/src/main/java/com/frameworkium/core/htmlelements/pagefactory/CustomElementLocatorFactory.java @@ -8,5 +8,5 @@ * ElementLocator will be returned per call. */ public interface CustomElementLocatorFactory extends ElementLocatorFactory { - ElementLocator createLocator(Class clazz); + ElementLocator createLocator(Class clazz); } diff --git a/src/main/java/com/frameworkium/core/htmlelements/utils/HtmlElementUtils.java b/src/main/java/com/frameworkium/core/htmlelements/utils/HtmlElementUtils.java index 9f593b0e..2690c8db 100755 --- a/src/main/java/com/frameworkium/core/htmlelements/utils/HtmlElementUtils.java +++ b/src/main/java/com/frameworkium/core/htmlelements/utils/HtmlElementUtils.java @@ -1,156 +1,161 @@ package com.frameworkium.core.htmlelements.utils; +import static org.apache.commons.lang3.reflect.ConstructorUtils.invokeConstructor; + import com.frameworkium.core.htmlelements.element.HtmlElement; import com.frameworkium.core.htmlelements.element.TypifiedElement; import com.frameworkium.core.htmlelements.exceptions.HtmlElementsException; import com.google.common.collect.Lists; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Modifier; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.net.URL; +import java.util.List; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.remote.RemoteWebDriver; import org.openqa.selenium.remote.RemoteWebElement; -import java.lang.reflect.*; -import java.net.URL; -import java.util.List; - -import static org.apache.commons.lang3.reflect.ConstructorUtils.invokeConstructor; - -/** Contains utility methods used in framework. */ +/** + * Contains utility methods used in framework. + */ public final class HtmlElementUtils { - /** - * Default implicit timeout for HtmlElements, should be less than - * any explicit waits to prevent - * {@code org.openqa.selenium.TimeoutException: Supplied function might have stalled} - */ - public static final int DEFAULT_TIMEOUT_SECS = 6; - - private HtmlElementUtils() { - } + /** + * Default implicit timeout for HtmlElements, should be less than + * any explicit waits to prevent + * {@code org.openqa.selenium.TimeoutException: Supplied function might have stalled} + */ + public static final int DEFAULT_TIMEOUT_SECS = 6; - public static T newInstance(Class clazz, Object... args) throws IllegalAccessException, - InstantiationException, NoSuchMethodException, InvocationTargetException { - if (clazz.isMemberClass() && !Modifier.isStatic(clazz.getModifiers())) { - Class outerClass = clazz.getDeclaringClass(); - Object outerObject = outerClass.newInstance(); - return invokeConstructor(clazz, Lists.asList(outerObject, args).toArray()); - } - return invokeConstructor(clazz, args); - } - - public static boolean isHtmlElement(Field field) { - return isHtmlElement(field.getType()); - } + private HtmlElementUtils() { + } - public static boolean isHtmlElement(Class clazz) { - return HtmlElement.class.isAssignableFrom(clazz); - } - - public static boolean isHtmlElement(T instance) { - return instance instanceof HtmlElement; - } - - public static boolean isTypifiedElement(Field field) { - return isTypifiedElement(field.getType()); - } - - public static boolean isTypifiedElement(Class clazz) { - return TypifiedElement.class.isAssignableFrom(clazz); - } - - public static boolean isWebElement(Field field) { - return isWebElement(field.getType()); - } - - public static boolean isWebElement(Class clazz) { - return WebElement.class.isAssignableFrom(clazz); - } - - public static boolean isHtmlElementList(Field field) { - if (!isParametrizedList(field)) { - return false; - } - Class listParameterClass = getGenericParameterClass(field); - return isHtmlElement(listParameterClass); - } - - public static boolean isTypifiedElementList(Field field) { - if (!isParametrizedList(field)) { - return false; - } - Class listParameterClass = getGenericParameterClass(field); - return isTypifiedElement(listParameterClass); - } - - public static boolean isWebElementList(Field field) { - if (!isParametrizedList(field)) { - return false; - } - Class listParameterClass = getGenericParameterClass(field); - return isWebElement(listParameterClass); - } - - public static Class getGenericParameterClass(Field field) { - Type genericType = field.getGenericType(); - return (Class) ((ParameterizedType) genericType).getActualTypeArguments()[0]; - } - - private static boolean isParametrizedList(Field field) { - return isList(field) && hasGenericParameter(field); - } - - private static boolean isList(Field field) { - return List.class.isAssignableFrom(field.getType()); - } - - private static boolean hasGenericParameter(Field field) { - return field.getGenericType() instanceof ParameterizedType; - } - - public static String getElementName(Field field) { - return field.getName(); - } - - public static String getElementName(Class clazz) { - return clazz.getSimpleName(); - } - - public static boolean isRemoteWebElement(WebElement element) { - return element.getClass().equals(RemoteWebElement.class); - } - - public static boolean isOnRemoteWebDriver(WebElement element) { - if (!isRemoteWebElement(element)) { - return false; - } - - // Since subclasses of RemoteWebElement were finally removed in Selenium 2.26.0, WebElements on local drivers - // are also instances of RemoteWebElement class. The only way that we found at the current moment to find out - // whether WebElement instance is on remote driver is to check the class of RemoteWebElement "parent" filed, - // which contains WebDriver instance to which this RemoteWebElement belongs. - // As this field has protected access this is done by reflection. - // TODO It's is a kind of a dirty hack to be improved in future versions. - RemoteWebElement remoteWebElement = (RemoteWebElement) element; - try { - Field elementParentFiled = RemoteWebElement.class.getDeclaredField("parent"); - elementParentFiled.setAccessible(true); - WebDriver elementParent = (WebDriver) elementParentFiled.get(remoteWebElement); - return elementParent.getClass().equals(RemoteWebDriver.class); - } catch (NoSuchFieldException | IllegalAccessException e) { - throw new HtmlElementsException("Unable to find out if WebElement is on remote driver", e); - } - } - - public static boolean existsInClasspath(final String fileName) { - return getResourceFromClasspath(fileName) != null; - } - - public static URL getResourceFromClasspath(final String fileName) { - return Thread.currentThread().getContextClassLoader().getResource(fileName); - } - - public static int getImplicitTimeoutInSeconds() { - return Integer.getInteger("webdriver.timeouts.implicitlywait", DEFAULT_TIMEOUT_SECS); - } + public static T newInstance(Class clazz, Object... args) throws IllegalAccessException, + InstantiationException, NoSuchMethodException, InvocationTargetException { + if (clazz.isMemberClass() && !Modifier.isStatic(clazz.getModifiers())) { + Class outerClass = clazz.getDeclaringClass(); + Object outerObject = outerClass.newInstance(); + return invokeConstructor(clazz, Lists.asList(outerObject, args).toArray()); + } + return invokeConstructor(clazz, args); + } + + public static boolean isHtmlElement(Field field) { + return isHtmlElement(field.getType()); + } + + public static boolean isHtmlElement(Class clazz) { + return HtmlElement.class.isAssignableFrom(clazz); + } + + public static boolean isHtmlElement(T instance) { + return instance instanceof HtmlElement; + } + + public static boolean isTypifiedElement(Field field) { + return isTypifiedElement(field.getType()); + } + + public static boolean isTypifiedElement(Class clazz) { + return TypifiedElement.class.isAssignableFrom(clazz); + } + + public static boolean isWebElement(Field field) { + return isWebElement(field.getType()); + } + + public static boolean isWebElement(Class clazz) { + return WebElement.class.isAssignableFrom(clazz); + } + + public static boolean isHtmlElementList(Field field) { + if (!isParametrizedList(field)) { + return false; + } + Class listParameterClass = getGenericParameterClass(field); + return isHtmlElement(listParameterClass); + } + + public static boolean isTypifiedElementList(Field field) { + if (!isParametrizedList(field)) { + return false; + } + Class listParameterClass = getGenericParameterClass(field); + return isTypifiedElement(listParameterClass); + } + + public static boolean isWebElementList(Field field) { + if (!isParametrizedList(field)) { + return false; + } + Class listParameterClass = getGenericParameterClass(field); + return isWebElement(listParameterClass); + } + + public static Class getGenericParameterClass(Field field) { + Type genericType = field.getGenericType(); + return (Class) ((ParameterizedType) genericType).getActualTypeArguments()[0]; + } + + private static boolean isParametrizedList(Field field) { + return isList(field) && hasGenericParameter(field); + } + + private static boolean isList(Field field) { + return List.class.isAssignableFrom(field.getType()); + } + + private static boolean hasGenericParameter(Field field) { + return field.getGenericType() instanceof ParameterizedType; + } + + public static String getElementName(Field field) { + return field.getName(); + } + + public static String getElementName(Class clazz) { + return clazz.getSimpleName(); + } + + public static boolean isRemoteWebElement(WebElement element) { + return element.getClass().equals(RemoteWebElement.class); + } + + public static boolean isOnRemoteWebDriver(WebElement element) { + if (!isRemoteWebElement(element)) { + return false; + } + + // Since subclasses of RemoteWebElement were finally removed in Selenium 2.26.0, WebElements on local drivers + // are also instances of RemoteWebElement class. The only way that we found at the current moment to find out + // whether WebElement instance is on remote driver is to check the class of RemoteWebElement "parent" filed, + // which contains WebDriver instance to which this RemoteWebElement belongs. + // As this field has protected access this is done by reflection. + // TODO It's is a kind of a dirty hack to be improved in future versions. + RemoteWebElement remoteWebElement = (RemoteWebElement) element; + try { + Field elementParentFiled = RemoteWebElement.class.getDeclaredField("parent"); + elementParentFiled.setAccessible(true); + WebDriver elementParent = (WebDriver) elementParentFiled.get(remoteWebElement); + return elementParent.getClass().equals(RemoteWebDriver.class); + } catch (NoSuchFieldException | IllegalAccessException e) { + throw new HtmlElementsException("Unable to find out if WebElement is on remote driver", e); + } + } + + public static boolean existsInClasspath(final String fileName) { + return getResourceFromClasspath(fileName) != null; + } + + public static URL getResourceFromClasspath(final String fileName) { + return Thread.currentThread().getContextClassLoader().getResource(fileName); + } + + public static int getImplicitTimeoutInSeconds() { + return Integer.getInteger("webdriver.timeouts.implicitlywait", DEFAULT_TIMEOUT_SECS); + } } diff --git a/src/main/java/com/frameworkium/core/ui/ExtraExpectedConditions.java b/src/main/java/com/frameworkium/core/ui/ExtraExpectedConditions.java index 75afbafb..e17f095f 100755 --- a/src/main/java/com/frameworkium/core/ui/ExtraExpectedConditions.java +++ b/src/main/java/com/frameworkium/core/ui/ExtraExpectedConditions.java @@ -1,12 +1,15 @@ package com.frameworkium.core.ui; -import org.openqa.selenium.*; -import org.openqa.selenium.support.ui.ExpectedCondition; -import org.openqa.selenium.support.ui.ExpectedConditions; - import java.util.List; import java.util.function.Function; import java.util.stream.Collectors; +import org.openqa.selenium.By; +import org.openqa.selenium.JavascriptExecutor; +import org.openqa.selenium.NoSuchElementException; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.support.ui.ExpectedCondition; +import org.openqa.selenium.support.ui.ExpectedConditions; /** * Frameworkium extension of {@link ExpectedConditions}. @@ -19,135 +22,135 @@ */ public class ExtraExpectedConditions { - protected ExtraExpectedConditions() { - // hide default constructor for this util class - // but allow subclassing for more specialised ExpectedConditions - } - - /** - * Custom wait which fills the gap left by Selenium whereby - * not({@link ExpectedConditions#visibilityOf(WebElement)}) - * will fail if the element is not present, but - * {@link ExpectedConditions#invisibilityOfElementLocated(By)} - * waits for either not visible or not present. - * - * @param element the element to wait for - * @return an {@link ExpectedCondition} which returns false - * if the element is visible, otherwise true. - */ - public static ExpectedCondition notPresentOrInvisible(WebElement element) { - - return expectedCondition( - driver -> { - try { - return !element.isDisplayed(); - } catch (NoSuchElementException e) { - return true; - } - }, - String.format("element '%s' to be not present or be invisible", element)); - } - - /** - * Overloaded {@link ExtraExpectedConditions#notPresentOrInvisible(WebElement)} - * for {@link List} of {@link WebElement}s. - * - * @param elements the lazy proxy for List<WebElement> to wait for - * @return an {@link ExpectedCondition} which returns the list - * iff any element is visible, otherwise null. - * @see ExtraExpectedConditions#notPresentOrInvisible(WebElement) - */ - public static ExpectedCondition> notPresentOrInvisible( - List elements) { - - return expectedCondition(driver -> - elements.stream() - .noneMatch(WebElement::isDisplayed) - ? elements - : null, - String.format( - "the following elements to not be present or be invisible: %s", - elements.stream() - .map(WebElement::toString) - .collect(Collectors.joining(", ")))); - } - - /** - * Useful for waiting for items to be added to a list. - * - * @param list the lazy proxy for List<WebElement> - * @param expectedSize expected expectedSize to be greater than - * @return the original list if list size is greater than expectedSize, else null - */ - public static ExpectedCondition> sizeGreaterThan( - List list, int expectedSize) { - - return expectedCondition( - driver -> list.size() > expectedSize ? list : null, - "list size of " + list.size() + " to be greater than " + expectedSize); - } - - /** - * Useful for waiting for items to be removed from a list. - * - * @param list the lazy proxy for List<WebElement> - * @param expectedSize expected expectedSize to be less than - * @return the original list if list size is less than expectedSize, else null - */ - public static ExpectedCondition> sizeLessThan( - List list, int expectedSize) { - - return expectedCondition( - driver -> list.size() < expectedSize ? list : null, - "list size of " + list.size() + " to be less than " + expectedSize); - } - - /** - * Wait until all jQuery AJAX calls are done. - * - * @return true iff jQuery is available and 0 ajax queries are active. - */ - public static ExpectedCondition jQueryAjaxDone() { - - return javascriptExpectedCondition( - "return !!window.jQuery && jQuery.active === 0;", - "jQuery AJAX queries to not be active"); - } - - /** - * Wait for the document ready state to equal 'complete'. - * Useful for javascript loading on page-load. - * - * @return a {@link ExpectedCondition} which returns false if the document - * isn't ready, and true if the document is ready - */ - public static ExpectedCondition documentBodyReady() { - - return javascriptExpectedCondition( - "return document.readyState == 'complete';", - "the document ready state to equal 'complete'"); - } - - private static ExpectedCondition javascriptExpectedCondition( - String query, String message) { - return expectedCondition( - driver -> (Boolean) ((JavascriptExecutor) driver).executeScript(query), - message); - } - - private static ExpectedCondition expectedCondition( - Function function, String string) { - - return new ExpectedCondition() { - @Override - public T apply(WebDriver driver) { - return function.apply(driver); - } - - @Override - public String toString() { - return string; - } - }; - } + protected ExtraExpectedConditions() { + // hide default constructor for this util class + // but allow subclassing for more specialised ExpectedConditions + } + + /** + * Custom wait which fills the gap left by Selenium whereby + * not({@link ExpectedConditions#visibilityOf(WebElement)}) + * will fail if the element is not present, but + * {@link ExpectedConditions#invisibilityOfElementLocated(By)} + * waits for either not visible or not present. + * + * @param element the element to wait for + * @return an {@link ExpectedCondition} which returns false + * if the element is visible, otherwise true. + */ + public static ExpectedCondition notPresentOrInvisible(WebElement element) { + + return expectedCondition( + driver -> { + try { + return !element.isDisplayed(); + } catch (NoSuchElementException e) { + return true; + } + }, + String.format("element '%s' to be not present or be invisible", element)); + } + + /** + * Overloaded {@link ExtraExpectedConditions#notPresentOrInvisible(WebElement)} + * for {@link List} of {@link WebElement}s. + * + * @param elements the lazy proxy for List<WebElement> to wait for + * @return an {@link ExpectedCondition} which returns the list + * iff any element is visible, otherwise null. + * @see ExtraExpectedConditions#notPresentOrInvisible(WebElement) + */ + public static ExpectedCondition> notPresentOrInvisible( + List elements) { + + return expectedCondition(driver -> + elements.stream() + .noneMatch(WebElement::isDisplayed) + ? elements + : null, + String.format( + "the following elements to not be present or be invisible: %s", + elements.stream() + .map(WebElement::toString) + .collect(Collectors.joining(", ")))); + } + + /** + * Useful for waiting for items to be added to a list. + * + * @param list the lazy proxy for List<WebElement> + * @param expectedSize expected expectedSize to be greater than + * @return the original list if list size is greater than expectedSize, else null + */ + public static ExpectedCondition> sizeGreaterThan( + List list, int expectedSize) { + + return expectedCondition( + driver -> list.size() > expectedSize ? list : null, + "list size of " + list.size() + " to be greater than " + expectedSize); + } + + /** + * Useful for waiting for items to be removed from a list. + * + * @param list the lazy proxy for List<WebElement> + * @param expectedSize expected expectedSize to be less than + * @return the original list if list size is less than expectedSize, else null + */ + public static ExpectedCondition> sizeLessThan( + List list, int expectedSize) { + + return expectedCondition( + driver -> list.size() < expectedSize ? list : null, + "list size of " + list.size() + " to be less than " + expectedSize); + } + + /** + * Wait until all jQuery AJAX calls are done. + * + * @return true iff jQuery is available and 0 ajax queries are active. + */ + public static ExpectedCondition jQueryAjaxDone() { + + return javascriptExpectedCondition( + "return !!window.jQuery && jQuery.active === 0;", + "jQuery AJAX queries to not be active"); + } + + /** + * Wait for the document ready state to equal 'complete'. + * Useful for javascript loading on page-load. + * + * @return a {@link ExpectedCondition} which returns false if the document + * isn't ready, and true if the document is ready + */ + public static ExpectedCondition documentBodyReady() { + + return javascriptExpectedCondition( + "return document.readyState == 'complete';", + "the document ready state to equal 'complete'"); + } + + private static ExpectedCondition javascriptExpectedCondition( + String query, String message) { + return expectedCondition( + driver -> (Boolean) ((JavascriptExecutor) driver).executeScript(query), + message); + } + + private static ExpectedCondition expectedCondition( + Function function, String string) { + + return new ExpectedCondition() { + @Override + public T apply(WebDriver driver) { + return function.apply(driver); + } + + @Override + public String toString() { + return string; + } + }; + } } diff --git a/src/main/java/com/frameworkium/core/ui/UITestLifecycle.java b/src/main/java/com/frameworkium/core/ui/UITestLifecycle.java index 693241fb..64577ab5 100644 --- a/src/main/java/com/frameworkium/core/ui/UITestLifecycle.java +++ b/src/main/java/com/frameworkium/core/ui/UITestLifecycle.java @@ -1,26 +1,28 @@ package com.frameworkium.core.ui; +import static java.time.temporal.ChronoUnit.SECONDS; + import com.frameworkium.core.common.properties.Property; import com.frameworkium.core.common.reporting.TestIdUtils; import com.frameworkium.core.common.reporting.allure.AllureProperties; import com.frameworkium.core.ui.browsers.UserAgent; import com.frameworkium.core.ui.capture.ScreenshotCapture; import com.frameworkium.core.ui.driver.DriverSetup; -import com.frameworkium.core.ui.driver.lifecycle.*; -import org.apache.commons.lang3.StringUtils; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.openqa.selenium.*; -import org.openqa.selenium.remote.RemoteWebDriver; -import org.openqa.selenium.support.ui.FluentWait; -import org.openqa.selenium.support.ui.Wait; - +import com.frameworkium.core.ui.driver.lifecycle.DriverLifecycle; +import com.frameworkium.core.ui.driver.lifecycle.MultiUseDriverLifecycle; +import com.frameworkium.core.ui.driver.lifecycle.SingleUseDriverLifecycle; import java.lang.reflect.Method; import java.time.Duration; import java.util.Objects; import java.util.Optional; - -import static java.time.temporal.ChronoUnit.SECONDS; +import org.apache.commons.lang3.StringUtils; +import org.openqa.selenium.JavascriptExecutor; +import org.openqa.selenium.NoSuchElementException; +import org.openqa.selenium.StaleElementReferenceException; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.remote.RemoteWebDriver; +import org.openqa.selenium.support.ui.FluentWait; +import org.openqa.selenium.support.ui.Wait; /** * Handles all UI test related state and life cycle. @@ -28,133 +30,144 @@ */ public class UITestLifecycle { - private static final Duration DEFAULT_TIMEOUT = Duration.of(10, SECONDS); - - private static final ThreadLocal capture = new ThreadLocal<>(); - private static final ThreadLocal> wait = new ThreadLocal<>(); - private static final ThreadLocal uiTestLifecycle = ThreadLocal.withInitial(UITestLifecycle::new); - - private static DriverLifecycle driverLifecycle; - private static String userAgent; - - /** @return a ThreadLocal instance of {@link UITestLifecycle} */ - public static UITestLifecycle get() { - return uiTestLifecycle.get(); - } - - /** @return check to see if class initialised correctly. */ - public boolean isInitialised() { - return wait.get() != null; - } - - /** Run this before the test suite to initialise a pool of drivers. */ - public void beforeSuite() { - if (Property.REUSE_BROWSER.getBoolean()) { - driverLifecycle = - new MultiUseDriverLifecycle( - Property.THREADS.getIntWithDefault(1)); - } else { - driverLifecycle = new SingleUseDriverLifecycle(); - } - driverLifecycle.initDriverPool(DriverSetup::instantiateDriver); + private static final Duration DEFAULT_TIMEOUT = Duration.of(10, SECONDS); + + private static final ThreadLocal capture = new ThreadLocal<>(); + private static final ThreadLocal> wait = new ThreadLocal<>(); + private static final ThreadLocal uiTestLifecycle = + ThreadLocal.withInitial(UITestLifecycle::new); + + private static DriverLifecycle driverLifecycle; + private static String userAgent; + + /** + * @return a ThreadLocal instance of {@link UITestLifecycle} + */ + public static UITestLifecycle get() { + return uiTestLifecycle.get(); + } + + /** + * @return check to see if class initialised correctly. + */ + public boolean isInitialised() { + return wait.get() != null; + } + + /** + * Run this before the test suite to initialise a pool of drivers. + */ + public void beforeSuite() { + if (Property.REUSE_BROWSER.getBoolean()) { + driverLifecycle = + new MultiUseDriverLifecycle( + Property.THREADS.getIntWithDefault(1)); + } else { + driverLifecycle = new SingleUseDriverLifecycle(); } - - /** - * Run this before each test method to initialise the - * browser, wait, capture, and user agent. - * - *

This is useful for times when the testMethod does not contain the required - * test name e.g. using data providers for BDD. - * - * @param testName the test name for Capture - */ - public void beforeTestMethod(String testName) { - driverLifecycle.initBrowserBeforeTest(DriverSetup::instantiateDriver); - - wait.set(newWaitWithTimeout(DEFAULT_TIMEOUT)); - - if (ScreenshotCapture.isRequired()) { - capture.set(new ScreenshotCapture(testName)); - } - - if (userAgent == null) { - userAgent = UserAgent.getUserAgent((JavascriptExecutor) getWebDriver()); - } - } - - /** - * @param testMethod the method about to run, used to extract the test name - * @see #beforeTestMethod(String) - */ - public void beforeTestMethod(Method testMethod) { - beforeTestMethod(getTestNameForCapture(testMethod)); - } - - private String getTestNameForCapture(Method testMethod) { - Optional testID = TestIdUtils.getIssueOrTmsLinkValue(testMethod); - if (!testID.isPresent() || testID.get().isEmpty()) { - testID = Optional.of(StringUtils.abbreviate(testMethod.getName(), 20)); - } - return testID.orElse("n/a"); - } - - /** Run after each test method to clear or tear down the browser */ - public void afterTestMethod() { - driverLifecycle.tearDownDriver(); - } - - /** - * Run after the entire test suite to: - * clear down the browser pool, send remaining screenshots to Capture - * and create properties for Allure. - */ - public void afterTestSuite() { - driverLifecycle.tearDownDriverPool(); - ScreenshotCapture.processRemainingBacklog(); - AllureProperties.createUI(); - } - - /** - * @return new Wait with default timeout. - * @deprecated use {@code UITestLifecycle.get().getWait()} instead. - */ - @Deprecated - public Wait newDefaultWait() { - return newWaitWithTimeout(DEFAULT_TIMEOUT); - } - - /** - * @param timeout timeout for the new Wait - * @return a Wait with the given timeout - */ - public Wait newWaitWithTimeout(Duration timeout) { - return new FluentWait<>(getWebDriver()) - .withTimeout(timeout) - .ignoring(NoSuchElementException.class) - .ignoring(StaleElementReferenceException.class); - } - - public WebDriver getWebDriver() { - return driverLifecycle.getWebDriver(); + driverLifecycle.initDriverPool(DriverSetup::instantiateDriver); + } + + /** + * Run this before each test method to initialise the + * browser, wait, capture, and user agent. + * + *

This is useful for times when the testMethod does not contain the required + * test name e.g. using data providers for BDD. + * + * @param testName the test name for Capture + */ + public void beforeTestMethod(String testName) { + driverLifecycle.initBrowserBeforeTest(DriverSetup::instantiateDriver); + + wait.set(newWaitWithTimeout(DEFAULT_TIMEOUT)); + + if (ScreenshotCapture.isRequired()) { + capture.set(new ScreenshotCapture(testName)); } - public ScreenshotCapture getCapture() { - return capture.get(); + if (userAgent == null) { + userAgent = UserAgent.getUserAgent((JavascriptExecutor) getWebDriver()); } - - public Wait getWait() { - return wait.get(); - } - - /** - * @return the user agent of the browser in the first UI test to run. - */ - public Optional getUserAgent() { - return Optional.ofNullable(userAgent); - } - - /** @return the session ID of the remote WebDriver */ - public String getRemoteSessionId() { - return Objects.toString(((RemoteWebDriver) getWebDriver()).getSessionId()); + } + + /** + * @param testMethod the method about to run, used to extract the test name + * @see #beforeTestMethod(String) + */ + public void beforeTestMethod(Method testMethod) { + beforeTestMethod(getTestNameForCapture(testMethod)); + } + + private String getTestNameForCapture(Method testMethod) { + Optional testID = TestIdUtils.getIssueOrTmsLinkValue(testMethod); + if (!testID.isPresent() || testID.get().isEmpty()) { + testID = Optional.of(StringUtils.abbreviate(testMethod.getName(), 20)); } + return testID.orElse("n/a"); + } + + /** + * Run after each test method to clear or tear down the browser + */ + public void afterTestMethod() { + driverLifecycle.tearDownDriver(); + } + + /** + * Run after the entire test suite to: + * clear down the browser pool, send remaining screenshots to Capture + * and create properties for Allure. + */ + public void afterTestSuite() { + driverLifecycle.tearDownDriverPool(); + ScreenshotCapture.processRemainingBacklog(); + AllureProperties.createUI(); + } + + /** + * @return new Wait with default timeout. + * @deprecated use {@code UITestLifecycle.get().getWait()} instead. + */ + @Deprecated + public Wait newDefaultWait() { + return newWaitWithTimeout(DEFAULT_TIMEOUT); + } + + /** + * @param timeout timeout for the new Wait + * @return a Wait with the given timeout + */ + public Wait newWaitWithTimeout(Duration timeout) { + return new FluentWait<>(getWebDriver()) + .withTimeout(timeout) + .ignoring(NoSuchElementException.class) + .ignoring(StaleElementReferenceException.class); + } + + public WebDriver getWebDriver() { + return driverLifecycle.getWebDriver(); + } + + public ScreenshotCapture getCapture() { + return capture.get(); + } + + public Wait getWait() { + return wait.get(); + } + + /** + * @return the user agent of the browser in the first UI test to run. + */ + public Optional getUserAgent() { + return Optional.ofNullable(userAgent); + } + + /** + * @return the session ID of the remote WebDriver + */ + public String getRemoteSessionId() { + return Objects.toString(((RemoteWebDriver) getWebDriver()).getSessionId()); + } } diff --git a/src/main/java/com/frameworkium/core/ui/annotations/ForceVisible.java b/src/main/java/com/frameworkium/core/ui/annotations/ForceVisible.java index b251e483..3fda8fe2 100644 --- a/src/main/java/com/frameworkium/core/ui/annotations/ForceVisible.java +++ b/src/main/java/com/frameworkium/core/ui/annotations/ForceVisible.java @@ -1,18 +1,23 @@ package com.frameworkium.core.ui.annotations; -import java.lang.annotation.*; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface ForceVisible { - /** Default value. */ - String value() default ""; + /** + * Default value. + */ + String value() default ""; - /** - * If checking for visibility of a list of elements, setting a value - * will only check for visibility of the first n elements of the list. - */ - int checkAtMost() default -1; + /** + * If checking for visibility of a list of elements, setting a value + * will only check for visibility of the first n elements of the list. + */ + int checkAtMost() default -1; } diff --git a/src/main/java/com/frameworkium/core/ui/annotations/Invisible.java b/src/main/java/com/frameworkium/core/ui/annotations/Invisible.java index 96226e0b..067e5136 100644 --- a/src/main/java/com/frameworkium/core/ui/annotations/Invisible.java +++ b/src/main/java/com/frameworkium/core/ui/annotations/Invisible.java @@ -1,18 +1,23 @@ package com.frameworkium.core.ui.annotations; -import java.lang.annotation.*; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface Invisible { - /** Default value. */ - String value() default ""; + /** + * Default value. + */ + String value() default ""; - /** - * If checking for invisibility of a list of elements, setting a value - * will only check for invisibility of the first n elements of the list. - */ - int checkAtMost() default -1; + /** + * If checking for invisibility of a list of elements, setting a value + * will only check for invisibility of the first n elements of the list. + */ + int checkAtMost() default -1; } diff --git a/src/main/java/com/frameworkium/core/ui/annotations/Visible.java b/src/main/java/com/frameworkium/core/ui/annotations/Visible.java index 71e3e63e..d12698e3 100644 --- a/src/main/java/com/frameworkium/core/ui/annotations/Visible.java +++ b/src/main/java/com/frameworkium/core/ui/annotations/Visible.java @@ -1,17 +1,22 @@ package com.frameworkium.core.ui.annotations; -import java.lang.annotation.*; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface Visible { - /** Default value. */ - String value() default ""; + /** + * Default value. + */ + String value() default ""; - /** - * If checking for visibility of a list of elements, setting a value - * will only check for visibility of the first n elements of the list. - */ - int checkAtMost() default -1; + /** + * If checking for visibility of a list of elements, setting a value + * will only check for visibility of the first n elements of the list. + */ + int checkAtMost() default -1; } diff --git a/src/main/java/com/frameworkium/core/ui/browsers/UserAgent.java b/src/main/java/com/frameworkium/core/ui/browsers/UserAgent.java index d73bb970..bc4b1edc 100644 --- a/src/main/java/com/frameworkium/core/ui/browsers/UserAgent.java +++ b/src/main/java/com/frameworkium/core/ui/browsers/UserAgent.java @@ -4,17 +4,17 @@ public class UserAgent { - public static final String SCRIPT = "return navigator.userAgent;"; + public static final String SCRIPT = "return navigator.userAgent;"; - private UserAgent() { - // hidden - } + private UserAgent() { + // hidden + } - public static String getUserAgent(JavascriptExecutor driver) { - try { - return (String) driver.executeScript(SCRIPT); - } catch (Exception ignored) { - return null; - } + public static String getUserAgent(JavascriptExecutor driver) { + try { + return (String) driver.executeScript(SCRIPT); + } catch (Exception ignored) { + return null; } + } } diff --git a/src/main/java/com/frameworkium/core/ui/capture/CaptureEndpoint.java b/src/main/java/com/frameworkium/core/ui/capture/CaptureEndpoint.java index 04c8ce33..4a0397a4 100755 --- a/src/main/java/com/frameworkium/core/ui/capture/CaptureEndpoint.java +++ b/src/main/java/com/frameworkium/core/ui/capture/CaptureEndpoint.java @@ -3,22 +3,24 @@ import com.frameworkium.core.api.Endpoint; import com.frameworkium.core.common.properties.Property; -/** The various Endpoints of Capture. */ +/** + * The various Endpoints of Capture. + */ enum CaptureEndpoint implements Endpoint { - BASE_URI(Property.CAPTURE_URL.getValue()), - EXECUTIONS(BASE_URI.url + "/executions"), - SCREENSHOT(BASE_URI.url + "/screenshot"); + BASE_URI(Property.CAPTURE_URL.getValue()), + EXECUTIONS(BASE_URI.url + "/executions"), + SCREENSHOT(BASE_URI.url + "/screenshot"); - private String url; + private String url; - CaptureEndpoint(String url) { - this.url = url; - } + CaptureEndpoint(String url) { + this.url = url; + } - @Override - public String getUrl(Object... params) { - return String.format(url, params); - } + @Override + public String getUrl(Object... params) { + return String.format(url, params); + } } diff --git a/src/main/java/com/frameworkium/core/ui/capture/ElementHighlighter.java b/src/main/java/com/frameworkium/core/ui/capture/ElementHighlighter.java index 8aea51bb..83008644 100644 --- a/src/main/java/com/frameworkium/core/ui/capture/ElementHighlighter.java +++ b/src/main/java/com/frameworkium/core/ui/capture/ElementHighlighter.java @@ -1,42 +1,45 @@ package com.frameworkium.core.ui.capture; -import org.openqa.selenium.*; +import org.openqa.selenium.JavascriptExecutor; +import org.openqa.selenium.StaleElementReferenceException; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; public class ElementHighlighter { - private JavascriptExecutor js; - private WebElement previousElem; - - public ElementHighlighter(WebDriver driver) { - js = (JavascriptExecutor) driver; - } - - /** - * Highlight a WebElement. - * - * @param webElement to highlight - */ - public void highlightElement(WebElement webElement) { - - previousElem = webElement; // remember the new element - try { - // TODO: save the previous border - js.executeScript("arguments[0].style.border='3px solid red'", webElement); - } catch (StaleElementReferenceException ignored) { - // something went wrong, but no need to crash for highlighting - } + private JavascriptExecutor js; + private WebElement previousElem; + + public ElementHighlighter(WebDriver driver) { + js = (JavascriptExecutor) driver; + } + + /** + * Highlight a WebElement. + * + * @param webElement to highlight + */ + public void highlightElement(WebElement webElement) { + + previousElem = webElement; // remember the new element + try { + // TODO: save the previous border + js.executeScript("arguments[0].style.border='3px solid red'", webElement); + } catch (StaleElementReferenceException ignored) { + // something went wrong, but no need to crash for highlighting } - - /** - * Unhighlight the previously highlighted WebElement. - */ - public void unhighlightPrevious() { - - try { - // unhighlight the previously highlighted element - js.executeScript("arguments[0].style.border='none'", previousElem); - } catch (StaleElementReferenceException ignored) { - // the page was reloaded/changed, the same element isn't there - } + } + + /** + * Unhighlight the previously highlighted WebElement. + */ + public void unhighlightPrevious() { + + try { + // unhighlight the previously highlighted element + js.executeScript("arguments[0].style.border='none'", previousElem); + } catch (StaleElementReferenceException ignored) { + // the page was reloaded/changed, the same element isn't there } + } } diff --git a/src/main/java/com/frameworkium/core/ui/capture/ScreenshotCapture.java b/src/main/java/com/frameworkium/core/ui/capture/ScreenshotCapture.java index 75c0b4e0..50556c06 100755 --- a/src/main/java/com/frameworkium/core/ui/capture/ScreenshotCapture.java +++ b/src/main/java/com/frameworkium/core/ui/capture/ScreenshotCapture.java @@ -1,5 +1,10 @@ package com.frameworkium.core.ui.capture; +import static com.frameworkium.core.common.properties.Property.CAPTURE_URL; +import static com.frameworkium.core.common.properties.Property.SUT_NAME; +import static com.frameworkium.core.common.properties.Property.SUT_VERSION; +import static org.apache.http.HttpStatus.SC_CREATED; + import com.frameworkium.core.common.properties.Property; import com.frameworkium.core.ui.UITestLifecycle; import com.frameworkium.core.ui.capture.model.Command; @@ -12,181 +17,190 @@ import io.restassured.RestAssured; import io.restassured.http.ContentType; import io.restassured.specification.RequestSpecification; +import java.net.InetAddress; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.UnknownHostException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.openqa.selenium.*; - -import java.net.*; -import java.util.concurrent.*; - -import static com.frameworkium.core.common.properties.Property.*; -import static org.apache.http.HttpStatus.SC_CREATED; +import org.openqa.selenium.OutputType; +import org.openqa.selenium.TakesScreenshot; +import org.openqa.selenium.WebDriver; -/** Takes and sends screenshots to "Capture" asynchronously. */ +/** + * Takes and sends screenshots to "Capture" asynchronously. + */ public class ScreenshotCapture { - private static final Logger logger = LogManager.getLogger(); + private static final Logger logger = LogManager.getLogger(); - /** Shared Executor for async sending of screenshot messages to capture. */ - private static final ExecutorService executorService = - Executors.newFixedThreadPool(4); + /** + * Shared Executor for async sending of screenshot messages to capture. + */ + private static final ExecutorService executorService = + Executors.newFixedThreadPool(4); - private String testID; - private String executionID; - - public ScreenshotCapture(String testID) { - logger.debug("About to initialise Capture execution for " + testID); - this.testID = testID; - this.executionID = createExecution(new CreateExecution(testID, getNode())); - logger.debug("Capture executionID=" + executionID); - } - - private String createExecution(CreateExecution createExecution) { - try { - return getRequestSpec() - .body(createExecution) - .when() - .post(CaptureEndpoint.EXECUTIONS.getUrl()) - .then().statusCode(SC_CREATED) - .extract().path("executionID").toString(); - } catch (Exception e) { - logger.error("Unable to create Capture execution.", e); - return null; - } - } + private String testID; + private String executionID; - private RequestSpecification getRequestSpec() { - return RestAssured.given() - .relaxedHTTPSValidation() - .contentType(ContentType.JSON); - } + public ScreenshotCapture(String testID) { + logger.debug("About to initialise Capture execution for " + testID); + this.testID = testID; + this.executionID = createExecution(new CreateExecution(testID, getNode())); + logger.debug("Capture executionID=" + executionID); + } - private String getNode() { - String node = "n/a"; - if (DriverSetup.useRemoteDriver()) { - node = getRemoteNode(node); - } else { - try { - node = InetAddress.getLocalHost().getCanonicalHostName(); - } catch (UnknownHostException e) { - logger.debug("Failed to get local machine name", e); - } - } - return node; - } + public static boolean isRequired() { + boolean allCapturePropertiesSpecified = CAPTURE_URL.isSpecified() + && SUT_NAME.isSpecified() + && SUT_VERSION.isSpecified(); + return allCapturePropertiesSpecified && !Driver.isNative(); + } - private String getRemoteNode(String defaultValue) { - if (Sauce.isDesired()) { - return "SauceLabs"; - } else if (BrowserStack.isDesired()) { - return "BrowserStack"; - } else { - try { - return getRemoteNodeAddress(); - } catch (Exception e) { - logger.warn("Failed to get node address of remote web driver"); - logger.debug(e); - } - } - return defaultValue; - } + /** + * Waits up to 2 minutes to send any remaining Screenshot messages. + */ + public static void processRemainingBacklog() { - private String getRemoteNodeAddress() throws MalformedURLException { - return RestAssured - .get(getTestSessionURL()) - .then() - .extract().jsonPath() - .getString("proxyId"); - } + executorService.shutdown(); - private String getTestSessionURL() throws MalformedURLException { - URL gridURL = new URL(Property.GRID_URL.getValue()); - return String.format( - "%s://%s:%d/grid/api/testsession?session=%s", - gridURL.getProtocol(), - gridURL.getHost(), - gridURL.getPort(), - UITestLifecycle.get().getRemoteSessionId()); + if (!isRequired()) { + return; } - public static boolean isRequired() { - boolean allCapturePropertiesSpecified = CAPTURE_URL.isSpecified() - && SUT_NAME.isSpecified() - && SUT_VERSION.isSpecified(); - return allCapturePropertiesSpecified && !Driver.isNative(); + logger.info("Processing remaining Screenshot Capture backlog..."); + boolean timeout; + try { + timeout = !executorService.awaitTermination(2, TimeUnit.MINUTES); + } catch (InterruptedException e) { + throw new IllegalStateException(e); } - - public void takeAndSendScreenshot(Command command, WebDriver driver) { - takeAndSendScreenshotWithError(command, driver, null); + if (timeout) { + logger.error("Shutdown timed out. " + + "Some screenshots might not have been sent."); + } else { + logger.info("Finished processing backlog."); } - - /** - * Take and send a screenshot with an error message. - */ - public void takeAndSendScreenshotWithError( - Command command, WebDriver driver, String errorMessage) { - - if (executionID == null) { - logger.error("Can't send Screenshot. " - + "Capture didn't initialise execution for test: " + testID); - return; - } - - CreateScreenshot createScreenshotMessage = - new CreateScreenshot( - executionID, - command, - driver.getCurrentUrl(), - errorMessage, - getBase64Screenshot((TakesScreenshot) driver)); - addScreenshotToSendQueue(createScreenshotMessage); + } + + private String createExecution(CreateExecution createExecution) { + try { + return getRequestSpec() + .body(createExecution) + .when() + .post(CaptureEndpoint.EXECUTIONS.getUrl()) + .then().statusCode(SC_CREATED) + .extract().path("executionID").toString(); + } catch (Exception e) { + logger.error("Unable to create Capture execution.", e); + return null; } - - private String getBase64Screenshot(TakesScreenshot driver) { - return driver.getScreenshotAs(OutputType.BASE64); + } + + private RequestSpecification getRequestSpec() { + return RestAssured.given() + .relaxedHTTPSValidation() + .contentType(ContentType.JSON); + } + + private String getNode() { + String node = "n/a"; + if (DriverSetup.useRemoteDriver()) { + node = getRemoteNode(node); + } else { + try { + node = InetAddress.getLocalHost().getCanonicalHostName(); + } catch (UnknownHostException e) { + logger.debug("Failed to get local machine name", e); + } } - - private void addScreenshotToSendQueue(CreateScreenshot createScreenshotMessage) { - executorService.execute(() -> sendScreenshot(createScreenshotMessage)); + return node; + } + + private String getRemoteNode(String defaultValue) { + if (Sauce.isDesired()) { + return "SauceLabs"; + } else if (BrowserStack.isDesired()) { + return "BrowserStack"; + } else { + try { + return getRemoteNodeAddress(); + } catch (Exception e) { + logger.warn("Failed to get node address of remote web driver"); + logger.debug(e); + } } - - private void sendScreenshot(CreateScreenshot createScreenshotMessage) { - logger.debug("About to send screenshot to Capture for {}", testID); - try { - getRequestSpec() - .body(createScreenshotMessage) - .when() - .post(CaptureEndpoint.SCREENSHOT.getUrl()) - .then() - .assertThat().statusCode(SC_CREATED); - logger.debug("Sent screenshot to Capture for " + testID); - } catch (Exception e) { - logger.warn("Failed sending screenshot to Capture for " + testID); - logger.debug(e); - } + return defaultValue; + } + + private String getRemoteNodeAddress() throws MalformedURLException { + return RestAssured + .get(getTestSessionURL()) + .then() + .extract().jsonPath() + .getString("proxyId"); + } + + private String getTestSessionURL() throws MalformedURLException { + URL gridURL = new URL(Property.GRID_URL.getValue()); + return String.format( + "%s://%s:%d/grid/api/testsession?session=%s", + gridURL.getProtocol(), + gridURL.getHost(), + gridURL.getPort(), + UITestLifecycle.get().getRemoteSessionId()); + } + + public void takeAndSendScreenshot(Command command, WebDriver driver) { + takeAndSendScreenshotWithError(command, driver, null); + } + + /** + * Take and send a screenshot with an error message. + */ + public void takeAndSendScreenshotWithError( + Command command, WebDriver driver, String errorMessage) { + + if (executionID == null) { + logger.error("Can't send Screenshot. " + + "Capture didn't initialise execution for test: " + testID); + return; } - /** Waits up to 2 minutes to send any remaining Screenshot messages. */ - public static void processRemainingBacklog() { - - executorService.shutdown(); - - if (!isRequired()) { - return; - } - - logger.info("Processing remaining Screenshot Capture backlog..."); - boolean timeout; - try { - timeout = !executorService.awaitTermination(2, TimeUnit.MINUTES); - } catch (InterruptedException e) { - throw new IllegalStateException(e); - } - if (timeout) { - logger.error("Shutdown timed out. " - + "Some screenshots might not have been sent."); - } else { - logger.info("Finished processing backlog."); - } + CreateScreenshot createScreenshotMessage = + new CreateScreenshot( + executionID, + command, + driver.getCurrentUrl(), + errorMessage, + getBase64Screenshot((TakesScreenshot) driver)); + addScreenshotToSendQueue(createScreenshotMessage); + } + + private String getBase64Screenshot(TakesScreenshot driver) { + return driver.getScreenshotAs(OutputType.BASE64); + } + + private void addScreenshotToSendQueue(CreateScreenshot createScreenshotMessage) { + executorService.execute(() -> sendScreenshot(createScreenshotMessage)); + } + + private void sendScreenshot(CreateScreenshot createScreenshotMessage) { + logger.debug("About to send screenshot to Capture for {}", testID); + try { + getRequestSpec() + .body(createScreenshotMessage) + .when() + .post(CaptureEndpoint.SCREENSHOT.getUrl()) + .then() + .assertThat().statusCode(SC_CREATED); + logger.debug("Sent screenshot to Capture for " + testID); + } catch (Exception e) { + logger.warn("Failed sending screenshot to Capture for " + testID); + logger.debug(e); } + } } diff --git a/src/main/java/com/frameworkium/core/ui/capture/model/Browser.java b/src/main/java/com/frameworkium/core/ui/capture/model/Browser.java index c90e9b11..b9a59339 100644 --- a/src/main/java/com/frameworkium/core/ui/capture/model/Browser.java +++ b/src/main/java/com/frameworkium/core/ui/capture/model/Browser.java @@ -1,61 +1,64 @@ package com.frameworkium.core.ui.capture.model; +import static com.frameworkium.core.common.properties.Property.BROWSER; +import static com.frameworkium.core.common.properties.Property.BROWSER_VERSION; +import static com.frameworkium.core.common.properties.Property.DEVICE; +import static com.frameworkium.core.common.properties.Property.PLATFORM; +import static com.frameworkium.core.common.properties.Property.PLATFORM_VERSION; + import com.fasterxml.jackson.annotation.JsonInclude; import com.frameworkium.core.ui.UITestLifecycle; import com.frameworkium.core.ui.driver.DriverSetup; +import java.util.Optional; import net.sf.uadetector.ReadableUserAgent; import net.sf.uadetector.UserAgentStringParser; import net.sf.uadetector.service.UADetectorServiceFactory; -import java.util.Optional; - -import static com.frameworkium.core.common.properties.Property.*; - @JsonInclude(JsonInclude.Include.NON_NULL) public class Browser { - public String name; - public String version; - public String device; - public String platform; - public String platformVersion; - - /** - * Create browser object. - */ - public Browser() { - - Optional userAgent = UITestLifecycle.get().getUserAgent(); - if (userAgent.isPresent() && !userAgent.get().isEmpty()) { - UserAgentStringParser uaParser = UADetectorServiceFactory.getResourceModuleParser(); - ReadableUserAgent agent = uaParser.parse(userAgent.get()); - - this.name = agent.getName(); - this.version = agent.getVersionNumber().toVersionString(); - this.device = agent.getDeviceCategory().getName(); - this.platform = agent.getOperatingSystem().getName(); - this.platformVersion = agent.getOperatingSystem().getVersionNumber().toVersionString(); - - } else { - // Fall-back to the Property class - if (BROWSER.isSpecified()) { - this.name = BROWSER.getValue().toLowerCase(); - } else { - this.name = DriverSetup.DEFAULT_BROWSER.toString(); - } - if (BROWSER_VERSION.isSpecified()) { - this.version = BROWSER_VERSION.getValue(); - } - if (DEVICE.isSpecified()) { - this.device = DEVICE.getValue(); - } - if (PLATFORM.isSpecified()) { - this.platform = PLATFORM.getValue(); - } - if (PLATFORM_VERSION.isSpecified()) { - this.platformVersion = PLATFORM_VERSION.getValue(); - } - } + public String name; + public String version; + public String device; + public String platform; + public String platformVersion; + + /** + * Create browser object. + */ + public Browser() { + + Optional userAgent = UITestLifecycle.get().getUserAgent(); + if (userAgent.isPresent() && !userAgent.get().isEmpty()) { + UserAgentStringParser uaParser = UADetectorServiceFactory.getResourceModuleParser(); + ReadableUserAgent agent = uaParser.parse(userAgent.get()); + + this.name = agent.getName(); + this.version = agent.getVersionNumber().toVersionString(); + this.device = agent.getDeviceCategory().getName(); + this.platform = agent.getOperatingSystem().getName(); + this.platformVersion = agent.getOperatingSystem().getVersionNumber().toVersionString(); + + } else { + // Fall-back to the Property class + if (BROWSER.isSpecified()) { + this.name = BROWSER.getValue().toLowerCase(); + } else { + this.name = DriverSetup.DEFAULT_BROWSER.toString(); + } + if (BROWSER_VERSION.isSpecified()) { + this.version = BROWSER_VERSION.getValue(); + } + if (DEVICE.isSpecified()) { + this.device = DEVICE.getValue(); + } + if (PLATFORM.isSpecified()) { + this.platform = PLATFORM.getValue(); + } + if (PLATFORM_VERSION.isSpecified()) { + this.platformVersion = PLATFORM_VERSION.getValue(); + } } + } } diff --git a/src/main/java/com/frameworkium/core/ui/capture/model/Command.java b/src/main/java/com/frameworkium/core/ui/capture/model/Command.java index ec283de8..8e270f99 100644 --- a/src/main/java/com/frameworkium/core/ui/capture/model/Command.java +++ b/src/main/java/com/frameworkium/core/ui/capture/model/Command.java @@ -8,42 +8,42 @@ @JsonInclude(JsonInclude.Include.NON_NULL) public class Command { - public String action; - public String using; - public String value; + public String action; + public String using; + public String value; - public Command(String action, String using, String value) { - this.action = action; - this.using = using; - this.value = value; - } + public Command(String action, String using, String value) { + this.action = action; + this.using = using; + this.value = value; + } - public Command(String action, WebElement element) { - this.action = action; - setUsingAndValue(element); - } + public Command(String action, WebElement element) { + this.action = action; + setUsingAndValue(element); + } - private void setUsingAndValue(WebElement element) { - // TODO: Improve this. Use hacky solution in LoggingListener? - if (Driver.isNative()) { - this.using = "n/a"; - this.value = "n/a"; - } else { - if (StringUtils.isNotBlank(element.getAttribute("id"))) { - this.using = "id"; - this.value = element.getAttribute("id"); - } else if (!(element.getText()).isEmpty()) { - this.using = "linkText"; - this.value = element.getText(); - } else if (!element.getTagName().isEmpty()) { - this.using = "css"; - this.value = element.getTagName() + "." - + element.getAttribute("class").replace(" ", "."); - } else { - // must be something weird - this.using = "n/a"; - this.value = "n/a"; - } - } + private void setUsingAndValue(WebElement element) { + // TODO: Improve this. Use hacky solution in LoggingListener? + if (Driver.isNative()) { + this.using = "n/a"; + this.value = "n/a"; + } else { + if (StringUtils.isNotBlank(element.getAttribute("id"))) { + this.using = "id"; + this.value = element.getAttribute("id"); + } else if (!(element.getText()).isEmpty()) { + this.using = "linkText"; + this.value = element.getText(); + } else if (!element.getTagName().isEmpty()) { + this.using = "css"; + this.value = element.getTagName() + "." + + element.getAttribute("class").replace(" ", "."); + } else { + // must be something weird + this.using = "n/a"; + this.value = "n/a"; + } } + } } diff --git a/src/main/java/com/frameworkium/core/ui/capture/model/SoftwareUnderTest.java b/src/main/java/com/frameworkium/core/ui/capture/model/SoftwareUnderTest.java index 5e0b75da..2a5bf107 100644 --- a/src/main/java/com/frameworkium/core/ui/capture/model/SoftwareUnderTest.java +++ b/src/main/java/com/frameworkium/core/ui/capture/model/SoftwareUnderTest.java @@ -5,18 +5,18 @@ public class SoftwareUnderTest { - public String name; - public String version; + public String name; + public String version; - /** - * Software under test object. - */ - public SoftwareUnderTest() { - if (SUT_NAME.isSpecified()) { - this.name = SUT_NAME.getValue(); - } - if (SUT_VERSION.isSpecified()) { - this.version = SUT_VERSION.getValue(); - } + /** + * Software under test object. + */ + public SoftwareUnderTest() { + if (SUT_NAME.isSpecified()) { + this.name = SUT_NAME.getValue(); } + if (SUT_VERSION.isSpecified()) { + this.version = SUT_VERSION.getValue(); + } + } } diff --git a/src/main/java/com/frameworkium/core/ui/capture/model/message/CreateExecution.java b/src/main/java/com/frameworkium/core/ui/capture/model/message/CreateExecution.java index bcae4be7..827195e0 100644 --- a/src/main/java/com/frameworkium/core/ui/capture/model/message/CreateExecution.java +++ b/src/main/java/com/frameworkium/core/ui/capture/model/message/CreateExecution.java @@ -9,22 +9,21 @@ @JsonInclude(JsonInclude.Include.NON_NULL) public final class CreateExecution { - public String testID; - public Browser browser; - public SoftwareUnderTest softwareUnderTest; - public String nodeAddress; + private static final Logger logger = LogManager.getLogger(); + public String testID; + public Browser browser; + public SoftwareUnderTest softwareUnderTest; + public String nodeAddress; - private static final Logger logger = LogManager.getLogger(); + /** + * Create Capture execution. + */ + public CreateExecution(String testID, String nodeAddress) { - /** - * Create Capture execution. - */ - public CreateExecution(String testID, String nodeAddress) { - - logger.debug("CreateExecution: testID='{}', nodeAddress='{}", testID, nodeAddress); - this.testID = testID; - this.browser = new Browser(); - this.softwareUnderTest = new SoftwareUnderTest(); - this.nodeAddress = nodeAddress; - } + logger.debug("CreateExecution: testID='{}', nodeAddress='{}", testID, nodeAddress); + this.testID = testID; + this.browser = new Browser(); + this.softwareUnderTest = new SoftwareUnderTest(); + this.nodeAddress = nodeAddress; + } } diff --git a/src/main/java/com/frameworkium/core/ui/capture/model/message/CreateScreenshot.java b/src/main/java/com/frameworkium/core/ui/capture/model/message/CreateScreenshot.java index 7a293cd8..06f43b35 100644 --- a/src/main/java/com/frameworkium/core/ui/capture/model/message/CreateScreenshot.java +++ b/src/main/java/com/frameworkium/core/ui/capture/model/message/CreateScreenshot.java @@ -8,30 +8,30 @@ @JsonInclude(JsonInclude.Include.NON_NULL) public class CreateScreenshot { - private static final Logger logger = LogManager.getLogger(); - public Command command; - public String url; - public String executionID; - public String errorMessage; - public String screenshotBase64; + private static final Logger logger = LogManager.getLogger(); + public Command command; + public String url; + public String executionID; + public String errorMessage; + public String screenshotBase64; - /** - * Create screenshot object. - */ - public CreateScreenshot( - String executionID, Command command, String url, - String errorMessage, String screenshotBase64) { + /** + * Create screenshot object. + */ + public CreateScreenshot( + String executionID, Command command, String url, + String errorMessage, String screenshotBase64) { - logger.debug("Creating screenshot: executionID='{}', " - + "Command.action='{}', url='{}', " - + "errorMessage='{}', screenshotBase64.length={}", - executionID, - command.action, url, - errorMessage, screenshotBase64.length()); - this.executionID = executionID; - this.command = command; - this.url = url; - this.errorMessage = errorMessage; - this.screenshotBase64 = screenshotBase64; - } + logger.debug("Creating screenshot: executionID='{}', " + + "Command.action='{}', url='{}', " + + "errorMessage='{}', screenshotBase64.length={}", + executionID, + command.action, url, + errorMessage, screenshotBase64.length()); + this.executionID = executionID; + this.command = command; + this.url = url; + this.errorMessage = errorMessage; + this.screenshotBase64 = screenshotBase64; + } } diff --git a/src/main/java/com/frameworkium/core/ui/driver/AbstractDriver.java b/src/main/java/com/frameworkium/core/ui/driver/AbstractDriver.java index a68f1e29..d7ab65cf 100755 --- a/src/main/java/com/frameworkium/core/ui/driver/AbstractDriver.java +++ b/src/main/java/com/frameworkium/core/ui/driver/AbstractDriver.java @@ -1,5 +1,7 @@ package com.frameworkium.core.ui.driver; +import static java.util.concurrent.TimeUnit.SECONDS; + import com.frameworkium.core.common.properties.Property; import com.frameworkium.core.ui.capture.ScreenshotCapture; import com.frameworkium.core.ui.driver.remotes.BrowserStack; @@ -14,67 +16,65 @@ import org.openqa.selenium.remote.CapabilityType; import org.openqa.selenium.support.events.EventFiringWebDriver; -import static java.util.concurrent.TimeUnit.SECONDS; - public abstract class AbstractDriver implements Driver { - protected static final Logger logger = LogManager.getLogger(); + protected static final Logger logger = LogManager.getLogger(); - private EventFiringWebDriver webDriverWrapper; + private EventFiringWebDriver webDriverWrapper; - @Override - public EventFiringWebDriver getWebDriver() { - return this.webDriverWrapper; + private static Capabilities addProxyIfRequired(Capabilities caps) { + if (Property.PROXY.isSpecified()) { + return caps.merge(createProxyCapabilities(Property.PROXY.getValue())); + } else { + return caps; } + } - /** - * Creates the Wrapped Driver object and maximises if required. - */ - public void initialise() { - this.webDriverWrapper = setupEventFiringWebDriver(getCapabilities()); - maximiseBrowserIfRequired(); - } + private static Capabilities createProxyCapabilities(String proxyProperty) { + return new ImmutableCapabilities( + CapabilityType.PROXY, + SeleniumProxyFactory.createProxy(proxyProperty)); + } - private EventFiringWebDriver setupEventFiringWebDriver(Capabilities capabilities) { - Capabilities caps = addProxyIfRequired(capabilities); - logger.debug("Browser Capabilities: " + caps); - EventFiringWebDriver eventFiringWD = new EventFiringWebDriver(getWebDriver(caps)); - eventFiringWD.register(new LoggingListener()); - if (ScreenshotCapture.isRequired()) { - eventFiringWD.register(new CaptureListener()); - } - if (!Driver.isNative()) { - eventFiringWD.manage().timeouts().setScriptTimeout(10, SECONDS); - } - return eventFiringWD; - } + private static boolean isMaximiseRequired() { + boolean ableToMaximise = !Sauce.isDesired() + && !BrowserStack.isDesired() + && !Driver.isNative(); - private static Capabilities addProxyIfRequired(Capabilities caps) { - if (Property.PROXY.isSpecified()) { - return caps.merge(createProxyCapabilities(Property.PROXY.getValue())); - } else { - return caps; - } - } + return ableToMaximise && Property.MAXIMISE.getBoolean(); + } - private static Capabilities createProxyCapabilities(String proxyProperty) { - return new ImmutableCapabilities( - CapabilityType.PROXY, - SeleniumProxyFactory.createProxy(proxyProperty)); - } + @Override + public EventFiringWebDriver getWebDriver() { + return this.webDriverWrapper; + } - private void maximiseBrowserIfRequired() { - if (isMaximiseRequired()) { - this.webDriverWrapper.manage().window().maximize(); - } - } + /** + * Creates the Wrapped Driver object and maximises if required. + */ + public void initialise() { + this.webDriverWrapper = setupEventFiringWebDriver(getCapabilities()); + maximiseBrowserIfRequired(); + } - private static boolean isMaximiseRequired() { - boolean ableToMaximise = !Sauce.isDesired() - && !BrowserStack.isDesired() - && !Driver.isNative(); + private EventFiringWebDriver setupEventFiringWebDriver(Capabilities capabilities) { + Capabilities caps = addProxyIfRequired(capabilities); + logger.debug("Browser Capabilities: " + caps); + EventFiringWebDriver eventFiringWD = new EventFiringWebDriver(getWebDriver(caps)); + eventFiringWD.register(new LoggingListener()); + if (ScreenshotCapture.isRequired()) { + eventFiringWD.register(new CaptureListener()); + } + if (!Driver.isNative()) { + eventFiringWD.manage().timeouts().setScriptTimeout(10, SECONDS); + } + return eventFiringWD; + } - return ableToMaximise && Property.MAXIMISE.getBoolean(); + private void maximiseBrowserIfRequired() { + if (isMaximiseRequired()) { + this.webDriverWrapper.manage().window().maximize(); } + } } diff --git a/src/main/java/com/frameworkium/core/ui/driver/Driver.java b/src/main/java/com/frameworkium/core/ui/driver/Driver.java index 11c9ba8d..3e9a061a 100755 --- a/src/main/java/com/frameworkium/core/ui/driver/Driver.java +++ b/src/main/java/com/frameworkium/core/ui/driver/Driver.java @@ -1,45 +1,51 @@ package com.frameworkium.core.ui.driver; +import static com.frameworkium.core.common.properties.Property.APP_PATH; + import org.openqa.selenium.Capabilities; import org.openqa.selenium.WebDriver; import org.openqa.selenium.support.events.EventFiringWebDriver; -import static com.frameworkium.core.common.properties.Property.APP_PATH; - public interface Driver { - /** Check whether the driver is for a mobile device. */ - static boolean isMobile() { - return false; - } - - /** Check whether the driver is for a native mobile app. */ - static boolean isNative() { - return APP_PATH.isSpecified(); - } - - /** Method to set-up the driver object. */ - void initialise(); - - /** - * Implemented in each Driver Type to specify the capabilities of that browser. - * - * @return Capabilities of each browser - */ - Capabilities getCapabilities(); - - /** - * Returns the correct WebDriver object for the Driver Type. - * - * @param capabilities Capabilities of the browser - * @return {@link WebDriver} object for the browser - */ - WebDriver getWebDriver(Capabilities capabilities); - - /** - * Getter for the driver that wraps the initialised driver. - * - * @return EventFiringWebDriver - */ - EventFiringWebDriver getWebDriver(); + /** + * Check whether the driver is for a mobile device. + */ + static boolean isMobile() { + return false; + } + + /** + * Check whether the driver is for a native mobile app. + */ + static boolean isNative() { + return APP_PATH.isSpecified(); + } + + /** + * Method to set-up the driver object. + */ + void initialise(); + + /** + * Implemented in each Driver Type to specify the capabilities of that browser. + * + * @return Capabilities of each browser + */ + Capabilities getCapabilities(); + + /** + * Returns the correct WebDriver object for the Driver Type. + * + * @param capabilities Capabilities of the browser + * @return {@link WebDriver} object for the browser + */ + WebDriver getWebDriver(Capabilities capabilities); + + /** + * Getter for the driver that wraps the initialised driver. + * + * @return EventFiringWebDriver + */ + EventFiringWebDriver getWebDriver(); } diff --git a/src/main/java/com/frameworkium/core/ui/driver/DriverSetup.java b/src/main/java/com/frameworkium/core/ui/driver/DriverSetup.java index e1fc2c28..67e1a889 100755 --- a/src/main/java/com/frameworkium/core/ui/driver/DriverSetup.java +++ b/src/main/java/com/frameworkium/core/ui/driver/DriverSetup.java @@ -1,157 +1,170 @@ package com.frameworkium.core.ui.driver; import com.frameworkium.core.common.properties.Property; -import com.frameworkium.core.ui.driver.drivers.*; +import com.frameworkium.core.ui.driver.drivers.BrowserStackImpl; +import com.frameworkium.core.ui.driver.drivers.ChromeImpl; +import com.frameworkium.core.ui.driver.drivers.EdgeImpl; +import com.frameworkium.core.ui.driver.drivers.ElectronImpl; +import com.frameworkium.core.ui.driver.drivers.FirefoxImpl; +import com.frameworkium.core.ui.driver.drivers.GridImpl; +import com.frameworkium.core.ui.driver.drivers.InternetExplorerImpl; +import com.frameworkium.core.ui.driver.drivers.LegacyFirefoxImpl; +import com.frameworkium.core.ui.driver.drivers.SafariImpl; +import com.frameworkium.core.ui.driver.drivers.SauceImpl; import com.frameworkium.core.ui.driver.remotes.BrowserStack; import com.frameworkium.core.ui.driver.remotes.Sauce; +import java.lang.reflect.InvocationTargetException; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.openqa.selenium.Capabilities; -import java.lang.reflect.InvocationTargetException; - public class DriverSetup { - public static final Browser DEFAULT_BROWSER = Browser.FIREFOX; - - /** Supported drivers. */ - public enum Browser { - FIREFOX, LEGACYFIREFOX, CHROME, EDGE, IE, SAFARI, ELECTRON, CUSTOM - } - - /** Supported remote grids. */ - private enum RemoteGrid { - SAUCE, BROWSERSTACK, GRID - } + public static final Browser DEFAULT_BROWSER = Browser.FIREFOX; + protected static final Logger logger = LogManager.getLogger(); - /** Supported platforms for remote grids. */ - public enum Platform { - WINDOWS, OSX, IOS, ANDROID, NONE + /** + * @return An uninitialised desired {@link Driver} implementation. + */ + public static Driver instantiateDriver() { + Driver driver = createDriverImpl(getBrowserTypeFromProperty()); + if (useRemoteDriver()) { + driver = instantiateDesiredRemote(driver); } - - protected static final Logger logger = LogManager.getLogger(); - - /** - * @return An uninitialised desired {@link Driver} implementation. - */ - public static Driver instantiateDriver() { - Driver driver = createDriverImpl(getBrowserTypeFromProperty()); - if (useRemoteDriver()) { - driver = instantiateDesiredRemote(driver); - } - driver.initialise(); + driver.initialise(); + return driver; + } + + /** + * Uses parameters to determine which browser/remote/platform to use. + * + * @param driver the desired (non-remote) driver implementation + * @return The (potentially) remote driver implementation based on parameters + */ + private static Driver instantiateDesiredRemote(Driver driver) { + + Capabilities capabilities = driver.getCapabilities(); + Platform platform = getPlatformType(); + switch (getRemoteType()) { + case SAUCE: + return new SauceImpl(platform, capabilities); + case BROWSERSTACK: + return new BrowserStackImpl(platform, capabilities); + case GRID: + return new GridImpl(capabilities); + default: return driver; } - - /** - * Uses parameters to determine which browser/remote/platform to use. - * - * @param driver the desired (non-remote) driver implementation - * @return The (potentially) remote driver implementation based on parameters - */ - private static Driver instantiateDesiredRemote(Driver driver) { - - Capabilities capabilities = driver.getCapabilities(); - Platform platform = getPlatformType(); - switch (getRemoteType()) { - case SAUCE: - return new SauceImpl(platform, capabilities); - case BROWSERSTACK: - return new BrowserStackImpl(platform, capabilities); - case GRID: - return new GridImpl(capabilities); - default: - return driver; - } - } - - private static Driver createDriverImpl(Browser browser) { - switch (browser) { - case FIREFOX: - return new FirefoxImpl(); - case LEGACYFIREFOX: - return new LegacyFirefoxImpl(); - case CHROME: - return new ChromeImpl(); - case EDGE: - return new EdgeImpl(); - case IE: - return new InternetExplorerImpl(); - case SAFARI: - return new SafariImpl(); - case ELECTRON: - return new ElectronImpl(); - case CUSTOM: - String customBrowserImpl = Property.CUSTOM_BROWSER_IMPL.getValue(); - try { - return getCustomBrowserImpl(customBrowserImpl) - .getDeclaredConstructor() - .newInstance(); - } catch (InstantiationException | IllegalAccessException - | NoSuchMethodException | InvocationTargetException e) { - throw new IllegalArgumentException( - "Unable to use custom browser implementation - " + customBrowserImpl, e); - } - default: - throw new IllegalArgumentException("Invalid Browser specified"); + } + + private static Driver createDriverImpl(Browser browser) { + switch (browser) { + case FIREFOX: + return new FirefoxImpl(); + case LEGACYFIREFOX: + return new LegacyFirefoxImpl(); + case CHROME: + return new ChromeImpl(); + case EDGE: + return new EdgeImpl(); + case IE: + return new InternetExplorerImpl(); + case SAFARI: + return new SafariImpl(); + case ELECTRON: + return new ElectronImpl(); + case CUSTOM: + String customBrowserImpl = Property.CUSTOM_BROWSER_IMPL.getValue(); + try { + return getCustomBrowserImpl(customBrowserImpl) + .getDeclaredConstructor() + .newInstance(); + } catch (InstantiationException | IllegalAccessException + | NoSuchMethodException | InvocationTargetException e) { + throw new IllegalArgumentException( + "Unable to use custom browser implementation - " + customBrowserImpl, e); } + default: + throw new IllegalArgumentException("Invalid Browser specified"); } - - public static boolean useRemoteDriver() { - return Property.GRID_URL.isSpecified() - || Sauce.isDesired() - || BrowserStack.isDesired(); + } + + public static boolean useRemoteDriver() { + return Property.GRID_URL.isSpecified() + || Sauce.isDesired() + || BrowserStack.isDesired(); + } + + private static Platform getPlatformType() { + if (Property.PLATFORM.isSpecified()) { + return Platform.valueOf(Property.PLATFORM.getValue().toUpperCase()); + } else { + return Platform.NONE; } - - private static Platform getPlatformType() { - if (Property.PLATFORM.isSpecified()) { - return Platform.valueOf(Property.PLATFORM.getValue().toUpperCase()); - } else { - return Platform.NONE; - } + } + + private static Browser getBrowserTypeFromProperty() { + if (Property.CUSTOM_BROWSER_IMPL.isSpecified()) { + return Browser.CUSTOM; + } else if (Property.BROWSER.isSpecified()) { + return Browser.valueOf(Property.BROWSER.getValue().toUpperCase()); + } else { + return DEFAULT_BROWSER; } - - private static Browser getBrowserTypeFromProperty() { - if (Property.CUSTOM_BROWSER_IMPL.isSpecified()) { - return Browser.CUSTOM; - } else if (Property.BROWSER.isSpecified()) { - return Browser.valueOf(Property.BROWSER.getValue().toUpperCase()); - } else { - return DEFAULT_BROWSER; - } + } + + private static RemoteGrid getRemoteType() { + if (Sauce.isDesired()) { + return RemoteGrid.SAUCE; + } else if (BrowserStack.isDesired()) { + return RemoteGrid.BROWSERSTACK; + } else { + return RemoteGrid.GRID; } - - private static RemoteGrid getRemoteType() { - if (Sauce.isDesired()) { - return RemoteGrid.SAUCE; - } else if (BrowserStack.isDesired()) { - return RemoteGrid.BROWSERSTACK; - } else { - return RemoteGrid.GRID; - } - } - - /** - * Returns custom Driver implementation based on (full) class name. - * - * @param implClassName fully qualified name of custom browser impl class - * @return Class implementing the Driver interface - */ - private static Class getCustomBrowserImpl(String implClassName) { - try { - return Class.forName(implClassName).asSubclass(Driver.class); - } catch (ClassNotFoundException ex) { - String message = "Failed to find custom browser implementation class: " + implClassName; - logger.fatal(message, ex); - throw new IllegalArgumentException(message - + "\nFully qualified class name is required. " - + "e.g. com.frameworkium.ui.MyCustomImpl"); - } catch (ClassCastException ex) { - String message = String.format( - "Custom browser implementation class '%s' does not implement the Driver interface.", - implClassName); - logger.fatal(message, ex); - throw new IllegalArgumentException(message, ex); - } + } + + /** + * Returns custom Driver implementation based on (full) class name. + * + * @param implClassName fully qualified name of custom browser impl class + * @return Class implementing the Driver interface + */ + private static Class getCustomBrowserImpl(String implClassName) { + try { + return Class.forName(implClassName).asSubclass(Driver.class); + } catch (ClassNotFoundException ex) { + String message = "Failed to find custom browser implementation class: " + implClassName; + logger.fatal(message, ex); + throw new IllegalArgumentException(message + + "\nFully qualified class name is required. " + + "e.g. com.frameworkium.ui.MyCustomImpl"); + } catch (ClassCastException ex) { + String message = String.format( + "Custom browser implementation class '%s' does not implement the Driver interface.", + implClassName); + logger.fatal(message, ex); + throw new IllegalArgumentException(message, ex); } + } + + /** + * Supported drivers. + */ + public enum Browser { + FIREFOX, LEGACYFIREFOX, CHROME, EDGE, IE, SAFARI, ELECTRON, CUSTOM + } + + /** + * Supported remote grids. + */ + private enum RemoteGrid { + SAUCE, BROWSERSTACK, GRID + } + + /** + * Supported platforms for remote grids. + */ + public enum Platform { + WINDOWS, OSX, IOS, ANDROID, NONE + } } diff --git a/src/main/java/com/frameworkium/core/ui/driver/drivers/BrowserStackImpl.java b/src/main/java/com/frameworkium/core/ui/driver/drivers/BrowserStackImpl.java index 90565793..a2bd9084 100644 --- a/src/main/java/com/frameworkium/core/ui/driver/drivers/BrowserStackImpl.java +++ b/src/main/java/com/frameworkium/core/ui/driver/drivers/BrowserStackImpl.java @@ -1,96 +1,97 @@ package com.frameworkium.core.ui.driver.drivers; +import static com.frameworkium.core.ui.driver.DriverSetup.Platform; + import com.frameworkium.core.common.properties.Property; import com.frameworkium.core.ui.driver.AbstractDriver; import com.frameworkium.core.ui.driver.remotes.BrowserStack; -import org.openqa.selenium.*; -import org.openqa.selenium.remote.RemoteWebDriver; - import java.net.MalformedURLException; import java.net.URL; - -import static com.frameworkium.core.ui.driver.DriverSetup.Platform; +import org.openqa.selenium.Capabilities; +import org.openqa.selenium.MutableCapabilities; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.remote.RemoteWebDriver; public class BrowserStackImpl extends AbstractDriver { - private URL remoteURL; - private Platform platform; - private Capabilities capabilities; - - /** - * Implementation of driver for BrowserStack. - */ - public BrowserStackImpl(Platform platform, Capabilities browserCapabilities) { + private URL remoteURL; + private Platform platform; + private Capabilities capabilities; - this.platform = platform; - capabilities = browserCapabilities; - try { - remoteURL = BrowserStack.getURL(); - } catch (MalformedURLException e) { - throw new IllegalArgumentException(e); - } - } + /** + * Implementation of driver for BrowserStack. + */ + public BrowserStackImpl(Platform platform, Capabilities browserCapabilities) { - @Override - public Capabilities getCapabilities() { - MutableCapabilities capabilities = getCapabilitiesBasedOnPlatform(); - capabilities.setCapability("browserstack.debug", true); - return capabilities; + this.platform = platform; + capabilities = browserCapabilities; + try { + remoteURL = BrowserStack.getURL(); + } catch (MalformedURLException e) { + throw new IllegalArgumentException(e); } + } - private MutableCapabilities getCapabilitiesBasedOnPlatform() { - MutableCapabilities mutableCapabilities = new MutableCapabilities(capabilities); - switch (platform) { - case WINDOWS: - mutableCapabilities.setCapability("os", "Windows"); - mutableCapabilities.merge(getDesktopCapability()); - break; - case OSX: - mutableCapabilities.setCapability("os", "OS X"); - mutableCapabilities.merge(getDesktopCapability()); - break; - case ANDROID: - mutableCapabilities.setCapability("platform", "ANDROID"); - mutableCapabilities.setCapability("browserName", "android"); - if (Property.DEVICE.isSpecified()) { - mutableCapabilities.setCapability( - "device", Property.DEVICE.getValue()); - } - break; - case IOS: - mutableCapabilities.setCapability("platform", "MAC"); - if (Property.DEVICE.isSpecified()) { - mutableCapabilities.setCapability( - "device", Property.DEVICE.getValue()); - mutableCapabilities.setCapability( - "browserName", Property.DEVICE.getValue().split(" ")[0]); - } - break; - default: - break; - } - return mutableCapabilities; - } + @Override + public Capabilities getCapabilities() { + MutableCapabilities capabilities = getCapabilitiesBasedOnPlatform(); + capabilities.setCapability("browserstack.debug", true); + return capabilities; + } - private MutableCapabilities getDesktopCapability() { - MutableCapabilities mutableCapabilities = new MutableCapabilities(capabilities); - if (Property.PLATFORM_VERSION.isSpecified()) { - mutableCapabilities.setCapability( - "os_version", Property.PLATFORM_VERSION.getValue()); + private MutableCapabilities getCapabilitiesBasedOnPlatform() { + MutableCapabilities mutableCapabilities = new MutableCapabilities(capabilities); + switch (platform) { + case WINDOWS: + mutableCapabilities.setCapability("os", "Windows"); + mutableCapabilities.merge(getDesktopCapability()); + break; + case OSX: + mutableCapabilities.setCapability("os", "OS X"); + mutableCapabilities.merge(getDesktopCapability()); + break; + case ANDROID: + mutableCapabilities.setCapability("platform", "ANDROID"); + mutableCapabilities.setCapability("browserName", "android"); + if (Property.DEVICE.isSpecified()) { + mutableCapabilities.setCapability( + "device", Property.DEVICE.getValue()); } - if (Property.RESOLUTION.isSpecified()) { - mutableCapabilities.setCapability( - "resolution", Property.RESOLUTION.getValue()); + break; + case IOS: + mutableCapabilities.setCapability("platform", "MAC"); + if (Property.DEVICE.isSpecified()) { + mutableCapabilities.setCapability( + "device", Property.DEVICE.getValue()); + mutableCapabilities.setCapability( + "browserName", Property.DEVICE.getValue().split(" ")[0]); } - if (Property.BROWSER_VERSION.isSpecified()) { - mutableCapabilities.setCapability( - "browser_version", Property.BROWSER_VERSION.getValue()); - } - return mutableCapabilities; + break; + default: + break; } + return mutableCapabilities; + } - @Override - public WebDriver getWebDriver(Capabilities capabilities) { - return new RemoteWebDriver(remoteURL, capabilities); + private MutableCapabilities getDesktopCapability() { + MutableCapabilities mutableCapabilities = new MutableCapabilities(capabilities); + if (Property.PLATFORM_VERSION.isSpecified()) { + mutableCapabilities.setCapability( + "os_version", Property.PLATFORM_VERSION.getValue()); + } + if (Property.RESOLUTION.isSpecified()) { + mutableCapabilities.setCapability( + "resolution", Property.RESOLUTION.getValue()); } + if (Property.BROWSER_VERSION.isSpecified()) { + mutableCapabilities.setCapability( + "browser_version", Property.BROWSER_VERSION.getValue()); + } + return mutableCapabilities; + } + + @Override + public WebDriver getWebDriver(Capabilities capabilities) { + return new RemoteWebDriver(remoteURL, capabilities); + } } diff --git a/src/main/java/com/frameworkium/core/ui/driver/drivers/ChromeImpl.java b/src/main/java/com/frameworkium/core/ui/driver/drivers/ChromeImpl.java index bad28008..4ce31feb 100644 --- a/src/main/java/com/frameworkium/core/ui/driver/drivers/ChromeImpl.java +++ b/src/main/java/com/frameworkium/core/ui/driver/drivers/ChromeImpl.java @@ -3,52 +3,51 @@ import com.frameworkium.core.common.properties.Property; import com.frameworkium.core.ui.driver.AbstractDriver; import com.google.common.collect.ImmutableMap; +import java.util.Collections; import org.openqa.selenium.Capabilities; import org.openqa.selenium.WebDriver; import org.openqa.selenium.chrome.ChromeDriver; import org.openqa.selenium.chrome.ChromeOptions; -import java.util.Collections; - public class ChromeImpl extends AbstractDriver { - @Override - public ChromeOptions getCapabilities() { - ChromeOptions chromeOptions = new ChromeOptions(); - - // useful defaults - chromeOptions.setCapability( - "chrome.switches", - Collections.singletonList("--no-default-browser-check")); - chromeOptions.setCapability( - "chrome.prefs", - ImmutableMap.of("profile.password_manager_enabled", "false")); - - // Workaround Docker/Travis issue - if (Boolean.parseBoolean(System.getenv("CHROME_NO_SANDBOX"))) { - chromeOptions.addArguments("--no-sandbox"); - } - - // Use Chrome's built in device emulators - if (Property.DEVICE.isSpecified()) { - chromeOptions.setExperimentalOption( - "mobileEmulation", - ImmutableMap.of("deviceName", Property.DEVICE.getValue())); - } - - chromeOptions.setHeadless(Property.HEADLESS.getBoolean()); - return chromeOptions; + @Override + public ChromeOptions getCapabilities() { + ChromeOptions chromeOptions = new ChromeOptions(); + + // useful defaults + chromeOptions.setCapability( + "chrome.switches", + Collections.singletonList("--no-default-browser-check")); + chromeOptions.setCapability( + "chrome.prefs", + ImmutableMap.of("profile.password_manager_enabled", "false")); + + // Workaround Docker/Travis issue + if (Boolean.parseBoolean(System.getenv("CHROME_NO_SANDBOX"))) { + chromeOptions.addArguments("--no-sandbox"); + } + + // Use Chrome's built in device emulators + if (Property.DEVICE.isSpecified()) { + chromeOptions.setExperimentalOption( + "mobileEmulation", + ImmutableMap.of("deviceName", Property.DEVICE.getValue())); } - @Override - public WebDriver getWebDriver(Capabilities capabilities) { - final ChromeOptions chromeOptions; - if (capabilities instanceof ChromeOptions) { - chromeOptions = (ChromeOptions) capabilities; - } else { - chromeOptions = new ChromeOptions().merge(capabilities); - } - return new ChromeDriver(chromeOptions); + chromeOptions.setHeadless(Property.HEADLESS.getBoolean()); + return chromeOptions; + } + + @Override + public WebDriver getWebDriver(Capabilities capabilities) { + final ChromeOptions chromeOptions; + if (capabilities instanceof ChromeOptions) { + chromeOptions = (ChromeOptions) capabilities; + } else { + chromeOptions = new ChromeOptions().merge(capabilities); } + return new ChromeDriver(chromeOptions); + } } diff --git a/src/main/java/com/frameworkium/core/ui/driver/drivers/EdgeImpl.java b/src/main/java/com/frameworkium/core/ui/driver/drivers/EdgeImpl.java index c833850f..02ac8660 100644 --- a/src/main/java/com/frameworkium/core/ui/driver/drivers/EdgeImpl.java +++ b/src/main/java/com/frameworkium/core/ui/driver/drivers/EdgeImpl.java @@ -8,19 +8,19 @@ public class EdgeImpl extends AbstractDriver { - @Override - public EdgeOptions getCapabilities() { - return new EdgeOptions(); - } + @Override + public EdgeOptions getCapabilities() { + return new EdgeOptions(); + } - @Override - public WebDriver getWebDriver(Capabilities capabilities) { - final EdgeOptions edgeOptions; - if (capabilities instanceof EdgeOptions) { - edgeOptions = (EdgeOptions) capabilities; - } else { - edgeOptions = new EdgeOptions().merge(capabilities); - } - return new EdgeDriver(edgeOptions); + @Override + public WebDriver getWebDriver(Capabilities capabilities) { + final EdgeOptions edgeOptions; + if (capabilities instanceof EdgeOptions) { + edgeOptions = (EdgeOptions) capabilities; + } else { + edgeOptions = new EdgeOptions().merge(capabilities); } + return new EdgeDriver(edgeOptions); + } } diff --git a/src/main/java/com/frameworkium/core/ui/driver/drivers/ElectronImpl.java b/src/main/java/com/frameworkium/core/ui/driver/drivers/ElectronImpl.java index 4d4beb9b..74c4ba58 100644 --- a/src/main/java/com/frameworkium/core/ui/driver/drivers/ElectronImpl.java +++ b/src/main/java/com/frameworkium/core/ui/driver/drivers/ElectronImpl.java @@ -1,42 +1,41 @@ package com.frameworkium.core.ui.driver.drivers; +import static com.frameworkium.core.common.properties.Property.APP_PATH; + import com.frameworkium.core.ui.driver.AbstractDriver; +import java.net.MalformedURLException; +import java.net.URL; import org.openqa.selenium.Capabilities; import org.openqa.selenium.WebDriver; import org.openqa.selenium.chrome.ChromeOptions; import org.openqa.selenium.remote.RemoteWebDriver; -import java.net.MalformedURLException; -import java.net.URL; - -import static com.frameworkium.core.common.properties.Property.APP_PATH; - public class ElectronImpl extends AbstractDriver { - private static URL remoteURL; + private static URL remoteURL; - static { - try { - remoteURL = new URL("http://localhost:9515"); - } catch (MalformedURLException e) { - throw new RuntimeException(e); - } + static { + try { + remoteURL = new URL("http://localhost:9515"); + } catch (MalformedURLException e) { + throw new RuntimeException(e); } + } - @Override - public ChromeOptions getCapabilities() { - if (!APP_PATH.isSpecified()) { - throw new IllegalStateException( - "App path must be specified when using Electron!"); - } - - ChromeOptions chromeOptions = new ChromeOptions(); - chromeOptions.setBinary(APP_PATH.getValue()); - return chromeOptions; + @Override + public ChromeOptions getCapabilities() { + if (!APP_PATH.isSpecified()) { + throw new IllegalStateException( + "App path must be specified when using Electron!"); } - @Override - public WebDriver getWebDriver(Capabilities capabilities) { - return new RemoteWebDriver(remoteURL, capabilities); - } + ChromeOptions chromeOptions = new ChromeOptions(); + chromeOptions.setBinary(APP_PATH.getValue()); + return chromeOptions; + } + + @Override + public WebDriver getWebDriver(Capabilities capabilities) { + return new RemoteWebDriver(remoteURL, capabilities); + } } diff --git a/src/main/java/com/frameworkium/core/ui/driver/drivers/FirefoxImpl.java b/src/main/java/com/frameworkium/core/ui/driver/drivers/FirefoxImpl.java index 2d0dfda6..900313c8 100644 --- a/src/main/java/com/frameworkium/core/ui/driver/drivers/FirefoxImpl.java +++ b/src/main/java/com/frameworkium/core/ui/driver/drivers/FirefoxImpl.java @@ -4,26 +4,28 @@ import com.frameworkium.core.ui.driver.AbstractDriver; import org.openqa.selenium.Capabilities; import org.openqa.selenium.WebDriver; -import org.openqa.selenium.firefox.*; +import org.openqa.selenium.firefox.FirefoxDriver; +import org.openqa.selenium.firefox.FirefoxDriverLogLevel; +import org.openqa.selenium.firefox.FirefoxOptions; public class FirefoxImpl extends AbstractDriver { - @Override - public FirefoxOptions getCapabilities() { - FirefoxOptions firefoxOptions = new FirefoxOptions(); - firefoxOptions.setHeadless(Property.HEADLESS.getBoolean()); - firefoxOptions.setLogLevel(FirefoxDriverLogLevel.INFO); - return firefoxOptions; - } + @Override + public FirefoxOptions getCapabilities() { + FirefoxOptions firefoxOptions = new FirefoxOptions(); + firefoxOptions.setHeadless(Property.HEADLESS.getBoolean()); + firefoxOptions.setLogLevel(FirefoxDriverLogLevel.INFO); + return firefoxOptions; + } - @Override - public WebDriver getWebDriver(Capabilities capabilities) { - final FirefoxOptions firefoxOptions; - if (capabilities instanceof FirefoxOptions) { - firefoxOptions = (FirefoxOptions) capabilities; - } else { - firefoxOptions = new FirefoxOptions().merge(capabilities); - } - return new FirefoxDriver(firefoxOptions); + @Override + public WebDriver getWebDriver(Capabilities capabilities) { + final FirefoxOptions firefoxOptions; + if (capabilities instanceof FirefoxOptions) { + firefoxOptions = (FirefoxOptions) capabilities; + } else { + firefoxOptions = new FirefoxOptions().merge(capabilities); } + return new FirefoxDriver(firefoxOptions); + } } diff --git a/src/main/java/com/frameworkium/core/ui/driver/drivers/GridImpl.java b/src/main/java/com/frameworkium/core/ui/driver/drivers/GridImpl.java index 8e0ea413..57a96d22 100644 --- a/src/main/java/com/frameworkium/core/ui/driver/drivers/GridImpl.java +++ b/src/main/java/com/frameworkium/core/ui/driver/drivers/GridImpl.java @@ -1,49 +1,53 @@ package com.frameworkium.core.ui.driver.drivers; +import static com.frameworkium.core.common.properties.Property.APPLICATION_NAME; +import static com.frameworkium.core.common.properties.Property.BROWSER_VERSION; +import static com.frameworkium.core.common.properties.Property.PLATFORM; +import static com.frameworkium.core.common.properties.Property.PLATFORM_VERSION; + import com.frameworkium.core.common.properties.Property; import com.frameworkium.core.ui.driver.AbstractDriver; -import org.openqa.selenium.*; -import org.openqa.selenium.remote.RemoteWebDriver; - import java.net.MalformedURLException; import java.net.URL; - -import static com.frameworkium.core.common.properties.Property.*; +import org.openqa.selenium.Capabilities; +import org.openqa.selenium.MutableCapabilities; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.remote.RemoteWebDriver; public class GridImpl extends AbstractDriver { - private URL remoteURL; - private Capabilities capabilities; - - /** - * Implementation of driver for the Selenium Grid . - */ - public GridImpl(Capabilities capabilities) { - this.capabilities = capabilities; - try { - this.remoteURL = new URL(Property.GRID_URL.getValue()); - } catch (MalformedURLException e) { - throw new RuntimeException(e); - } + private URL remoteURL; + private Capabilities capabilities; + + /** + * Implementation of driver for the Selenium Grid . + */ + public GridImpl(Capabilities capabilities) { + this.capabilities = capabilities; + try { + this.remoteURL = new URL(Property.GRID_URL.getValue()); + } catch (MalformedURLException e) { + throw new RuntimeException(e); } + } - @Override - public Capabilities getCapabilities() { - MutableCapabilities mutableCapabilities = new MutableCapabilities(capabilities); - if (BROWSER_VERSION.isSpecified()) { - mutableCapabilities.setCapability("version", BROWSER_VERSION.getValue()); - } - if (PLATFORM.isSpecified()) { - mutableCapabilities.setCapability("platform", PLATFORM_VERSION.getValue()); - } - if (APPLICATION_NAME.isSpecified()) { - mutableCapabilities.setCapability("applicationName", APPLICATION_NAME.getValue()); - } - return mutableCapabilities; + @Override + public Capabilities getCapabilities() { + MutableCapabilities mutableCapabilities = new MutableCapabilities(capabilities); + if (BROWSER_VERSION.isSpecified()) { + mutableCapabilities.setCapability("version", BROWSER_VERSION.getValue()); } - - @Override - public WebDriver getWebDriver(Capabilities capabilities) { - return new RemoteWebDriver(remoteURL, capabilities); + if (PLATFORM.isSpecified()) { + mutableCapabilities.setCapability("platform", PLATFORM_VERSION.getValue()); } + if (APPLICATION_NAME.isSpecified()) { + mutableCapabilities.setCapability("applicationName", APPLICATION_NAME.getValue()); + } + return mutableCapabilities; + } + + @Override + public WebDriver getWebDriver(Capabilities capabilities) { + return new RemoteWebDriver(remoteURL, capabilities); + } } diff --git a/src/main/java/com/frameworkium/core/ui/driver/drivers/InternetExplorerImpl.java b/src/main/java/com/frameworkium/core/ui/driver/drivers/InternetExplorerImpl.java index 09a937b4..333625cd 100644 --- a/src/main/java/com/frameworkium/core/ui/driver/drivers/InternetExplorerImpl.java +++ b/src/main/java/com/frameworkium/core/ui/driver/drivers/InternetExplorerImpl.java @@ -9,17 +9,17 @@ public class InternetExplorerImpl extends AbstractDriver { - @Override - public InternetExplorerOptions getCapabilities() { - InternetExplorerOptions ieOptions = new InternetExplorerOptions(); - ieOptions.setCapability(CapabilityType.ForSeleniumServer.ENSURING_CLEAN_SESSION, true); - ieOptions.setCapability(InternetExplorerDriver.ENABLE_PERSISTENT_HOVERING, true); - ieOptions.setCapability("requireWindowFocus", true); - return ieOptions; - } + @Override + public InternetExplorerOptions getCapabilities() { + InternetExplorerOptions ieOptions = new InternetExplorerOptions(); + ieOptions.setCapability(CapabilityType.ForSeleniumServer.ENSURING_CLEAN_SESSION, true); + ieOptions.setCapability(InternetExplorerDriver.ENABLE_PERSISTENT_HOVERING, true); + ieOptions.setCapability("requireWindowFocus", true); + return ieOptions; + } - @Override - public WebDriver getWebDriver(Capabilities capabilities) { - return new InternetExplorerDriver(new InternetExplorerOptions(capabilities)); - } + @Override + public WebDriver getWebDriver(Capabilities capabilities) { + return new InternetExplorerDriver(new InternetExplorerOptions(capabilities)); + } } diff --git a/src/main/java/com/frameworkium/core/ui/driver/drivers/LegacyFirefoxImpl.java b/src/main/java/com/frameworkium/core/ui/driver/drivers/LegacyFirefoxImpl.java index a268d26c..661b4fd4 100644 --- a/src/main/java/com/frameworkium/core/ui/driver/drivers/LegacyFirefoxImpl.java +++ b/src/main/java/com/frameworkium/core/ui/driver/drivers/LegacyFirefoxImpl.java @@ -4,10 +4,10 @@ public class LegacyFirefoxImpl extends FirefoxImpl { - @Override - public FirefoxOptions getCapabilities() { - FirefoxOptions firefoxOptions = new FirefoxOptions(); - firefoxOptions.setLegacy(true); - return firefoxOptions; - } + @Override + public FirefoxOptions getCapabilities() { + FirefoxOptions firefoxOptions = new FirefoxOptions(); + firefoxOptions.setLegacy(true); + return firefoxOptions; + } } diff --git a/src/main/java/com/frameworkium/core/ui/driver/drivers/SafariImpl.java b/src/main/java/com/frameworkium/core/ui/driver/drivers/SafariImpl.java index d42a2ca5..415a6438 100644 --- a/src/main/java/com/frameworkium/core/ui/driver/drivers/SafariImpl.java +++ b/src/main/java/com/frameworkium/core/ui/driver/drivers/SafariImpl.java @@ -9,25 +9,25 @@ public class SafariImpl extends AbstractDriver { - @Override - public SafariOptions getCapabilities() { - if (Driver.isMobile()) { - return new SafariOptions(); - } else { - SafariOptions safariOptions = new SafariOptions(); - safariOptions.setCapability("safari.cleanSession", true); - return safariOptions; - } + @Override + public SafariOptions getCapabilities() { + if (Driver.isMobile()) { + return new SafariOptions(); + } else { + SafariOptions safariOptions = new SafariOptions(); + safariOptions.setCapability("safari.cleanSession", true); + return safariOptions; } + } - @Override - public WebDriver getWebDriver(Capabilities capabilities) { - if (Driver.isMobile()) { - throw new IllegalArgumentException( - "seleniumGridURL or sauceUser and sauceKey must be specified when running on iOS"); - } else { - return new SafariDriver(new SafariOptions(capabilities)); - } + @Override + public WebDriver getWebDriver(Capabilities capabilities) { + if (Driver.isMobile()) { + throw new IllegalArgumentException( + "seleniumGridURL or sauceUser and sauceKey must be specified when running on iOS"); + } else { + return new SafariDriver(new SafariOptions(capabilities)); } + } } diff --git a/src/main/java/com/frameworkium/core/ui/driver/drivers/SauceImpl.java b/src/main/java/com/frameworkium/core/ui/driver/drivers/SauceImpl.java index c2352f41..bce40a47 100644 --- a/src/main/java/com/frameworkium/core/ui/driver/drivers/SauceImpl.java +++ b/src/main/java/com/frameworkium/core/ui/driver/drivers/SauceImpl.java @@ -1,137 +1,142 @@ package com.frameworkium.core.ui.driver.drivers; +import static com.frameworkium.core.common.properties.Property.APP_PATH; +import static com.frameworkium.core.common.properties.Property.BROWSER_VERSION; +import static com.frameworkium.core.common.properties.Property.BUILD; +import static com.frameworkium.core.common.properties.Property.DEVICE; +import static com.frameworkium.core.common.properties.Property.PLATFORM_VERSION; +import static com.frameworkium.core.ui.driver.DriverSetup.Platform; + import com.frameworkium.core.ui.driver.AbstractDriver; import com.frameworkium.core.ui.driver.Driver; import com.frameworkium.core.ui.driver.remotes.Sauce; -import org.openqa.selenium.*; -import org.openqa.selenium.remote.RemoteWebDriver; - import java.io.File; import java.net.URL; - -import static com.frameworkium.core.common.properties.Property.*; -import static com.frameworkium.core.ui.driver.DriverSetup.Platform; +import org.openqa.selenium.Capabilities; +import org.openqa.selenium.MutableCapabilities; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.remote.RemoteWebDriver; public class SauceImpl extends AbstractDriver { - private Platform platform; - private Capabilities capabilities; - private URL remoteURL; + private Platform platform; + private Capabilities capabilities; + private URL remoteURL; - public SauceImpl(Platform platform, Capabilities capabilities) { - this.platform = platform; - this.capabilities = capabilities; - this.remoteURL = Sauce.getURL(); - } + public SauceImpl(Platform platform, Capabilities capabilities) { + this.platform = platform; + this.capabilities = capabilities; + this.remoteURL = Sauce.getURL(); + } - @Override - public Capabilities getCapabilities() { - MutableCapabilities mutableCapabilities; - if (Driver.isNative()) { - mutableCapabilities = getAppiumCapabilities(); - } else { - mutableCapabilities = getCapabilitiesBasedOnPlatform(); - } - mutableCapabilities.setCapability("capture-html", true); - mutableCapabilities.setCapability("sauce-advisor", false); - mutableCapabilities.setCapability("build", BUILD.getValue()); - return mutableCapabilities; + @Override + public Capabilities getCapabilities() { + MutableCapabilities mutableCapabilities; + if (Driver.isNative()) { + mutableCapabilities = getAppiumCapabilities(); + } else { + mutableCapabilities = getCapabilitiesBasedOnPlatform(); } + mutableCapabilities.setCapability("capture-html", true); + mutableCapabilities.setCapability("sauce-advisor", false); + mutableCapabilities.setCapability("build", BUILD.getValue()); + return mutableCapabilities; + } - @Override - public WebDriver getWebDriver(Capabilities capabilities) { - return new RemoteWebDriver(remoteURL, capabilities); + @Override + public WebDriver getWebDriver(Capabilities capabilities) { + return new RemoteWebDriver(remoteURL, capabilities); + } + + private MutableCapabilities getCapabilitiesBasedOnPlatform() { + switch (platform) { + case WINDOWS: + return getDesktopCapabilities("Windows"); + case OSX: + return getDesktopCapabilities("OS X"); + case ANDROID: + return getAndroidCapabilities(); + case IOS: + return getIOSCapabilities(); + default: + throw new IllegalStateException( + "Unrecognised platform: " + platform); } + } - private MutableCapabilities getCapabilitiesBasedOnPlatform() { - switch (platform) { - case WINDOWS: - return getDesktopCapabilities("Windows"); - case OSX: - return getDesktopCapabilities("OS X"); - case ANDROID: - return getAndroidCapabilities(); - case IOS: - return getIOSCapabilities(); - default: - throw new IllegalStateException( - "Unrecognised platform: " + platform); - } + private MutableCapabilities getDesktopCapabilities(String platformName) { + if (!PLATFORM_VERSION.isSpecified()) { + throw new IllegalArgumentException( + "Platform version required for " + platformName + " SauceLabs!"); + } + MutableCapabilities caps = new MutableCapabilities(capabilities); + caps.setCapability( + "platform", platformName + " " + PLATFORM_VERSION.getValue()); + if (BROWSER_VERSION.isSpecified()) { + caps.setCapability("version", BROWSER_VERSION.getValue()); } + return caps; + } - private MutableCapabilities getDesktopCapabilities(String platformName) { - if (!PLATFORM_VERSION.isSpecified()) { - throw new IllegalArgumentException( - "Platform version required for " + platformName + " SauceLabs!"); - } - MutableCapabilities caps = new MutableCapabilities(capabilities); - caps.setCapability( - "platform", platformName + " " + PLATFORM_VERSION.getValue()); - if (BROWSER_VERSION.isSpecified()) { - caps.setCapability("version", BROWSER_VERSION.getValue()); - } - return caps; + private MutableCapabilities getAndroidCapabilities() { + MutableCapabilities caps = new MutableCapabilities(capabilities); + caps.setCapability("platformName", "Android"); + if (PLATFORM_VERSION.isSpecified()) { + caps.setCapability("version", PLATFORM_VERSION.getValue()); } + caps.setCapability("deviceName", "Android Emulator"); + setPortraitOrientation(caps); + return caps; + } - private MutableCapabilities getAndroidCapabilities() { - MutableCapabilities caps = new MutableCapabilities(capabilities); - caps.setCapability("platformName", "Android"); - if (PLATFORM_VERSION.isSpecified()) { - caps.setCapability("version", PLATFORM_VERSION.getValue()); - } - caps.setCapability("deviceName", "Android Emulator"); - setPortraitOrientation(caps); - return caps; + private MutableCapabilities getIOSCapabilities() { + MutableCapabilities caps = new MutableCapabilities(capabilities); + caps.setCapability("deviceName", "iPhone .*"); + caps.setCapability("platformName", "iOS"); + if (PLATFORM_VERSION.isSpecified()) { + caps.setCapability("version", PLATFORM_VERSION.getValue()); + } + if (DEVICE.isSpecified()) { + caps.setCapability("deviceName", DEVICE.getValue() + " Simulator"); } + setPortraitOrientation(caps); + return caps; + } - private MutableCapabilities getIOSCapabilities() { - MutableCapabilities caps = new MutableCapabilities(capabilities); + private MutableCapabilities getAppiumCapabilities() { + MutableCapabilities caps = new MutableCapabilities(capabilities); + caps.setCapability( + "app", "sauce-storage:" + new File(APP_PATH.getValue()).getName()); + caps.setCapability("appiumVersion", "1.4.10"); + setPortraitOrientation(caps); + caps.setCapability("browserName", ""); + switch (platform) { + case IOS: caps.setCapability("deviceName", "iPhone .*"); - caps.setCapability("platformName", "iOS"); - if (PLATFORM_VERSION.isSpecified()) { - caps.setCapability("version", PLATFORM_VERSION.getValue()); - } - if (DEVICE.isSpecified()) { - caps.setCapability("deviceName", DEVICE.getValue() + " Simulator"); - } - setPortraitOrientation(caps); - return caps; + return getAppiumCapabilities(caps, "iOS", "Simulator"); + case ANDROID: + caps.setCapability("platformName", "Android"); + return getAppiumCapabilities(caps, "Android", "Emulator"); + default: + throw new IllegalStateException("Appium is only available on iOS/Android"); } + } - private MutableCapabilities getAppiumCapabilities() { - MutableCapabilities caps = new MutableCapabilities(capabilities); - caps.setCapability( - "app", "sauce-storage:" + new File(APP_PATH.getValue()).getName()); - caps.setCapability("appiumVersion", "1.4.10"); - setPortraitOrientation(caps); - caps.setCapability("browserName", ""); - switch (platform) { - case IOS: - caps.setCapability("deviceName", "iPhone .*"); - return getAppiumCapabilities(caps, "iOS", "Simulator"); - case ANDROID: - caps.setCapability("platformName", "Android"); - return getAppiumCapabilities(caps, "Android", "Emulator"); - default: - throw new IllegalStateException("Appium is only available on iOS/Android"); - } + private MutableCapabilities getAppiumCapabilities( + Capabilities commonCaps, String platformName, String emulatorOrSimulator) { + MutableCapabilities caps = new MutableCapabilities(commonCaps); + if (DEVICE.isSpecified()) { + caps.setCapability( + "deviceName", DEVICE.getValue() + " " + emulatorOrSimulator); } - - private MutableCapabilities getAppiumCapabilities( - Capabilities commonCaps, String platformName, String emulatorOrSimulator) { - MutableCapabilities caps = new MutableCapabilities(commonCaps); - if (DEVICE.isSpecified()) { - caps.setCapability( - "deviceName", DEVICE.getValue() + " " + emulatorOrSimulator); - } - caps.setCapability("platformName", platformName); - if (PLATFORM_VERSION.isSpecified()) { - caps.setCapability("platformVersion", PLATFORM_VERSION.getValue()); - } - return caps; + caps.setCapability("platformName", platformName); + if (PLATFORM_VERSION.isSpecified()) { + caps.setCapability("platformVersion", PLATFORM_VERSION.getValue()); } + return caps; + } - private void setPortraitOrientation(MutableCapabilities caps) { - caps.setCapability("deviceOrientation", "portrait"); - } + private void setPortraitOrientation(MutableCapabilities caps) { + caps.setCapability("deviceOrientation", "portrait"); + } } diff --git a/src/main/java/com/frameworkium/core/ui/driver/lifecycle/DriverLifecycle.java b/src/main/java/com/frameworkium/core/ui/driver/lifecycle/DriverLifecycle.java index 4583dbf0..70da8464 100644 --- a/src/main/java/com/frameworkium/core/ui/driver/lifecycle/DriverLifecycle.java +++ b/src/main/java/com/frameworkium/core/ui/driver/lifecycle/DriverLifecycle.java @@ -1,9 +1,8 @@ package com.frameworkium.core.ui.driver.lifecycle; import com.frameworkium.core.ui.driver.Driver; -import org.openqa.selenium.WebDriver; - import java.util.function.Supplier; +import org.openqa.selenium.WebDriver; /** * Controls the lifecycle of the {@link Driver}(s). @@ -22,41 +21,43 @@ */ public interface DriverLifecycle { - /** - * Will initialise a pool of {@link Driver}s if required. - * - * @param driverSupplier the {@link Supplier} that creates {@link Driver}s - * @throws IllegalStateException if trying to re-initialise existing pool - */ - default void initDriverPool(Supplier driverSupplier) {} - - /** - * Will set the current {@link ThreadLocal} {@link Driver} to be the next - * available from the pool or will add the {@link Driver} created by the - * supplied {@link Supplier}. - * - * @param driverSupplier the {@link Supplier} that creates {@link Driver}s - * @throws java.util.NoSuchElementException if this pool is empty - */ - void initBrowserBeforeTest(Supplier driverSupplier); - - /** - * @return the {@link WebDriver} in use by the current thread. - * @throws NullPointerException if called before - * {@link #initBrowserBeforeTest(Supplier)} or - * after {@link #tearDownDriver()}. - */ - WebDriver getWebDriver(); - - /** - * Tears down the driver, ready for reinitialisation, if required, by - * {@link #initBrowserBeforeTest(Supplier)}. - */ - void tearDownDriver(); - - /** - * Clears the driver pool, if exists, ready to run run - * {@link #initDriverPool(Supplier)} again if required. - */ - default void tearDownDriverPool() {} + /** + * Will initialise a pool of {@link Driver}s if required. + * + * @param driverSupplier the {@link Supplier} that creates {@link Driver}s + * @throws IllegalStateException if trying to re-initialise existing pool + */ + default void initDriverPool(Supplier driverSupplier) { + } + + /** + * Will set the current {@link ThreadLocal} {@link Driver} to be the next + * available from the pool or will add the {@link Driver} created by the + * supplied {@link Supplier}. + * + * @param driverSupplier the {@link Supplier} that creates {@link Driver}s + * @throws java.util.NoSuchElementException if this pool is empty + */ + void initBrowserBeforeTest(Supplier driverSupplier); + + /** + * @return the {@link WebDriver} in use by the current thread. + * @throws NullPointerException if called before + * {@link #initBrowserBeforeTest(Supplier)} or + * after {@link #tearDownDriver()}. + */ + WebDriver getWebDriver(); + + /** + * Tears down the driver, ready for reinitialisation, if required, by + * {@link #initBrowserBeforeTest(Supplier)}. + */ + void tearDownDriver(); + + /** + * Clears the driver pool, if exists, ready to run run + * {@link #initDriverPool(Supplier)} again if required. + */ + default void tearDownDriverPool() { + } } diff --git a/src/main/java/com/frameworkium/core/ui/driver/lifecycle/MultiUseDriverLifecycle.java b/src/main/java/com/frameworkium/core/ui/driver/lifecycle/MultiUseDriverLifecycle.java index 49c75486..9b4eaf74 100644 --- a/src/main/java/com/frameworkium/core/ui/driver/lifecycle/MultiUseDriverLifecycle.java +++ b/src/main/java/com/frameworkium/core/ui/driver/lifecycle/MultiUseDriverLifecycle.java @@ -1,107 +1,106 @@ package com.frameworkium.core.ui.driver.lifecycle; import com.frameworkium.core.ui.driver.Driver; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.openqa.selenium.WebDriver; - import java.util.concurrent.BlockingDeque; import java.util.concurrent.LinkedBlockingDeque; import java.util.function.Supplier; import java.util.stream.IntStream; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.openqa.selenium.WebDriver; -/** @see DriverLifecycle */ +/** + * @see DriverLifecycle + */ public class MultiUseDriverLifecycle implements DriverLifecycle { - private static final Logger logger = LogManager.getLogger(); - - private int poolSize; - private BlockingDeque driverPool; + private static final Logger logger = LogManager.getLogger(); + private static final ThreadLocal threadLocalDriver = new ThreadLocal<>(); + private int poolSize; + private BlockingDeque driverPool; - private static final ThreadLocal threadLocalDriver = new ThreadLocal<>(); + public MultiUseDriverLifecycle(int poolSize) { + this.poolSize = poolSize; + } - public MultiUseDriverLifecycle(int poolSize) { - this.poolSize = poolSize; + /** + * Create {@link Driver}s in parallel and add them to the pool up to the + * size specified. + * + * @param driverSupplier the {@link Supplier} that creates {@link Driver}s + * @throws IllegalStateException if trying to re-initialise existing pool + */ + @Override + public void initDriverPool(Supplier driverSupplier) { + if (driverPool != null) { + throw new IllegalStateException( + "initDriverPool called when already initialised"); } + driverPool = new LinkedBlockingDeque<>(poolSize); + IntStream.range(0, poolSize) + .parallel() + .mapToObj(i -> driverSupplier.get()) + .forEach(driverPool::addLast); + } - /** - * Create {@link Driver}s in parallel and add them to the pool up to the - * size specified. - * - * @param driverSupplier the {@link Supplier} that creates {@link Driver}s - * @throws IllegalStateException if trying to re-initialise existing pool - */ - @Override - public void initDriverPool(Supplier driverSupplier) { - if (driverPool != null) { - throw new IllegalStateException( - "initDriverPool called when already initialised"); - } - driverPool = new LinkedBlockingDeque<>(poolSize); - IntStream.range(0, poolSize) - .parallel() - .mapToObj(i -> driverSupplier.get()) - .forEach(driverPool::addLast); - } + /** + * Will set the current {@link ThreadLocal} {@link Driver} to be the next + * available from the pool. + * + * @param driverSupplier the {@link Supplier} that creates {@link Driver}s + * @throws java.util.NoSuchElementException if this pool is empty + */ + @Override + public void initBrowserBeforeTest(Supplier driverSupplier) { + threadLocalDriver.set(driverPool.removeFirst()); + } - /** - * Will set the current {@link ThreadLocal} {@link Driver} to be the next - * available from the pool. - * - * @param driverSupplier the {@link Supplier} that creates {@link Driver}s - * @throws java.util.NoSuchElementException if this pool is empty - */ - @Override - public void initBrowserBeforeTest(Supplier driverSupplier) { - threadLocalDriver.set(driverPool.removeFirst()); - } + @Override + public WebDriver getWebDriver() { + return threadLocalDriver.get().getWebDriver().getWrappedDriver(); + } - @Override - public WebDriver getWebDriver() { - return threadLocalDriver.get().getWebDriver().getWrappedDriver(); + /** + * If reuseBrowser is true, this will {@code deleteAllCookies} and then + * re-add the {@link Driver} back to the pool, else it will call {@code quit()} + * on the underlying {@link WebDriver}. + */ + @Override + public void tearDownDriver() { + try { + Driver driver = threadLocalDriver.get(); + driver.getWebDriver().manage().deleteAllCookies(); + driverPool.addLast(driver); + } catch (Exception e) { + logger.error("Failed to tear down browser after test method."); + logger.debug("Failed to tear down browser after test method.", e); + throw e; + } finally { + threadLocalDriver.remove(); } + } - /** - * If reuseBrowser is true, this will {@code deleteAllCookies} and then - * re-add the {@link Driver} back to the pool, else it will call {@code quit()} - * on the underlying {@link WebDriver}. - */ - @Override - public void tearDownDriver() { - try { - Driver driver = threadLocalDriver.get(); - driver.getWebDriver().manage().deleteAllCookies(); - driverPool.addLast(driver); - } catch (Exception e) { - logger.error("Failed to tear down browser after test method."); - logger.debug("Failed to tear down browser after test method.", e); - throw e; - } finally { - threadLocalDriver.remove(); - } + /** + * Drains the pool, calls {@link WebDriver#quit} on every {@link Driver} + * remaining in the pool and sets the pool to {@code null}. + */ + @Override + public void tearDownDriverPool() { + if (driverPool == null) { + return; } - /** - * Drains the pool, calls {@link WebDriver#quit} on every {@link Driver} - * remaining in the pool and sets the pool to {@code null}. - */ - @Override - public void tearDownDriverPool() { - if (driverPool == null) { - return; - } - - driverPool.parallelStream() - .forEach(driver -> { - try { - driver.getWebDriver().quit(); - } catch (Exception e) { - logger.error("Failed to quit a browser in the pool."); - logger.debug("Failed to quit a browser in the pool.", e); - } - }); + driverPool.parallelStream() + .forEach(driver -> { + try { + driver.getWebDriver().quit(); + } catch (Exception e) { + logger.error("Failed to quit a browser in the pool."); + logger.debug("Failed to quit a browser in the pool.", e); + } + }); - driverPool = null; // allows re-initialisation - } + driverPool = null; // allows re-initialisation + } } diff --git a/src/main/java/com/frameworkium/core/ui/driver/lifecycle/SingleUseDriverLifecycle.java b/src/main/java/com/frameworkium/core/ui/driver/lifecycle/SingleUseDriverLifecycle.java index 54d7a186..f934ed6d 100644 --- a/src/main/java/com/frameworkium/core/ui/driver/lifecycle/SingleUseDriverLifecycle.java +++ b/src/main/java/com/frameworkium/core/ui/driver/lifecycle/SingleUseDriverLifecycle.java @@ -1,12 +1,11 @@ package com.frameworkium.core.ui.driver.lifecycle; import com.frameworkium.core.ui.driver.Driver; +import java.util.function.Supplier; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.openqa.selenium.WebDriver; -import java.util.function.Supplier; - /** * {@link #initDriverPool(Supplier)} and {@link #tearDownDriverPool()} do not do * anything for {@link SingleUseDriverLifecycle} and can be omitted. @@ -15,40 +14,40 @@ */ public class SingleUseDriverLifecycle implements DriverLifecycle { - private static final Logger logger = LogManager.getLogger(); - - private static final ThreadLocal threadLocalDriver = new ThreadLocal<>(); - - /** - * Sets the {@link Driver} created by the supplied {@link Supplier} to the - * {@link ThreadLocal} driver. - * - * @param driverSupplier the {@link Supplier} that creates {@link Driver}s - */ - @Override - public void initBrowserBeforeTest(Supplier driverSupplier) { - threadLocalDriver.set(driverSupplier.get()); - } - - @Override - public WebDriver getWebDriver() { - return threadLocalDriver.get().getWebDriver().getWrappedDriver(); - } - - /** - * Calls {@code quit()} on the underlying driver. - */ - @Override - public void tearDownDriver() { - try { - threadLocalDriver.get().getWebDriver().quit(); - } catch (Exception e) { - logger.error("Failed to quit browser."); - logger.debug("Failed to quit browser", e); - throw e; - } finally { - threadLocalDriver.remove(); - } + private static final Logger logger = LogManager.getLogger(); + + private static final ThreadLocal threadLocalDriver = new ThreadLocal<>(); + + /** + * Sets the {@link Driver} created by the supplied {@link Supplier} to the + * {@link ThreadLocal} driver. + * + * @param driverSupplier the {@link Supplier} that creates {@link Driver}s + */ + @Override + public void initBrowserBeforeTest(Supplier driverSupplier) { + threadLocalDriver.set(driverSupplier.get()); + } + + @Override + public WebDriver getWebDriver() { + return threadLocalDriver.get().getWebDriver().getWrappedDriver(); + } + + /** + * Calls {@code quit()} on the underlying driver. + */ + @Override + public void tearDownDriver() { + try { + threadLocalDriver.get().getWebDriver().quit(); + } catch (Exception e) { + logger.error("Failed to quit browser."); + logger.debug("Failed to quit browser", e); + throw e; + } finally { + threadLocalDriver.remove(); } + } } diff --git a/src/main/java/com/frameworkium/core/ui/driver/remotes/BrowserStack.java b/src/main/java/com/frameworkium/core/ui/driver/remotes/BrowserStack.java index c47b2724..a070f4f3 100644 --- a/src/main/java/com/frameworkium/core/ui/driver/remotes/BrowserStack.java +++ b/src/main/java/com/frameworkium/core/ui/driver/remotes/BrowserStack.java @@ -1,23 +1,23 @@ package com.frameworkium.core.ui.driver.remotes; +import static com.frameworkium.core.common.properties.Property.BROWSER_STACK; + import java.net.MalformedURLException; import java.net.URL; -import static com.frameworkium.core.common.properties.Property.BROWSER_STACK; - public class BrowserStack { - private BrowserStack() { - // hide default constructor for this util class - } + private BrowserStack() { + // hide default constructor for this util class + } - public static URL getURL() throws MalformedURLException { - return new URL(String.format("https://%s:%s@hub-cloud.browserstack.com/wd/hub", - System.getenv("BROWSER_STACK_USERNAME"), - System.getenv("BROWSER_STACK_ACCESS_KEY"))); - } + public static URL getURL() throws MalformedURLException { + return new URL(String.format("https://%s:%s@hub-cloud.browserstack.com/wd/hub", + System.getenv("BROWSER_STACK_USERNAME"), + System.getenv("BROWSER_STACK_ACCESS_KEY"))); + } - public static boolean isDesired() { - return BROWSER_STACK.getBoolean(); - } + public static boolean isDesired() { + return BROWSER_STACK.getBoolean(); + } } diff --git a/src/main/java/com/frameworkium/core/ui/driver/remotes/Sauce.java b/src/main/java/com/frameworkium/core/ui/driver/remotes/Sauce.java index 8c437213..17a12fb1 100644 --- a/src/main/java/com/frameworkium/core/ui/driver/remotes/Sauce.java +++ b/src/main/java/com/frameworkium/core/ui/driver/remotes/Sauce.java @@ -5,7 +5,6 @@ import com.saucelabs.common.SauceOnDemandAuthentication; import com.saucelabs.common.SauceOnDemandSessionIdProvider; import com.saucelabs.saucerest.SauceREST; - import java.io.File; import java.io.IOException; import java.net.MalformedURLException; @@ -13,40 +12,40 @@ public class Sauce { - private static final SauceOnDemandAuthentication sauceAuth = - new SauceOnDemandAuthentication( - System.getenv("SAUCE_USERNAME"), - System.getenv("SAUCE_ACCESS_KEY")); - - private static final SauceREST client = - new SauceREST( - sauceAuth.getUsername(), - sauceAuth.getAccessKey()); - - public static URL getURL() { - try { - return new URL(String.format( - "https://%s:%s@ondemand.saucelabs.com/wd/hub", - sauceAuth.getUsername(), - sauceAuth.getAccessKey())); - } catch (MalformedURLException e) { - throw new IllegalArgumentException(e); - } + private static final SauceOnDemandAuthentication sauceAuth = + new SauceOnDemandAuthentication( + System.getenv("SAUCE_USERNAME"), + System.getenv("SAUCE_ACCESS_KEY")); + + private static final SauceREST client = + new SauceREST( + sauceAuth.getUsername(), + sauceAuth.getAccessKey()); + + public static URL getURL() { + try { + return new URL(String.format( + "https://%s:%s@ondemand.saucelabs.com/wd/hub", + sauceAuth.getUsername(), + sauceAuth.getAccessKey())); + } catch (MalformedURLException e) { + throw new IllegalArgumentException(e); } + } - public static boolean isDesired() { - return Property.SAUCE.getBoolean(); - } + public static boolean isDesired() { + return Property.SAUCE.getBoolean(); + } - public static void updateJobName(SauceOnDemandSessionIdProvider sessionIdProvider, String name) { + public static void updateJobName(SauceOnDemandSessionIdProvider sessionIdProvider, String name) { - client.updateJobInfo( - sessionIdProvider.getSessionId(), - ImmutableMap.of("name", name)); - } + client.updateJobInfo( + sessionIdProvider.getSessionId(), + ImmutableMap.of("name", name)); + } - public static void uploadFile(File file) throws IOException { - client.uploadFile(file); - } + public static void uploadFile(File file) throws IOException { + client.uploadFile(file); + } } diff --git a/src/main/java/com/frameworkium/core/ui/element/AbstractStreamTable.java b/src/main/java/com/frameworkium/core/ui/element/AbstractStreamTable.java index 66d73728..600da4ba 100644 --- a/src/main/java/com/frameworkium/core/ui/element/AbstractStreamTable.java +++ b/src/main/java/com/frameworkium/core/ui/element/AbstractStreamTable.java @@ -2,12 +2,13 @@ import com.frameworkium.core.htmlelements.element.HtmlElement; import com.google.common.collect.Streams; -import org.openqa.selenium.*; - import java.util.Objects; import java.util.Optional; import java.util.function.Predicate; import java.util.stream.Stream; +import org.openqa.selenium.By; +import org.openqa.selenium.NoSuchElementException; +import org.openqa.selenium.WebElement; /** * {@link AbstractStreamTable} is an {@link HtmlElement} which provides a Java 8 @@ -42,178 +43,178 @@ */ public abstract class AbstractStreamTable extends HtmlElement { - /** - * @return a {@link Stream} of {@link WebElement}s representing the header - * cells of the table. - */ - protected abstract Stream headerCells(); - - /** - * @return a {@link Stream} of {@link WebElement}s representing the rows - * of the table. - */ - protected abstract Stream rows(); - - /** - * @return a {@link By} to select cells inside the table rows. - */ - protected abstract By cellLocator(); - - /** - * @return {@link Stream} of {@link WebElement}s representing the table - * heading cells. - */ - public Stream getHeadings() { - return headerCells(); - } - - /** - * @param index 0-based index - * @return {@link Optional} of the heading specified by the index - */ - public Optional getHeading(long index) { - return getHeadings().skip(index).findFirst(); - } - - /** - * @param text text of the header cell to return - * @return {@link Optional} of the first heading with text matching {@code text} - */ - public Optional getHeading(String text) { - return getHeading(e -> Objects.equals(e.getText().trim(), text)); - } - - /** - * @param headerMatcher matcher for of the header cell to return - * @return {@link Optional} of the first heading matching {@code headerMatcher} - */ - public Optional getHeading(Predicate headerMatcher) { - return getHeadings().filter(headerMatcher).findFirst(); - } - - /** - * @return {@link Stream} of {@link Stream} of row cell {@link WebElement}s - */ - public Stream> getRows() { - return rows() - .map(row -> row.findElements(cellLocator()).stream()); - } - - /** - * @param index 0-based index - * @return {@link Optional} of the row specified by the index - */ - public Optional> getRow(int index) { - return getRows().skip(index).findFirst(); - } - - /** - * Useful when the index is already known, or in other cases where the other - * methods do not work as expected, e.g. on tables which violate assumptions. - * - * @param index 0-based index of the column to return - * @return {@link Stream} of cells in the table column indexed {@code index} - */ - public Stream getColumn(long index) { - return getRows() - .map(rowCells -> rowCells - .skip(index) - .findFirst() - .orElseThrow(() -> new NoSuchElementException( - "A row doesn't have column index " + index))); - } - - /** - * @param headerText the text of the header we are looking for - * @return a {@link Stream} of {@link WebElement}s of the cells inside - * for the first column that matches the trimmed text of a header. - */ - public Stream getColumn(String headerText) { - long index = getHeaderIndex(e -> Objects.equals(e.getText(), headerText)); - return getColumn(index); - } - - /** - * @param headerMatcher predicate to find the header that we are looking for - * @return a {@link Stream} of {@link WebElement}s of the cells for the - * first column that matches the {@code headerMatcher} - */ - public Stream getColumn(Predicate headerMatcher) { - return getColumn(getHeaderIndex(headerMatcher)); - } - - /** - * Trims the text from the cells before comparing. - * - * @param lookupColHeaderText the String to match the header of the column - * where we want to lookup using {@code lookupCellText} - * @param lookupCellText the String to match the cell(s) in the column - * identified by {@code lookupColHeaderText} in the - * column identified by {@code targetColHeaderText} - * @param targetColHeaderText the String to match the header containing the - * return value(s) - * @return all {@link WebElement}s from the column matched by - * {@code targetColHeaderText} which matches {@code lookupCellText} - * in {@code lookupColHeaderText} - * @see #getCellsByLookup(Predicate, Predicate, Predicate) - */ - public Stream getCellsByLookup( - String lookupColHeaderText, String lookupCellText, String targetColHeaderText) { - return getCellsByLookup( - element -> element.getText().trim().equals(lookupColHeaderText), - element -> element.getText().trim().equals(lookupCellText), - element -> element.getText().trim().equals(targetColHeaderText) - ); - } - - /** - * Returns cells in the target column where the corresponding cell matches - * in the lookup column. - * - *

-     * +--+--------+---------+
-     * |  | lookup |  target |
-     * +--+--------+---------+
-     * |  | match---->return |
-     * |  |    |   |         |
-     * |  | match---->return |
-     * +--+--------+---------+
-     * 
- * - * @param lookupHeaderMatcher matches the header of the column where we want - * to lookup using {@code lookupCellMatcher} - * @param lookupCellMatcher matches the cell(s) in the column - * identified by {@code lookupHeaderMatcher} in the - * column identified by {@code targetHeaderMatcher} - * @param targetHeaderMatcher matches the header containing the return value(s) - * @return {@link WebElement}s from the column matched by - * {@code lookupHeaderMatcher} which matches {@code lookupCellMatcher} - * in {@code lookupHeaderMatcher} - */ - public Stream getCellsByLookup( - Predicate lookupHeaderMatcher, - Predicate lookupCellMatcher, - Predicate targetHeaderMatcher) { - - long lookupColumnIndex = getHeaderIndex(lookupHeaderMatcher); - long targetColumnIndex = getHeaderIndex(targetHeaderMatcher); - Stream lookupColumn = getColumn(lookupColumnIndex); - Stream targetColumn = getColumn(targetColumnIndex); - - return Streams.zip( - lookupColumn, - targetColumn, - (lookupCell, targetCell) -> - lookupCellMatcher.test(lookupCell) ? targetCell : null) - .filter(Objects::nonNull); - } - - private long getHeaderIndex(Predicate headerPredicate) { - return Streams.mapWithIndex( - getHeadings(), (webElement, i) -> headerPredicate.test(webElement) ? i : null) - .filter(Objects::nonNull) - .findFirst() - .orElseThrow(() -> new NoSuchElementException("No header found.")); - } + /** + * @return a {@link Stream} of {@link WebElement}s representing the header + * cells of the table. + */ + protected abstract Stream headerCells(); + + /** + * @return a {@link Stream} of {@link WebElement}s representing the rows + * of the table. + */ + protected abstract Stream rows(); + + /** + * @return a {@link By} to select cells inside the table rows. + */ + protected abstract By cellLocator(); + + /** + * @return {@link Stream} of {@link WebElement}s representing the table + * heading cells. + */ + public Stream getHeadings() { + return headerCells(); + } + + /** + * @param index 0-based index + * @return {@link Optional} of the heading specified by the index + */ + public Optional getHeading(long index) { + return getHeadings().skip(index).findFirst(); + } + + /** + * @param text text of the header cell to return + * @return {@link Optional} of the first heading with text matching {@code text} + */ + public Optional getHeading(String text) { + return getHeading(e -> Objects.equals(e.getText().trim(), text)); + } + + /** + * @param headerMatcher matcher for of the header cell to return + * @return {@link Optional} of the first heading matching {@code headerMatcher} + */ + public Optional getHeading(Predicate headerMatcher) { + return getHeadings().filter(headerMatcher).findFirst(); + } + + /** + * @return {@link Stream} of {@link Stream} of row cell {@link WebElement}s + */ + public Stream> getRows() { + return rows() + .map(row -> row.findElements(cellLocator()).stream()); + } + + /** + * @param index 0-based index + * @return {@link Optional} of the row specified by the index + */ + public Optional> getRow(int index) { + return getRows().skip(index).findFirst(); + } + + /** + * Useful when the index is already known, or in other cases where the other + * methods do not work as expected, e.g. on tables which violate assumptions. + * + * @param index 0-based index of the column to return + * @return {@link Stream} of cells in the table column indexed {@code index} + */ + public Stream getColumn(long index) { + return getRows() + .map(rowCells -> rowCells + .skip(index) + .findFirst() + .orElseThrow(() -> new NoSuchElementException( + "A row doesn't have column index " + index))); + } + + /** + * @param headerText the text of the header we are looking for + * @return a {@link Stream} of {@link WebElement}s of the cells inside + * for the first column that matches the trimmed text of a header. + */ + public Stream getColumn(String headerText) { + long index = getHeaderIndex(e -> Objects.equals(e.getText(), headerText)); + return getColumn(index); + } + + /** + * @param headerMatcher predicate to find the header that we are looking for + * @return a {@link Stream} of {@link WebElement}s of the cells for the + * first column that matches the {@code headerMatcher} + */ + public Stream getColumn(Predicate headerMatcher) { + return getColumn(getHeaderIndex(headerMatcher)); + } + + /** + * Trims the text from the cells before comparing. + * + * @param lookupColHeaderText the String to match the header of the column + * where we want to lookup using {@code lookupCellText} + * @param lookupCellText the String to match the cell(s) in the column + * identified by {@code lookupColHeaderText} in the + * column identified by {@code targetColHeaderText} + * @param targetColHeaderText the String to match the header containing the + * return value(s) + * @return all {@link WebElement}s from the column matched by + * {@code targetColHeaderText} which matches {@code lookupCellText} + * in {@code lookupColHeaderText} + * @see #getCellsByLookup(Predicate, Predicate, Predicate) + */ + public Stream getCellsByLookup( + String lookupColHeaderText, String lookupCellText, String targetColHeaderText) { + return getCellsByLookup( + element -> element.getText().trim().equals(lookupColHeaderText), + element -> element.getText().trim().equals(lookupCellText), + element -> element.getText().trim().equals(targetColHeaderText) + ); + } + + /** + * Returns cells in the target column where the corresponding cell matches + * in the lookup column. + * + *
+   * +--+--------+---------+
+   * |  | lookup |  target |
+   * +--+--------+---------+
+   * |  | match---->return |
+   * |  |    |   |         |
+   * |  | match---->return |
+   * +--+--------+---------+
+   * 
+ * + * @param lookupHeaderMatcher matches the header of the column where we want + * to lookup using {@code lookupCellMatcher} + * @param lookupCellMatcher matches the cell(s) in the column + * identified by {@code lookupHeaderMatcher} in the + * column identified by {@code targetHeaderMatcher} + * @param targetHeaderMatcher matches the header containing the return value(s) + * @return {@link WebElement}s from the column matched by + * {@code lookupHeaderMatcher} which matches {@code lookupCellMatcher} + * in {@code lookupHeaderMatcher} + */ + public Stream getCellsByLookup( + Predicate lookupHeaderMatcher, + Predicate lookupCellMatcher, + Predicate targetHeaderMatcher) { + + long lookupColumnIndex = getHeaderIndex(lookupHeaderMatcher); + long targetColumnIndex = getHeaderIndex(targetHeaderMatcher); + Stream lookupColumn = getColumn(lookupColumnIndex); + Stream targetColumn = getColumn(targetColumnIndex); + + return Streams.zip( + lookupColumn, + targetColumn, + (lookupCell, targetCell) -> + lookupCellMatcher.test(lookupCell) ? targetCell : null) + .filter(Objects::nonNull); + } + + private long getHeaderIndex(Predicate headerPredicate) { + return Streams.mapWithIndex( + getHeadings(), (webElement, i) -> headerPredicate.test(webElement) ? i : null) + .filter(Objects::nonNull) + .findFirst() + .orElseThrow(() -> new NoSuchElementException("No header found.")); + } } diff --git a/src/main/java/com/frameworkium/core/ui/element/OptimisedStreamTable.java b/src/main/java/com/frameworkium/core/ui/element/OptimisedStreamTable.java index 1be63d44..c1621be1 100644 --- a/src/main/java/com/frameworkium/core/ui/element/OptimisedStreamTable.java +++ b/src/main/java/com/frameworkium/core/ui/element/OptimisedStreamTable.java @@ -1,12 +1,11 @@ package com.frameworkium.core.ui.element; +import java.util.List; +import java.util.stream.Stream; import org.openqa.selenium.By; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.FindBy; -import java.util.List; -import java.util.stream.Stream; - /** * {@link OptimisedStreamTable} is an {@link AbstractStreamTable}. * @@ -20,25 +19,25 @@ */ public class OptimisedStreamTable extends AbstractStreamTable { - @FindBy(css = "thead > tr > th") - private List headerCells; + @FindBy(css = "thead > tr > th") + private List headerCells; - @FindBy(css = "tbody > tr") - private List rows; + @FindBy(css = "tbody > tr") + private List rows; - @Override - protected Stream headerCells() { - return headerCells.stream(); - } + @Override + protected Stream headerCells() { + return headerCells.stream(); + } - @Override - protected Stream rows() { - return rows.stream(); - } + @Override + protected Stream rows() { + return rows.stream(); + } - @Override - protected By cellLocator() { - return By.cssSelector("td"); - } + @Override + protected By cellLocator() { + return By.cssSelector("td"); + } } diff --git a/src/main/java/com/frameworkium/core/ui/element/StreamTable.java b/src/main/java/com/frameworkium/core/ui/element/StreamTable.java index 73d3ce9d..5006a5a9 100644 --- a/src/main/java/com/frameworkium/core/ui/element/StreamTable.java +++ b/src/main/java/com/frameworkium/core/ui/element/StreamTable.java @@ -1,12 +1,11 @@ package com.frameworkium.core.ui.element; +import java.util.List; +import java.util.stream.Stream; import org.openqa.selenium.By; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.FindBy; -import java.util.List; -import java.util.stream.Stream; - /** * {@link StreamTable} is an {@link AbstractStreamTable}. * @@ -19,25 +18,25 @@ */ public class StreamTable extends AbstractStreamTable { - @FindBy(css = "thead > tr > th") - private List headerCells; + @FindBy(css = "thead > tr > th") + private List headerCells; - @FindBy(css = "tbody > tr") - private List rows; + @FindBy(css = "tbody > tr") + private List rows; - @Override - protected Stream headerCells() { - return headerCells.stream().filter(WebElement::isDisplayed); - } + @Override + protected Stream headerCells() { + return headerCells.stream().filter(WebElement::isDisplayed); + } - @Override - protected Stream rows() { - return rows.stream().filter(WebElement::isDisplayed); - } + @Override + protected Stream rows() { + return rows.stream().filter(WebElement::isDisplayed); + } - @Override - protected By cellLocator() { - return By.cssSelector("td"); - } + @Override + protected By cellLocator() { + return By.cssSelector("td"); + } } diff --git a/src/main/java/com/frameworkium/core/ui/js/JavascriptWait.java b/src/main/java/com/frameworkium/core/ui/js/JavascriptWait.java index 5713e3f3..2e383ec3 100755 --- a/src/main/java/com/frameworkium/core/ui/js/JavascriptWait.java +++ b/src/main/java/com/frameworkium/core/ui/js/JavascriptWait.java @@ -11,41 +11,41 @@ */ public class JavascriptWait { - private final Wait wait; - private final JavascriptExecutor javascriptExecutor; - - public JavascriptWait( - JavascriptExecutor javascriptExecutor, Wait wait) { - this.wait = wait; - this.javascriptExecutor = javascriptExecutor; - } - - /** - * Default entry to {@link JavascriptWait}. - * The following actions are waited for: - *
    - *
  1. Document state to be ready
  2. - *
  3. If page is using Angular, it will detect and wait
  4. - *
- */ - public void waitForJavascriptEventsOnLoad() { - waitForDocumentReady(); - waitForAngular(); - } - - /** - * If a page is using a supported JS framework, it will wait until it's ready. - */ - public void waitForJavascriptFramework() { - waitForAngular(); - } - - private void waitForDocumentReady() { - wait.until(ExtraExpectedConditions.documentBodyReady()); - } - - private void waitForAngular() { - new NgWebDriver(javascriptExecutor).waitForAngularRequestsToFinish(); - } + private final Wait wait; + private final JavascriptExecutor javascriptExecutor; + + public JavascriptWait( + JavascriptExecutor javascriptExecutor, Wait wait) { + this.wait = wait; + this.javascriptExecutor = javascriptExecutor; + } + + /** + * Default entry to {@link JavascriptWait}. + * The following actions are waited for: + *
    + *
  1. Document state to be ready
  2. + *
  3. If page is using Angular, it will detect and wait
  4. + *
+ */ + public void waitForJavascriptEventsOnLoad() { + waitForDocumentReady(); + waitForAngular(); + } + + /** + * If a page is using a supported JS framework, it will wait until it's ready. + */ + public void waitForJavascriptFramework() { + waitForAngular(); + } + + private void waitForDocumentReady() { + wait.until(ExtraExpectedConditions.documentBodyReady()); + } + + private void waitForAngular() { + new NgWebDriver(javascriptExecutor).waitForAngularRequestsToFinish(); + } } diff --git a/src/main/java/com/frameworkium/core/ui/listeners/CaptureListener.java b/src/main/java/com/frameworkium/core/ui/listeners/CaptureListener.java index c8e1ff95..f7131f06 100644 --- a/src/main/java/com/frameworkium/core/ui/listeners/CaptureListener.java +++ b/src/main/java/com/frameworkium/core/ui/listeners/CaptureListener.java @@ -1,5 +1,7 @@ package com.frameworkium.core.ui.listeners; +import static org.apache.commons.lang3.StringUtils.abbreviate; + import com.frameworkium.core.ui.UITestLifecycle; import com.frameworkium.core.ui.browsers.UserAgent; import com.frameworkium.core.ui.capture.ElementHighlighter; @@ -7,203 +9,230 @@ import com.frameworkium.core.ui.capture.model.Command; import com.frameworkium.core.ui.pages.Visibility; import org.apache.commons.lang3.exception.ExceptionUtils; -import org.openqa.selenium.*; +import org.openqa.selenium.By; +import org.openqa.selenium.OutputType; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; import org.openqa.selenium.support.events.WebDriverEventListener; -import org.testng.*; - -import static org.apache.commons.lang3.StringUtils.abbreviate; +import org.testng.ITestContext; +import org.testng.ITestListener; +import org.testng.ITestResult; /** * Assumes {@link ScreenshotCapture#isRequired()} is true for WebDriver events. */ public class CaptureListener implements WebDriverEventListener, ITestListener { - private void takeScreenshotAndSend(Command command, WebDriver driver) { - UITestLifecycle.get().getCapture().takeAndSendScreenshot(command, driver); - } - - private void takeScreenshotAndSend(String action, WebDriver driver) { + private void takeScreenshotAndSend(Command command, WebDriver driver) { + UITestLifecycle.get().getCapture().takeAndSendScreenshot(command, driver); + } + + private void takeScreenshotAndSend(String action, WebDriver driver) { + Command command = new Command(action, "n/a", "n/a"); + takeScreenshotAndSend(command, driver); + } + + private void takeScreenshotAndSend(String action, WebDriver driver, Throwable thrw) { + + UITestLifecycle.get().getCapture().takeAndSendScreenshotWithError( + new Command(action, "n/a", "n/a"), + driver, + thrw.getMessage() + "\n" + ExceptionUtils.getStackTrace(thrw)); + } + + private void sendFinalScreenshot(ITestResult result, String action) { + if (ScreenshotCapture.isRequired() && isUITest()) { + Throwable thrw = result.getThrowable(); + WebDriver driver = UITestLifecycle.get().getWebDriver(); + if (null != thrw) { + takeScreenshotAndSend(action, driver, thrw); + } else { Command command = new Command(action, "n/a", "n/a"); takeScreenshotAndSend(command, driver); - } - - private void takeScreenshotAndSend(String action, WebDriver driver, Throwable thrw) { - - UITestLifecycle.get().getCapture().takeAndSendScreenshotWithError( - new Command(action, "n/a", "n/a"), - driver, - thrw.getMessage() + "\n" + ExceptionUtils.getStackTrace(thrw)); - } - - private void sendFinalScreenshot(ITestResult result, String action) { - if (ScreenshotCapture.isRequired() && isUITest()) { - Throwable thrw = result.getThrowable(); - WebDriver driver = UITestLifecycle.get().getWebDriver(); - if (null != thrw) { - takeScreenshotAndSend(action, driver, thrw); - } else { - Command command = new Command(action, "n/a", "n/a"); - takeScreenshotAndSend(command, driver); - } - } - } - - private boolean isUITest() { - return UITestLifecycle.get().isInitialised(); - } - - private void highlightElementOnClickAndSendScreenshot( - WebDriver driver, WebElement element) { - if (!ScreenshotCapture.isRequired()) { - return; - } - ElementHighlighter highlighter = new ElementHighlighter(driver); - highlighter.highlightElement(element); - Command command = new Command("click", element); - takeScreenshotAndSend(command, driver); - highlighter.unhighlightPrevious(); - } - - /* WebDriver events */ - @Override - public void beforeClickOn(WebElement element, WebDriver driver) { - highlightElementOnClickAndSendScreenshot(driver, element); - } - - @Override - public void afterChangeValueOf(WebElement element, WebDriver driver, CharSequence[] keysSent) { - takeScreenshotAndSend("change", driver); - } - - @Override - public void beforeNavigateBack(WebDriver driver) { - takeScreenshotAndSend("nav back", driver); - } - - @Override - public void beforeNavigateForward(WebDriver driver) { - takeScreenshotAndSend("nav forward", driver); - } - - @Override - public void beforeNavigateTo(String url, WebDriver driver) { - Command command = new Command("nav", "url", url); - takeScreenshotAndSend(command, driver); - } - - @Override - public void afterSwitchToWindow(String windowName, WebDriver driver) { - Command command = new Command("nav", "window", windowName); - takeScreenshotAndSend(command, driver); - } - - @Override - public void beforeScript(String script, WebDriver driver) { - // ignore scripts which are part of Frameworkium - if (!isFrameworkiumScript(script)) { - takeScreenshotAndSend( - new Command("script", "n/a", abbreviate(script, 42)), - driver); - } - } - - private boolean isFrameworkiumScript(String script) { - String waitForAngularRequestsPrefix = - "var callback = arguments[arguments.length - 1];\n"; - - return script.equals(UserAgent.SCRIPT) - || script.equals(Visibility.FORCE_VISIBLE_SCRIPT) - || script.startsWith(waitForAngularRequestsPrefix); - } - - /* Test end methods */ - - @Override - public void onTestSuccess(ITestResult result) { - sendFinalScreenshot(result, "pass"); - } - - @Override - public void onTestFailure(ITestResult result) { - sendFinalScreenshot(result, "fail"); - } - - @Override - public void onTestSkipped(ITestResult result) { - sendFinalScreenshot(result, "skip"); - } - - /* Methods we don't really want screenshots for. */ - - @Override - public void onException(Throwable thrw, WebDriver driver) {} - - @Override - public void beforeGetScreenshotAs(OutputType outputType) {} - - @Override - public void afterGetScreenshotAs(OutputType outputType, X x) {} - - @Override - public void beforeGetText(WebElement webElement, WebDriver webDriver) {} - - @Override - public void afterGetText(WebElement webElement, WebDriver webDriver, String s) {} - - @Override - public void afterClickOn(WebElement element, WebDriver driver) {} - - @Override - public void beforeChangeValueOf(WebElement element, WebDriver driver, CharSequence[] keysToSend) {} - - @Override - public void afterFindBy(By by, WebElement arg1, WebDriver arg2) {} - - @Override - public void afterNavigateBack(WebDriver driver) {} - - @Override - public void afterNavigateForward(WebDriver driver) {} - - @Override - public void beforeNavigateRefresh(WebDriver webDriver) {} - - @Override - public void afterNavigateRefresh(WebDriver webDriver) {} - - @Override - public void afterNavigateTo(String url, WebDriver driver) {} - - @Override - public void afterScript(String script, WebDriver driver) {} - - @Override - public void beforeSwitchToWindow(String windowName, WebDriver driver) {} - - @Override - public void beforeFindBy(By by, WebElement element, WebDriver arg2) {} - - @Override - public void beforeAlertAccept(WebDriver webDriver) {} - - @Override - public void afterAlertAccept(WebDriver webDriver) {} + } + } + } + + private boolean isUITest() { + return UITestLifecycle.get().isInitialised(); + } + + private void highlightElementOnClickAndSendScreenshot( + WebDriver driver, WebElement element) { + if (!ScreenshotCapture.isRequired()) { + return; + } + ElementHighlighter highlighter = new ElementHighlighter(driver); + highlighter.highlightElement(element); + Command command = new Command("click", element); + takeScreenshotAndSend(command, driver); + highlighter.unhighlightPrevious(); + } + + /* WebDriver events */ + @Override + public void beforeClickOn(WebElement element, WebDriver driver) { + highlightElementOnClickAndSendScreenshot(driver, element); + } + + @Override + public void afterChangeValueOf(WebElement element, WebDriver driver, CharSequence[] keysSent) { + takeScreenshotAndSend("change", driver); + } + + @Override + public void beforeNavigateBack(WebDriver driver) { + takeScreenshotAndSend("nav back", driver); + } + + @Override + public void beforeNavigateForward(WebDriver driver) { + takeScreenshotAndSend("nav forward", driver); + } + + @Override + public void beforeNavigateTo(String url, WebDriver driver) { + Command command = new Command("nav", "url", url); + takeScreenshotAndSend(command, driver); + } + + @Override + public void afterSwitchToWindow(String windowName, WebDriver driver) { + Command command = new Command("nav", "window", windowName); + takeScreenshotAndSend(command, driver); + } + + @Override + public void beforeScript(String script, WebDriver driver) { + // ignore scripts which are part of Frameworkium + if (!isFrameworkiumScript(script)) { + takeScreenshotAndSend( + new Command("script", "n/a", abbreviate(script, 42)), + driver); + } + } + + private boolean isFrameworkiumScript(String script) { + String waitForAngularRequestsPrefix = + "var callback = arguments[arguments.length - 1];\n"; + + return script.equals(UserAgent.SCRIPT) + || script.equals(Visibility.FORCE_VISIBLE_SCRIPT) + || script.startsWith(waitForAngularRequestsPrefix); + } + + /* Test end methods */ + + @Override + public void onTestSuccess(ITestResult result) { + sendFinalScreenshot(result, "pass"); + } + + @Override + public void onTestFailure(ITestResult result) { + sendFinalScreenshot(result, "fail"); + } + + @Override + public void onTestSkipped(ITestResult result) { + sendFinalScreenshot(result, "skip"); + } + + /* Methods we don't really want screenshots for. */ + + @Override + public void onException(Throwable thrw, WebDriver driver) { + } + + @Override + public void beforeGetScreenshotAs(OutputType outputType) { + } + + @Override + public void afterGetScreenshotAs(OutputType outputType, X x) { + } + + @Override + public void beforeGetText(WebElement webElement, WebDriver webDriver) { + } + + @Override + public void afterGetText(WebElement webElement, WebDriver webDriver, String s) { + } + + @Override + public void afterClickOn(WebElement element, WebDriver driver) { + } + + @Override + public void beforeChangeValueOf(WebElement element, WebDriver driver, CharSequence[] keysToSend) { + } + + @Override + public void afterFindBy(By by, WebElement arg1, WebDriver arg2) { + } + + @Override + public void afterNavigateBack(WebDriver driver) { + } + + @Override + public void afterNavigateForward(WebDriver driver) { + } + + @Override + public void beforeNavigateRefresh(WebDriver webDriver) { + } + + @Override + public void afterNavigateRefresh(WebDriver webDriver) { + } + + @Override + public void afterNavigateTo(String url, WebDriver driver) { + } + + @Override + public void afterScript(String script, WebDriver driver) { + } + + @Override + public void beforeSwitchToWindow(String windowName, WebDriver driver) { + } + + @Override + public void beforeFindBy(By by, WebElement element, WebDriver arg2) { + } + + @Override + public void beforeAlertAccept(WebDriver webDriver) { + } - @Override - public void beforeAlertDismiss(WebDriver webDriver) {} + @Override + public void afterAlertAccept(WebDriver webDriver) { + } - @Override - public void afterAlertDismiss(WebDriver webDriver) {} + @Override + public void beforeAlertDismiss(WebDriver webDriver) { + } - @Override - public void onTestStart(ITestResult result) {} + @Override + public void afterAlertDismiss(WebDriver webDriver) { + } - @Override - public void onTestFailedButWithinSuccessPercentage(ITestResult result) {} + @Override + public void onTestStart(ITestResult result) { + } + + @Override + public void onTestFailedButWithinSuccessPercentage(ITestResult result) { + } - @Override - public void onStart(ITestContext context) {} + @Override + public void onStart(ITestContext context) { + } - @Override - public void onFinish(ITestContext context) {} + @Override + public void onFinish(ITestContext context) { + } } diff --git a/src/main/java/com/frameworkium/core/ui/listeners/LoggingListener.java b/src/main/java/com/frameworkium/core/ui/listeners/LoggingListener.java index 2968c2bf..dd5ee0e5 100644 --- a/src/main/java/com/frameworkium/core/ui/listeners/LoggingListener.java +++ b/src/main/java/com/frameworkium/core/ui/listeners/LoggingListener.java @@ -1,163 +1,165 @@ package com.frameworkium.core.ui.listeners; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import org.apache.commons.lang3.StringUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.openqa.selenium.*; +import org.openqa.selenium.By; +import org.openqa.selenium.OutputType; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; import org.openqa.selenium.support.events.WebDriverEventListener; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - public class LoggingListener implements WebDriverEventListener { - private static final Logger logger = LogManager.getLogger(); - - private static String getLocatorFromElement(WebElement element) { - String str = element.toString(); - Pattern p = Pattern.compile("->\\s(.*)(?=\\])"); - Matcher m = p.matcher(str); - return m.find() && m.groupCount() > 0 - ? m.group(1) - : str; - } - - @Override - public void afterChangeValueOf(WebElement element, WebDriver driver, CharSequence[] keysSent) { - logger.debug(() -> "changed value of element with " + getLocatorFromElement(element)); - } - - @Override - public void afterClickOn(WebElement element, WebDriver driver) { - logger.debug(() -> "clicked element with " + getLocatorFromElement(element)); - } - - @Override - public void afterFindBy(By by, WebElement element, WebDriver driver) { - logger.debug("found element {}", by); - } - - @Override - public void afterNavigateBack(WebDriver driver) { - logger.debug("after back"); - } - - @Override - public void afterNavigateForward(WebDriver driver) { - logger.debug("after forward"); - } - - @Override - public void beforeNavigateRefresh(WebDriver webDriver) { - logger.debug("before Navigate Refresh"); - } - - @Override - public void afterNavigateRefresh(WebDriver webDriver) { - logger.debug("after Navigate Refresh"); - } - - @Override - public void afterNavigateTo(String url, WebDriver driver) { - logger.debug("navigated to {}", url); - } - - @Override - public void afterScript(String script, WebDriver driver) { - // Only log part of a long script - // We log more of script in beforeScript - logger.debug(() -> "ran script " + StringUtils.abbreviate(script, 128)); - } - - @Override - public void beforeSwitchToWindow(String windowName, WebDriver driver) { - logger.debug("before switch to window " + windowName); - } - - @Override - public void afterSwitchToWindow(String windowName, WebDriver driver) { - logger.debug("after switch to window " + windowName); - } - - @Override - public void beforeChangeValueOf(WebElement element, WebDriver driver, CharSequence[] keysToSend) { - logger.debug(() -> "change value of element with " + getLocatorFromElement(element)); - } - - @Override - public void beforeClickOn(WebElement element, WebDriver driver) { - logger.debug(() -> "click element with " + getLocatorFromElement(element)); - } - - @Override - public void beforeFindBy(By by, WebElement element, WebDriver driver) { - logger.debug("before find element by {}", by); - } - - @Override - public void beforeNavigateBack(WebDriver driver) { - logger.debug("before back"); - } - - @Override - public void beforeNavigateForward(WebDriver driver) { - logger.debug("before forward"); - } - - @Override - public void beforeNavigateTo(String url, WebDriver driver) { - logger.debug("navigate to " + url); - } - - @Override - public void beforeScript(String script, WebDriver driver) { - // Only log part of a long script - logger.debug("running script " + StringUtils.abbreviate(script, 512)); - } - - @Override - public void onException(Throwable thrw, WebDriver driver) { - // Lots of caught exceptions being logged here - logger.trace("Event listener onException().", thrw); - } - - @Override - public void beforeGetScreenshotAs(OutputType outputType) { - logger.trace("Before get screenshot as"); - } - - @Override - public void afterGetScreenshotAs(OutputType outputType, X x) { - logger.trace("After get screenshot as"); - } - - @Override - public void beforeGetText(WebElement webElement, WebDriver webDriver) { - logger.trace("Before get text"); - } - - @Override - public void afterGetText(WebElement webElement, WebDriver webDriver, String s) { - logger.trace("After get text"); - } - - @Override - public void beforeAlertAccept(WebDriver webDriver) { - logger.debug("before alert accept"); - } - - @Override - public void afterAlertAccept(WebDriver webDriver) { - logger.debug("after alert accept"); - } - - @Override - public void beforeAlertDismiss(WebDriver webDriver) { - logger.debug("before alert dismiss"); - } - - @Override - public void afterAlertDismiss(WebDriver webDriver) { - logger.debug("after alert accept"); - } + private static final Logger logger = LogManager.getLogger(); + + private static String getLocatorFromElement(WebElement element) { + String str = element.toString(); + Pattern p = Pattern.compile("->\\s(.*)(?=\\])"); + Matcher m = p.matcher(str); + return m.find() && m.groupCount() > 0 + ? m.group(1) + : str; + } + + @Override + public void afterChangeValueOf(WebElement element, WebDriver driver, CharSequence[] keysSent) { + logger.debug(() -> "changed value of element with " + getLocatorFromElement(element)); + } + + @Override + public void afterClickOn(WebElement element, WebDriver driver) { + logger.debug(() -> "clicked element with " + getLocatorFromElement(element)); + } + + @Override + public void afterFindBy(By by, WebElement element, WebDriver driver) { + logger.debug("found element {}", by); + } + + @Override + public void afterNavigateBack(WebDriver driver) { + logger.debug("after back"); + } + + @Override + public void afterNavigateForward(WebDriver driver) { + logger.debug("after forward"); + } + + @Override + public void beforeNavigateRefresh(WebDriver webDriver) { + logger.debug("before Navigate Refresh"); + } + + @Override + public void afterNavigateRefresh(WebDriver webDriver) { + logger.debug("after Navigate Refresh"); + } + + @Override + public void afterNavigateTo(String url, WebDriver driver) { + logger.debug("navigated to {}", url); + } + + @Override + public void afterScript(String script, WebDriver driver) { + // Only log part of a long script + // We log more of script in beforeScript + logger.debug(() -> "ran script " + StringUtils.abbreviate(script, 128)); + } + + @Override + public void beforeSwitchToWindow(String windowName, WebDriver driver) { + logger.debug("before switch to window " + windowName); + } + + @Override + public void afterSwitchToWindow(String windowName, WebDriver driver) { + logger.debug("after switch to window " + windowName); + } + + @Override + public void beforeChangeValueOf(WebElement element, WebDriver driver, CharSequence[] keysToSend) { + logger.debug(() -> "change value of element with " + getLocatorFromElement(element)); + } + + @Override + public void beforeClickOn(WebElement element, WebDriver driver) { + logger.debug(() -> "click element with " + getLocatorFromElement(element)); + } + + @Override + public void beforeFindBy(By by, WebElement element, WebDriver driver) { + logger.debug("before find element by {}", by); + } + + @Override + public void beforeNavigateBack(WebDriver driver) { + logger.debug("before back"); + } + + @Override + public void beforeNavigateForward(WebDriver driver) { + logger.debug("before forward"); + } + + @Override + public void beforeNavigateTo(String url, WebDriver driver) { + logger.debug("navigate to " + url); + } + + @Override + public void beforeScript(String script, WebDriver driver) { + // Only log part of a long script + logger.debug("running script " + StringUtils.abbreviate(script, 512)); + } + + @Override + public void onException(Throwable thrw, WebDriver driver) { + // Lots of caught exceptions being logged here + logger.trace("Event listener onException().", thrw); + } + + @Override + public void beforeGetScreenshotAs(OutputType outputType) { + logger.trace("Before get screenshot as"); + } + + @Override + public void afterGetScreenshotAs(OutputType outputType, X x) { + logger.trace("After get screenshot as"); + } + + @Override + public void beforeGetText(WebElement webElement, WebDriver webDriver) { + logger.trace("Before get text"); + } + + @Override + public void afterGetText(WebElement webElement, WebDriver webDriver, String s) { + logger.trace("After get text"); + } + + @Override + public void beforeAlertAccept(WebDriver webDriver) { + logger.debug("before alert accept"); + } + + @Override + public void afterAlertAccept(WebDriver webDriver) { + logger.debug("after alert accept"); + } + + @Override + public void beforeAlertDismiss(WebDriver webDriver) { + logger.debug("before alert dismiss"); + } + + @Override + public void afterAlertDismiss(WebDriver webDriver) { + logger.debug("after alert accept"); + } } diff --git a/src/main/java/com/frameworkium/core/ui/listeners/SauceLabsListener.java b/src/main/java/com/frameworkium/core/ui/listeners/SauceLabsListener.java index b4b791cd..07a4944e 100644 --- a/src/main/java/com/frameworkium/core/ui/listeners/SauceLabsListener.java +++ b/src/main/java/com/frameworkium/core/ui/listeners/SauceLabsListener.java @@ -1,64 +1,63 @@ package com.frameworkium.core.ui.listeners; +import static com.frameworkium.core.common.properties.Property.APP_PATH; + import com.frameworkium.core.ui.driver.Driver; import com.frameworkium.core.ui.driver.remotes.Sauce; import com.saucelabs.common.SauceOnDemandSessionIdProvider; import com.saucelabs.testng.SauceOnDemandTestListener; +import java.io.File; +import java.io.IOException; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.testng.ITestContext; import org.testng.ITestResult; -import java.io.File; -import java.io.IOException; - -import static com.frameworkium.core.common.properties.Property.APP_PATH; - public class SauceLabsListener extends SauceOnDemandTestListener { - private static final Logger logger = LogManager.getLogger(); + private static final Logger logger = LogManager.getLogger(); - private static final boolean IS_RUNNING_ON_SAUCE_LABS = Sauce.isDesired(); + private static final boolean IS_RUNNING_ON_SAUCE_LABS = Sauce.isDesired(); - @Override - public void onStart(ITestContext testContext) { - if (IS_RUNNING_ON_SAUCE_LABS) { - super.onStart(testContext); + @Override + public void onStart(ITestContext testContext) { + if (IS_RUNNING_ON_SAUCE_LABS) { + super.onStart(testContext); - if (Driver.isNative()) { - try { - Sauce.uploadFile(new File(APP_PATH.getValue())); - } catch (IOException ioe) { - logger.error("Error uploading file", ioe); - } - } + if (Driver.isNative()) { + try { + Sauce.uploadFile(new File(APP_PATH.getValue())); + } catch (IOException ioe) { + logger.error("Error uploading file", ioe); } + } } + } - @Override - public void onTestStart(ITestResult result) { - if (IS_RUNNING_ON_SAUCE_LABS) { - // TODO: thread safe? - Sauce.updateJobName( - (SauceOnDemandSessionIdProvider) result.getInstance(), - result.getTestClass().getRealClass().getSimpleName()); + @Override + public void onTestStart(ITestResult result) { + if (IS_RUNNING_ON_SAUCE_LABS) { + // TODO: thread safe? + Sauce.updateJobName( + (SauceOnDemandSessionIdProvider) result.getInstance(), + result.getTestClass().getRealClass().getSimpleName()); - super.onTestStart(result); - } + super.onTestStart(result); } + } - @Override - public void onTestFailure(ITestResult tr) { - if (IS_RUNNING_ON_SAUCE_LABS) { - super.onTestFailure(tr); - } + @Override + public void onTestFailure(ITestResult tr) { + if (IS_RUNNING_ON_SAUCE_LABS) { + super.onTestFailure(tr); } + } - @Override - public void onTestSuccess(ITestResult tr) { - if (IS_RUNNING_ON_SAUCE_LABS) { - super.onTestSuccess(tr); - } + @Override + public void onTestSuccess(ITestResult tr) { + if (IS_RUNNING_ON_SAUCE_LABS) { + super.onTestSuccess(tr); } + } } diff --git a/src/main/java/com/frameworkium/core/ui/listeners/ScreenshotListener.java b/src/main/java/com/frameworkium/core/ui/listeners/ScreenshotListener.java index 953c76c4..0ef65258 100644 --- a/src/main/java/com/frameworkium/core/ui/listeners/ScreenshotListener.java +++ b/src/main/java/com/frameworkium/core/ui/listeners/ScreenshotListener.java @@ -1,94 +1,97 @@ package com.frameworkium.core.ui.listeners; +import static com.frameworkium.core.common.properties.Property.BROWSER; +import static com.frameworkium.core.ui.driver.DriverSetup.Browser.ELECTRON; + import com.frameworkium.core.ui.UITestLifecycle; import com.frameworkium.core.ui.capture.ScreenshotCapture; import com.frameworkium.core.ui.driver.DriverSetup.Browser; import com.frameworkium.core.ui.tests.BaseUITest; import io.qameta.allure.Attachment; +import java.io.IOException; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.openqa.selenium.*; +import org.openqa.selenium.OutputType; +import org.openqa.selenium.TakesScreenshot; +import org.openqa.selenium.WebDriverException; import org.testng.ITestResult; import org.testng.TestListenerAdapter; -import java.io.IOException; -import java.io.OutputStream; -import java.nio.file.*; - -import static com.frameworkium.core.common.properties.Property.BROWSER; -import static com.frameworkium.core.ui.driver.DriverSetup.Browser.ELECTRON; - public class ScreenshotListener extends TestListenerAdapter { - private static final Logger logger = LogManager.getLogger(); - private final boolean captureEnabled = ScreenshotCapture.isRequired(); + private static final Logger logger = LogManager.getLogger(); + private final boolean captureEnabled = ScreenshotCapture.isRequired(); - @Override - public void onTestFailure(ITestResult failingTest) { - if (!captureEnabled && isScreenshotSupported(failingTest)) { - takeScreenshotAndSaveLocally(failingTest.getName()); - } + @Override + public void onTestFailure(ITestResult failingTest) { + if (!captureEnabled && isScreenshotSupported(failingTest)) { + takeScreenshotAndSaveLocally(failingTest.getName()); } + } - @Override - public void onTestSkipped(ITestResult skippedTest) { - if (!captureEnabled && isScreenshotSupported(skippedTest)) { - takeScreenshotAndSaveLocally(skippedTest.getName()); - } + @Override + public void onTestSkipped(ITestResult skippedTest) { + if (!captureEnabled && isScreenshotSupported(skippedTest)) { + takeScreenshotAndSaveLocally(skippedTest.getName()); } + } - private void takeScreenshotAndSaveLocally(String testName) { - takeScreenshotAndSaveLocally( - testName, (TakesScreenshot) UITestLifecycle.get().getWebDriver()); - } + private void takeScreenshotAndSaveLocally(String testName) { + takeScreenshotAndSaveLocally( + testName, (TakesScreenshot) UITestLifecycle.get().getWebDriver()); + } - private void takeScreenshotAndSaveLocally(String testName, TakesScreenshot driver) { - String screenshotDirectory = System.getProperty("screenshotDirectory"); - if (screenshotDirectory == null) { - screenshotDirectory = "screenshots"; - } - String fileName = String.format( - "%s_%s.png", - System.currentTimeMillis(), - testName); - Path screenshotPath = Paths.get(screenshotDirectory); - Path absolutePath = screenshotPath.resolve(fileName); - if (createScreenshotDirectory(screenshotPath)) { - writeScreenshotToFile(driver, absolutePath); - logger.info("Written screenshot to " + absolutePath); - } else { - logger.error("Unable to create " + screenshotPath); - } + private void takeScreenshotAndSaveLocally(String testName, TakesScreenshot driver) { + String screenshotDirectory = System.getProperty("screenshotDirectory"); + if (screenshotDirectory == null) { + screenshotDirectory = "screenshots"; } - - private boolean createScreenshotDirectory(Path screenshotDirectory) { - try { - Files.createDirectories(screenshotDirectory); - } catch (IOException e) { - logger.error("Error creating screenshot directory", e); - } - return Files.isDirectory(screenshotDirectory); + String fileName = String.format( + "%s_%s.png", + System.currentTimeMillis(), + testName); + Path screenshotPath = Paths.get(screenshotDirectory); + Path absolutePath = screenshotPath.resolve(fileName); + if (createScreenshotDirectory(screenshotPath)) { + writeScreenshotToFile(driver, absolutePath); + logger.info("Written screenshot to " + absolutePath); + } else { + logger.error("Unable to create " + screenshotPath); } + } - @Attachment(value = "Screenshot on failure", type = "image/png") - private byte[] writeScreenshotToFile(TakesScreenshot driver, Path screenshot) { - try (OutputStream screenshotStream = Files.newOutputStream(screenshot)) { - byte[] bytes = driver.getScreenshotAs(OutputType.BYTES); - screenshotStream.write(bytes); - screenshotStream.close(); - return bytes; - } catch (IOException e) { - logger.error("Unable to write " + screenshot, e); - } catch (WebDriverException e) { - logger.error("Unable to take screenshot.", e); - } - return null; + private boolean createScreenshotDirectory(Path screenshotDirectory) { + try { + Files.createDirectories(screenshotDirectory); + } catch (IOException e) { + logger.error("Error creating screenshot directory", e); } + return Files.isDirectory(screenshotDirectory); + } - private boolean isScreenshotSupported(ITestResult testResult) { - boolean isElectron = BROWSER.isSpecified() - && ELECTRON.equals(Browser.valueOf(BROWSER.getValue().toUpperCase())); - boolean isUITest = testResult.getInstance() instanceof BaseUITest; - return isUITest && !isElectron; + @Attachment(value = "Screenshot on failure", type = "image/png") + private byte[] writeScreenshotToFile(TakesScreenshot driver, Path screenshot) { + try (OutputStream screenshotStream = Files.newOutputStream(screenshot)) { + byte[] bytes = driver.getScreenshotAs(OutputType.BYTES); + screenshotStream.write(bytes); + screenshotStream.close(); + return bytes; + } catch (IOException e) { + logger.error("Unable to write " + screenshot, e); + } catch (WebDriverException e) { + logger.error("Unable to take screenshot.", e); } + return null; + } + + private boolean isScreenshotSupported(ITestResult testResult) { + boolean isElectron = BROWSER.isSpecified() + && ELECTRON.equals(Browser.valueOf(BROWSER.getValue().toUpperCase())); + boolean isUITest = testResult.getInstance() instanceof BaseUITest; + return isUITest && !isElectron; + } } diff --git a/src/main/java/com/frameworkium/core/ui/listeners/VideoListener.java b/src/main/java/com/frameworkium/core/ui/listeners/VideoListener.java index 5260053e..d69d0199 100755 --- a/src/main/java/com/frameworkium/core/ui/listeners/VideoListener.java +++ b/src/main/java/com/frameworkium/core/ui/listeners/VideoListener.java @@ -2,30 +2,32 @@ import com.frameworkium.core.ui.UITestLifecycle; import com.frameworkium.core.ui.video.VideoCapture; -import org.testng.*; +import org.testng.ITestContext; +import org.testng.ITestResult; +import org.testng.TestListenerAdapter; public class VideoListener extends TestListenerAdapter { - @Override - public void onTestStart(ITestResult iTestResult) { - if (VideoCapture.isRequired()) { - VideoCapture.saveTestSessionID( - iTestResult.getName(), - UITestLifecycle.get().getRemoteSessionId()); - } + @Override + public void onTestStart(ITestResult iTestResult) { + if (VideoCapture.isRequired()) { + VideoCapture.saveTestSessionID( + iTestResult.getName(), + UITestLifecycle.get().getRemoteSessionId()); } + } - @Override - public void onFinish(ITestContext iTestContext) { - if (VideoCapture.isRequired()) { - VideoCapture videoCapture = new VideoCapture(); - iTestContext - .getFailedTests() - .getAllResults() - .stream() - .map(ITestResult::getName) - .forEach(videoCapture::fetchAndSaveVideo); - } + @Override + public void onFinish(ITestContext iTestContext) { + if (VideoCapture.isRequired()) { + VideoCapture videoCapture = new VideoCapture(); + iTestContext + .getFailedTests() + .getAllResults() + .stream() + .map(ITestResult::getName) + .forEach(videoCapture::fetchAndSaveVideo); } + } } diff --git a/src/main/java/com/frameworkium/core/ui/pages/BasePage.java b/src/main/java/com/frameworkium/core/ui/pages/BasePage.java index e24fe61c..87ba29fe 100755 --- a/src/main/java/com/frameworkium/core/ui/pages/BasePage.java +++ b/src/main/java/com/frameworkium/core/ui/pages/BasePage.java @@ -8,232 +8,237 @@ import com.frameworkium.core.ui.capture.model.Command; import com.frameworkium.core.ui.driver.Driver; import com.frameworkium.core.ui.js.JavascriptWait; +import java.time.Duration; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.openqa.selenium.*; +import org.openqa.selenium.JavascriptExecutor; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; import org.openqa.selenium.support.ui.Wait; -import java.time.Duration; - public abstract class BasePage> { - protected final Logger logger = LogManager.getLogger(this); - - protected final WebDriver driver; - protected Wait wait; - private Visibility visibility; - private JavascriptWait javascriptWait; - - public BasePage() { - this(UITestLifecycle.get().getWebDriver(), UITestLifecycle.get().getWait()); - } - - /** - * Added to enable testing and, one day, remove coupling to BaseUITest. - */ - public BasePage(WebDriver driver, Wait wait) { - this.driver = driver; - this.wait = wait; - JavascriptExecutor javascriptExecutor = (JavascriptExecutor) driver; - this.visibility = new Visibility(wait, javascriptExecutor); - this.javascriptWait = new JavascriptWait(javascriptExecutor, wait); - } - - /** - * Get the current page object. Useful for e.g. - * myPage.get().then().doSomething(); - * - * @return the current page object - */ - @SuppressWarnings("unchecked") - public T then() { - return (T) this; - } - - /** - * Get current page object. Useful for e.g. - * myPage.get().then().with().aComponent().clickHome(); - * - * @return the current page object - */ - @SuppressWarnings("unchecked") - public T with() { - return (T) this; - } - - /** - * Get new instance of a PageObject of type T, see {@link BasePage#get()}. - * - * @param url the url to open before initialising - * @return PageObject of type T - * @see BasePage#get() - */ - public T get(String url) { - driver.get(url); - return get(); - } - - /** - * Get new instance of a PageObject of type T, - * see {@link BasePage#get(Duration)} for updating the timeout. - * - * @param url the url to open before initialising - * @param timeout the timeout for the new {@link Wait} for this page - * @return new instance of a PageObject of type T, see {@link BasePage#get()} - * @see BasePage#get() - */ - public T get(String url, Duration timeout) { - updatePageTimeout(timeout); - return get(url); - } - - /** - * Get new instance of a PageObject of type T. - * - * @param timeout the timeout, in seconds, for the new {@link Wait} for this page - * @return new instance of a PageObject of type T, see {@link BasePage#get()} - * @see BasePage#get() - */ - public T get(Duration timeout) { - updatePageTimeout(timeout); - return get(); - } - - /** - * Initialises the PageObject. - *
    - *
  • Initialises fields with lazy proxies
  • - *
  • Waits for Javascript events including document ready & JS frameworks (if applicable)
  • - *
  • Processes Frameworkium visibility annotations e.g. {@link Visible}
  • - *
  • Log page load to Allure and Capture
  • - *
- * - * @return the PageObject, of type T, populated with lazy proxies which are - * checked for visibility based upon appropriate Frameworkium annotations. - */ - @SuppressWarnings("unchecked") - public T get() { - - initPageObjectFields(); - - // Wait for Elements & JS - visibility.waitForAnnotatedElementVisibility(this); - if (!Driver.isNative()) { - javascriptWait.waitForJavascriptEventsOnLoad(); - } - - // Log - takePageLoadedScreenshotAndSendToCapture(); - logPageLoadToAllure(); - - return (T) this; - } - - /** - * Method to initialise the fields in the page object. - * Can be overridden where a custom implementation is desired. - */ - protected void initPageObjectFields() { - HtmlElementLoader.populatePageObject(this, driver); - } - - private void updatePageTimeout(Duration timeout) { - wait = UITestLifecycle.get().newWaitWithTimeout(timeout); - JavascriptExecutor jsExecutor = (JavascriptExecutor) driver; - visibility = new Visibility(wait, jsExecutor); - javascriptWait = new JavascriptWait(jsExecutor, wait); - } - - private void logPageLoadToAllure() { - try { - AllureLogger.logToAllure("Page '" + getClass().getName() + "' successfully loaded"); - } catch (Exception e) { - logger.warn("Error logging page load, but loaded successfully", e); - } - } - - private void takePageLoadedScreenshotAndSendToCapture() { - if (ScreenshotCapture.isRequired()) { - Command pageLoadCommand = new Command( - "load", "page", getSimplePageObjectName()); - UITestLifecycle.get().getCapture().takeAndSendScreenshot( - pageLoadCommand, driver); - } - } - - private String getSimplePageObjectName() { - String packageName = getClass().getPackage().getName(); - return packageName.substring(packageName.lastIndexOf('.') + 1) - + "." - + getClass().getSimpleName(); - } - - /** Get title of the web page. */ - public String getTitle() { - return driver.getTitle(); - } - - /** Get page source code of the current page. */ - public String getSource() { - return driver.getPageSource(); - } - - /** - * Waits for all JS framework requests to finish on page. - */ - protected void waitForJavascriptFrameworkToFinish() { - javascriptWait.waitForJavascriptFramework(); - } - - /** - * @param javascript the Javascript to execute on the current page - * @return One of Boolean, Long, String, List or WebElement. Or null. - * @see JavascriptExecutor#executeScript(String, Object...) - */ - protected Object executeJS(String javascript, Object... objects) { - Object returnObj = null; - JavascriptExecutor jsExecutor = (JavascriptExecutor) driver; - try { - returnObj = jsExecutor.executeScript(javascript, objects); - } catch (Exception e) { - logger.error("Javascript execution failed!"); - logger.debug("Failed Javascript:" + javascript, e); - } - return returnObj; - } - - /** - * Execute an asynchronous piece of JavaScript in the context of the - * currently selected frame or window. Unlike executing synchronous - * JavaScript, scripts executed with this method must explicitly signal they - * are finished by invoking the provided callback. This callback is always - * injected into the executed function as the last argument. - * - *

If executeAsyncScript throws an Exception it's caught and logged. - * - * @param javascript the JavaScript code to execute - * @return One of Boolean, Long, String, List, WebElement, or null. - * @see JavascriptExecutor#executeAsyncScript(String, Object...) - */ - protected Object executeAsyncJS(String javascript, Object... objects) { - Object returnObj = null; - try { - JavascriptExecutor jsExecutor = (JavascriptExecutor) driver; - returnObj = jsExecutor.executeAsyncScript(javascript, objects); - } catch (Exception e) { - logger.error("Async Javascript execution failed!"); - logger.debug("Failed Javascript:\n" + javascript, e); - } - return returnObj; - } - - /** - * Convenience method for {@link Visibility#forceVisible(WebElement)}. - * - * @param element the {@link WebElement} to "force visible" via Javascript. - */ - protected void forceVisible(WebElement element) { - visibility.forceVisible(element); - } + protected final Logger logger = LogManager.getLogger(this); + + protected final WebDriver driver; + protected Wait wait; + private Visibility visibility; + private JavascriptWait javascriptWait; + + public BasePage() { + this(UITestLifecycle.get().getWebDriver(), UITestLifecycle.get().getWait()); + } + + /** + * Added to enable testing and, one day, remove coupling to BaseUITest. + */ + public BasePage(WebDriver driver, Wait wait) { + this.driver = driver; + this.wait = wait; + JavascriptExecutor javascriptExecutor = (JavascriptExecutor) driver; + this.visibility = new Visibility(wait, javascriptExecutor); + this.javascriptWait = new JavascriptWait(javascriptExecutor, wait); + } + + /** + * Get the current page object. Useful for e.g. + * myPage.get().then().doSomething(); + * + * @return the current page object + */ + @SuppressWarnings("unchecked") + public T then() { + return (T) this; + } + + /** + * Get current page object. Useful for e.g. + * myPage.get().then().with().aComponent().clickHome(); + * + * @return the current page object + */ + @SuppressWarnings("unchecked") + public T with() { + return (T) this; + } + + /** + * Get new instance of a PageObject of type T, see {@link BasePage#get()}. + * + * @param url the url to open before initialising + * @return PageObject of type T + * @see BasePage#get() + */ + public T get(String url) { + driver.get(url); + return get(); + } + + /** + * Get new instance of a PageObject of type T, + * see {@link BasePage#get(Duration)} for updating the timeout. + * + * @param url the url to open before initialising + * @param timeout the timeout for the new {@link Wait} for this page + * @return new instance of a PageObject of type T, see {@link BasePage#get()} + * @see BasePage#get() + */ + public T get(String url, Duration timeout) { + updatePageTimeout(timeout); + return get(url); + } + + /** + * Get new instance of a PageObject of type T. + * + * @param timeout the timeout, in seconds, for the new {@link Wait} for this page + * @return new instance of a PageObject of type T, see {@link BasePage#get()} + * @see BasePage#get() + */ + public T get(Duration timeout) { + updatePageTimeout(timeout); + return get(); + } + + /** + * Initialises the PageObject. + *

    + *
  • Initialises fields with lazy proxies
  • + *
  • Waits for Javascript events including document ready & JS frameworks (if applicable)
  • + *
  • Processes Frameworkium visibility annotations e.g. {@link Visible}
  • + *
  • Log page load to Allure and Capture
  • + *
+ * + * @return the PageObject, of type T, populated with lazy proxies which are + * checked for visibility based upon appropriate Frameworkium annotations. + */ + @SuppressWarnings("unchecked") + public T get() { + + initPageObjectFields(); + + // Wait for Elements & JS + visibility.waitForAnnotatedElementVisibility(this); + if (!Driver.isNative()) { + javascriptWait.waitForJavascriptEventsOnLoad(); + } + + // Log + takePageLoadedScreenshotAndSendToCapture(); + logPageLoadToAllure(); + + return (T) this; + } + + /** + * Method to initialise the fields in the page object. + * Can be overridden where a custom implementation is desired. + */ + protected void initPageObjectFields() { + HtmlElementLoader.populatePageObject(this, driver); + } + + private void updatePageTimeout(Duration timeout) { + wait = UITestLifecycle.get().newWaitWithTimeout(timeout); + JavascriptExecutor jsExecutor = (JavascriptExecutor) driver; + visibility = new Visibility(wait, jsExecutor); + javascriptWait = new JavascriptWait(jsExecutor, wait); + } + + private void logPageLoadToAllure() { + try { + AllureLogger.logToAllure("Page '" + getClass().getName() + "' successfully loaded"); + } catch (Exception e) { + logger.warn("Error logging page load, but loaded successfully", e); + } + } + + private void takePageLoadedScreenshotAndSendToCapture() { + if (ScreenshotCapture.isRequired()) { + Command pageLoadCommand = new Command( + "load", "page", getSimplePageObjectName()); + UITestLifecycle.get().getCapture().takeAndSendScreenshot( + pageLoadCommand, driver); + } + } + + private String getSimplePageObjectName() { + String packageName = getClass().getPackage().getName(); + return packageName.substring(packageName.lastIndexOf('.') + 1) + + "." + + getClass().getSimpleName(); + } + + /** + * Get title of the web page. + */ + public String getTitle() { + return driver.getTitle(); + } + + /** + * Get page source code of the current page. + */ + public String getSource() { + return driver.getPageSource(); + } + + /** + * Waits for all JS framework requests to finish on page. + */ + protected void waitForJavascriptFrameworkToFinish() { + javascriptWait.waitForJavascriptFramework(); + } + + /** + * @param javascript the Javascript to execute on the current page + * @return One of Boolean, Long, String, List or WebElement. Or null. + * @see JavascriptExecutor#executeScript(String, Object...) + */ + protected Object executeJS(String javascript, Object... objects) { + Object returnObj = null; + JavascriptExecutor jsExecutor = (JavascriptExecutor) driver; + try { + returnObj = jsExecutor.executeScript(javascript, objects); + } catch (Exception e) { + logger.error("Javascript execution failed!"); + logger.debug("Failed Javascript:" + javascript, e); + } + return returnObj; + } + + /** + * Execute an asynchronous piece of JavaScript in the context of the + * currently selected frame or window. Unlike executing synchronous + * JavaScript, scripts executed with this method must explicitly signal they + * are finished by invoking the provided callback. This callback is always + * injected into the executed function as the last argument. + * + *

If executeAsyncScript throws an Exception it's caught and logged. + * + * @param javascript the JavaScript code to execute + * @return One of Boolean, Long, String, List, WebElement, or null. + * @see JavascriptExecutor#executeAsyncScript(String, Object...) + */ + protected Object executeAsyncJS(String javascript, Object... objects) { + Object returnObj = null; + try { + JavascriptExecutor jsExecutor = (JavascriptExecutor) driver; + returnObj = jsExecutor.executeAsyncScript(javascript, objects); + } catch (Exception e) { + logger.error("Async Javascript execution failed!"); + logger.debug("Failed Javascript:\n" + javascript, e); + } + return returnObj; + } + + /** + * Convenience method for {@link Visibility#forceVisible(WebElement)}. + * + * @param element the {@link WebElement} to "force visible" via Javascript. + */ + protected void forceVisible(WebElement element) { + visibility.forceVisible(element); + } } diff --git a/src/main/java/com/frameworkium/core/ui/pages/PageFactory.java b/src/main/java/com/frameworkium/core/ui/pages/PageFactory.java index f62a36f0..b069be23 100644 --- a/src/main/java/com/frameworkium/core/ui/pages/PageFactory.java +++ b/src/main/java/com/frameworkium/core/ui/pages/PageFactory.java @@ -1,43 +1,43 @@ package com.frameworkium.core.ui.pages; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - import java.lang.reflect.InvocationTargetException; import java.time.Duration; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; public class PageFactory { - private static final Logger logger = LogManager.getLogger(); - - protected PageFactory() {} - - public static > T newInstance(Class clazz) { - return instantiatePageObject(clazz).get(); - } - - public static > T newInstance( - Class clazz, Duration timeout) { - return instantiatePageObject(clazz).get(timeout); - } - - public static > T newInstance( - Class clazz, String url) { - return instantiatePageObject(clazz).get(url); - } - - public static > T newInstance( - Class clazz, String url, Duration timeout) { - return instantiatePageObject(clazz).get(url, timeout); - } - - private static > T instantiatePageObject(Class clazz) { - try { - return clazz.getDeclaredConstructor().newInstance(); - } catch (InstantiationException | IllegalAccessException - | NoSuchMethodException | InvocationTargetException e) { - logger.fatal("Unable to instantiate PageObject", e); - throw new IllegalStateException("Unable to instantiate PageObject", e); - } + private static final Logger logger = LogManager.getLogger(); + + protected PageFactory() { + } + + public static > T newInstance(Class clazz) { + return instantiatePageObject(clazz).get(); + } + + public static > T newInstance( + Class clazz, Duration timeout) { + return instantiatePageObject(clazz).get(timeout); + } + + public static > T newInstance( + Class clazz, String url) { + return instantiatePageObject(clazz).get(url); + } + + public static > T newInstance( + Class clazz, String url, Duration timeout) { + return instantiatePageObject(clazz).get(url, timeout); + } + + private static > T instantiatePageObject(Class clazz) { + try { + return clazz.getDeclaredConstructor().newInstance(); + } catch (InstantiationException | IllegalAccessException + | NoSuchMethodException | InvocationTargetException e) { + logger.fatal("Unable to instantiate PageObject", e); + throw new IllegalStateException("Unable to instantiate PageObject", e); } + } } diff --git a/src/main/java/com/frameworkium/core/ui/pages/Visibility.java b/src/main/java/com/frameworkium/core/ui/pages/Visibility.java index b67c6850..cdbf5f3f 100644 --- a/src/main/java/com/frameworkium/core/ui/pages/Visibility.java +++ b/src/main/java/com/frameworkium/core/ui/pages/Visibility.java @@ -1,218 +1,226 @@ package com.frameworkium.core.ui.pages; +import static com.frameworkium.core.htmlelements.utils.HtmlElementUtils.isHtmlElement; +import static com.frameworkium.core.htmlelements.utils.HtmlElementUtils.isHtmlElementList; +import static com.frameworkium.core.htmlelements.utils.HtmlElementUtils.isTypifiedElementList; +import static com.frameworkium.core.htmlelements.utils.HtmlElementUtils.isWebElementList; +import static org.openqa.selenium.support.ui.ExpectedConditions.visibilityOf; +import static org.openqa.selenium.support.ui.ExpectedConditions.visibilityOfAllElements; + import com.frameworkium.core.htmlelements.element.HtmlElement; import com.frameworkium.core.ui.ExtraExpectedConditions; -import com.frameworkium.core.ui.annotations.*; -import org.openqa.selenium.*; -import org.openqa.selenium.support.ui.Wait; - +import com.frameworkium.core.ui.annotations.ForceVisible; +import com.frameworkium.core.ui.annotations.Invisible; +import com.frameworkium.core.ui.annotations.Visible; import java.lang.annotation.Annotation; import java.lang.reflect.Field; import java.lang.reflect.Modifier; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import java.util.function.Consumer; import java.util.stream.Collectors; import java.util.stream.Stream; - -import static com.frameworkium.core.htmlelements.utils.HtmlElementUtils.*; -import static org.openqa.selenium.support.ui.ExpectedConditions.visibilityOf; -import static org.openqa.selenium.support.ui.ExpectedConditions.visibilityOfAllElements; +import org.openqa.selenium.JavascriptExecutor; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.support.ui.Wait; /** * All things Frameworkium-related dealing with PageObject element visibility. */ public final class Visibility { - public static final String FORCE_VISIBLE_SCRIPT = - "arguments[0].style.zindex='10000';" - + "arguments[0].style.visibility='visible';" - + "arguments[0].style.opacity='100';"; - - private static final List> VISIBILITY_ANNOTATION_CLASSES = - Arrays.asList(Visible.class, Invisible.class, ForceVisible.class); - - private final Wait wait; - private final JavascriptExecutor javascriptExecutor; - - public Visibility(Wait wait, JavascriptExecutor driver) { - this.wait = wait; - this.javascriptExecutor = driver; + public static final String FORCE_VISIBLE_SCRIPT = + "arguments[0].style.zindex='10000';" + + "arguments[0].style.visibility='visible';" + + "arguments[0].style.opacity='100';"; + + private static final List> VISIBILITY_ANNOTATION_CLASSES = + Arrays.asList(Visible.class, Invisible.class, ForceVisible.class); + + private final Wait wait; + private final JavascriptExecutor javascriptExecutor; + + public Visibility(Wait wait, JavascriptExecutor driver) { + this.wait = wait; + this.javascriptExecutor = driver; + } + + /** + * The main entry point for {@link BasePage}. + * For each Field: + *

    + *
  • Ensures either 0 or 1 Frameworkium Visibility annotations are present.
  • + *
  • Waits for the (in)visibility of elements based upon annotations.
  • + *
+ * + * @param pageObject the "page object" i.e. extends {@link BasePage} or {@link HtmlElement}. + */ + void waitForAnnotatedElementVisibility(Object pageObject) { + + getDeclaredFieldsIncludingSuperClasses(pageObject.getClass()) + .stream() + .filter(field -> !Modifier.isStatic(field.getModifiers())) + .filter(this::hasOnlyOneVisibilityAnnotation) + .forEach(field -> invokeWaitFunctionForField(field, pageObject)); + } + + /** + * Extracts all fields from a class (page object) and its super classes. + * This then behaves as expected if a page object extends something which + * itself extends HtmlElement or BasePage. + */ + private List getDeclaredFieldsIncludingSuperClasses(Class childClazz) { + final List fields = new ArrayList<>(); + + Class parentClazz = childClazz; + while (parentClazz != null + && parentClazz != BasePage.class + && parentClazz != HtmlElement.class) { + fields.addAll(Arrays.asList(parentClazz.getDeclaredFields())); + parentClazz = parentClazz.getSuperclass(); } - - /** - * The main entry point for {@link BasePage}. - * For each Field: - *
    - *
  • Ensures either 0 or 1 Frameworkium Visibility annotations are present.
  • - *
  • Waits for the (in)visibility of elements based upon annotations.
  • - *
- * - * @param pageObject the "page object" i.e. extends {@link BasePage} or {@link HtmlElement}. - */ - void waitForAnnotatedElementVisibility(Object pageObject) { - - getDeclaredFieldsIncludingSuperClasses(pageObject.getClass()) - .stream() - .filter(field -> !Modifier.isStatic(field.getModifiers())) - .filter(this::hasOnlyOneVisibilityAnnotation) - .forEach(field -> invokeWaitFunctionForField(field, pageObject)); + return fields; + } + + private boolean hasOnlyOneVisibilityAnnotation(Field field) { + long annotationCount = visibilityAnnotationsOf(field).count(); + + if (annotationCount > 1) { + throw new IllegalArgumentException(String.format( + "Field %s on %s has too many Visibility related Annotations", + field.getName(), + field.getDeclaringClass().getName())); + } else { + return annotationCount == 1; } - - /** - * Extracts all fields from a class (page object) and its super classes. - * This then behaves as expected if a page object extends something which - * itself extends HtmlElement or BasePage. - */ - private List getDeclaredFieldsIncludingSuperClasses(Class childClazz) { - final List fields = new ArrayList<>(); - - Class parentClazz = childClazz; - while (parentClazz != null - && parentClazz != BasePage.class - && parentClazz != HtmlElement.class) { - fields.addAll(Arrays.asList(parentClazz.getDeclaredFields())); - parentClazz = parentClazz.getSuperclass(); - } - return fields; + } + + private Stream> visibilityAnnotationsOf(Field field) { + return VISIBILITY_ANNOTATION_CLASSES.stream() + .filter(field::isAnnotationPresent); + } + + private void invokeWaitFunctionForField(Field field, Object pageObject) { + + Class visibilityAnnotationClass = + visibilityAnnotationsOf(field) + .findAny() + .orElseThrow(IllegalStateException::new); + + if (Visible.class.equals(visibilityAnnotationClass)) { + int toCheckCount = field.getAnnotation(Visible.class).checkAtMost(); + waitForFieldToBeVisible(pageObject, field, toCheckCount); + } else if (Invisible.class.equals(visibilityAnnotationClass)) { + int toCheckCount = field.getAnnotation(Invisible.class).checkAtMost(); + waitForFieldToBeInvisible(pageObject, field, toCheckCount); + } else if (ForceVisible.class.equals(visibilityAnnotationClass)) { + int toCheckCount = field.getAnnotation(ForceVisible.class).checkAtMost(); + forceThenWaitForFieldToBeVisible(pageObject, field, toCheckCount); } - - private boolean hasOnlyOneVisibilityAnnotation(Field field) { - long annotationCount = visibilityAnnotationsOf(field).count(); - - if (annotationCount > 1) { - throw new IllegalArgumentException(String.format( - "Field %s on %s has too many Visibility related Annotations", - field.getName(), - field.getDeclaringClass().getName())); - } else { - return annotationCount == 1; - } + } + + /** + * Checks for visibility of Fields with the {@link Visible} annotation. + * Will recurse inside {@link HtmlElement}s + * + * @param pageObject the pageObject + * @param field wait for visibility of the field + * @param checkAtMost maximum number of elements to check in a List + */ + @SuppressWarnings("unchecked") + private void waitForFieldToBeVisible(Object pageObject, Field field, int checkAtMost) { + + Object objectFromField = getObjectFromField(pageObject, field); + applyToWebElements( + field, + objectFromField, + we -> wait.until(visibilityOf(we)), + list -> wait.until(visibilityOfAllElements( + list.stream() + .limit(checkAtMost == -1 ? list.size() : checkAtMost) + .collect(Collectors.toList())))); + + // recurse inside HtmlElements + if (isHtmlElementList(field)) { + ((List) objectFromField) + .forEach(this::waitForAnnotatedElementVisibility); + } else if (isHtmlElement(field)) { + waitForAnnotatedElementVisibility(objectFromField); } - - private Stream> visibilityAnnotationsOf(Field field) { - return VISIBILITY_ANNOTATION_CLASSES.stream() - .filter(field::isAnnotationPresent); - } - - private void invokeWaitFunctionForField(Field field, Object pageObject) { - - Class visibilityAnnotationClass = - visibilityAnnotationsOf(field) - .findAny() - .orElseThrow(IllegalStateException::new); - - if (Visible.class.equals(visibilityAnnotationClass)) { - int toCheckCount = field.getAnnotation(Visible.class).checkAtMost(); - waitForFieldToBeVisible(pageObject, field, toCheckCount); - } else if (Invisible.class.equals(visibilityAnnotationClass)) { - int toCheckCount = field.getAnnotation(Invisible.class).checkAtMost(); - waitForFieldToBeInvisible(pageObject, field, toCheckCount); - } else if (ForceVisible.class.equals(visibilityAnnotationClass)) { - int toCheckCount = field.getAnnotation(ForceVisible.class).checkAtMost(); - forceThenWaitForFieldToBeVisible(pageObject, field, toCheckCount); - } - } - - /** - * Checks for visibility of Fields with the {@link Visible} annotation. - * Will recurse inside {@link HtmlElement}s - * - * @param pageObject the pageObject - * @param field wait for visibility of the field - * @param checkAtMost maximum number of elements to check in a List - */ - @SuppressWarnings("unchecked") - private void waitForFieldToBeVisible(Object pageObject, Field field, int checkAtMost) { - - Object objectFromField = getObjectFromField(pageObject, field); - applyToWebElements( - field, - objectFromField, - we -> wait.until(visibilityOf(we)), - list -> wait.until(visibilityOfAllElements( - list.stream() - .limit(checkAtMost == -1 ? list.size() : checkAtMost) - .collect(Collectors.toList())))); - - // recurse inside HtmlElements - if (isHtmlElementList(field)) { - ((List) objectFromField) - .forEach(this::waitForAnnotatedElementVisibility); - } else if (isHtmlElement(field)) { - waitForAnnotatedElementVisibility(objectFromField); - } - } - - /** - * Same as {@link Visibility#waitForFieldToBeVisible(Object, Field, int)} - * but for Invisibility. - */ - private void waitForFieldToBeInvisible(Object pageObject, Field field, int checkAtMost) { - - applyToWebElements( - field, - getObjectFromField(pageObject, field), - we -> wait.until(ExtraExpectedConditions.notPresentOrInvisible(we)), - list -> wait.until(ExtraExpectedConditions.notPresentOrInvisible( - list.stream() - .limit(checkAtMost == -1 ? list.size() : checkAtMost) - .collect(Collectors.toList())))); + } + + /** + * Same as {@link Visibility#waitForFieldToBeVisible(Object, Field, int)} + * but for Invisibility. + */ + private void waitForFieldToBeInvisible(Object pageObject, Field field, int checkAtMost) { + + applyToWebElements( + field, + getObjectFromField(pageObject, field), + we -> wait.until(ExtraExpectedConditions.notPresentOrInvisible(we)), + list -> wait.until(ExtraExpectedConditions.notPresentOrInvisible( + list.stream() + .limit(checkAtMost == -1 ? list.size() : checkAtMost) + .collect(Collectors.toList())))); + } + + /** + * Calls {@link Visibility#forceVisible(WebElement)} for each field + * annotated ith {@code @ForceVisible}, then calls + * {@link Visibility#waitForFieldToBeVisible(Object, Field, int)}. + */ + private void forceThenWaitForFieldToBeVisible(Object pageObject, Field field, int checkAtMost) { + + applyToWebElements( + field, + getObjectFromField(pageObject, field), + this::forceVisible, + list -> list.stream() + .limit(checkAtMost == -1 ? list.size() : checkAtMost) + .forEach(this::forceVisible)); + + waitForFieldToBeVisible(pageObject, field, checkAtMost); + } + + @SuppressWarnings("unchecked") + private void applyToWebElements( + Field field, + Object objectFromField, + Consumer fun, + Consumer> listFun) { + + if (isWebElementList(field) || isTypifiedElementList(field) || isHtmlElementList(field)) { + listFun.accept((List) objectFromField); + } else if (objectFromField instanceof WebElement) { + fun.accept((WebElement) objectFromField); + } else { + throw new IllegalArgumentException( + "Only elements of type HtmlElement, TypifiedElement, WebElement or " + + "Lists thereof are supported by Visibility annotations."); } - - /** - * Calls {@link Visibility#forceVisible(WebElement)} for each field - * annotated ith {@code @ForceVisible}, then calls - * {@link Visibility#waitForFieldToBeVisible(Object, Field, int)}. - */ - private void forceThenWaitForFieldToBeVisible(Object pageObject, Field field, int checkAtMost) { - - applyToWebElements( - field, - getObjectFromField(pageObject, field), - this::forceVisible, - list -> list.stream() - .limit(checkAtMost == -1 ? list.size() : checkAtMost) - .forEach(this::forceVisible)); - - waitForFieldToBeVisible(pageObject, field, checkAtMost); - } - - @SuppressWarnings("unchecked") - private void applyToWebElements( - Field field, - Object objectFromField, - Consumer fun, - Consumer> listFun) { - - if (isWebElementList(field) || isTypifiedElementList(field) || isHtmlElementList(field)) { - listFun.accept((List) objectFromField); - } else if (objectFromField instanceof WebElement) { - fun.accept((WebElement) objectFromField); - } else { - throw new IllegalArgumentException( - "Only elements of type HtmlElement, TypifiedElement, WebElement or " - + "Lists thereof are supported by Visibility annotations."); - } - } - - private Object getObjectFromField(Object pageObject, Field field) { - field.setAccessible(true); - try { - return field.get(pageObject); - } catch (IllegalAccessException e) { - throw new IllegalStateException(e); - } - } - - /** - * Executes JavaScript in an attempt to make the element visible - * e.g. for elements which are occluded but are required for interaction. - * To apply this to a list of WebElements, try the following code: - * {@code elements.forEach(visibility::forceVisible)} - * - * @param element the {@link WebElement} to make visible - */ - void forceVisible(WebElement element) { - javascriptExecutor.executeScript(FORCE_VISIBLE_SCRIPT, element); + } + + private Object getObjectFromField(Object pageObject, Field field) { + field.setAccessible(true); + try { + return field.get(pageObject); + } catch (IllegalAccessException e) { + throw new IllegalStateException(e); } + } + + /** + * Executes JavaScript in an attempt to make the element visible + * e.g. for elements which are occluded but are required for interaction. + * To apply this to a list of WebElements, try the following code: + * {@code elements.forEach(visibility::forceVisible)} + * + * @param element the {@link WebElement} to make visible + */ + void forceVisible(WebElement element) { + javascriptExecutor.executeScript(FORCE_VISIBLE_SCRIPT, element); + } } diff --git a/src/main/java/com/frameworkium/core/ui/proxy/SeleniumProxyFactory.java b/src/main/java/com/frameworkium/core/ui/proxy/SeleniumProxyFactory.java index ca9bb716..7e597786 100644 --- a/src/main/java/com/frameworkium/core/ui/proxy/SeleniumProxyFactory.java +++ b/src/main/java/com/frameworkium/core/ui/proxy/SeleniumProxyFactory.java @@ -1,71 +1,70 @@ package com.frameworkium.core.ui.proxy; +import java.net.URI; +import java.net.URISyntaxException; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.openqa.selenium.Proxy; -import java.net.URI; -import java.net.URISyntaxException; - public class SeleniumProxyFactory { - private static final Logger logger = LogManager.getLogger(); + private static final Logger logger = LogManager.getLogger(); - /** - * Valid inputs are system, autodetect, direct or http://{hostname}:{port} - * - *

This does not currently cope with PAC (Proxy auto-configuration from URL) - * - * @param proxyProperty the string representing the proxy required - * @return a Selenium {@link Proxy} representation of proxyProperty - */ - public static Proxy createProxy(String proxyProperty) { - Proxy proxy = new Proxy(); - switch (proxyProperty.toLowerCase()) { - case "system": - logger.debug("Using system proxy"); - proxy.setProxyType(Proxy.ProxyType.SYSTEM); - break; - case "autodetect": - logger.debug("Using autodetect proxy"); - proxy.setProxyType(Proxy.ProxyType.AUTODETECT); - break; - case "direct": - logger.debug("Using direct i.e. (no) proxy"); - proxy.setProxyType(Proxy.ProxyType.DIRECT); - break; - default: - return createManualProxy(proxyProperty); - } - return proxy; + /** + * Valid inputs are system, autodetect, direct or http://{hostname}:{port} + * + *

This does not currently cope with PAC (Proxy auto-configuration from URL) + * + * @param proxyProperty the string representing the proxy required + * @return a Selenium {@link Proxy} representation of proxyProperty + */ + public static Proxy createProxy(String proxyProperty) { + Proxy proxy = new Proxy(); + switch (proxyProperty.toLowerCase()) { + case "system": + logger.debug("Using system proxy"); + proxy.setProxyType(Proxy.ProxyType.SYSTEM); + break; + case "autodetect": + logger.debug("Using autodetect proxy"); + proxy.setProxyType(Proxy.ProxyType.AUTODETECT); + break; + case "direct": + logger.debug("Using direct i.e. (no) proxy"); + proxy.setProxyType(Proxy.ProxyType.DIRECT); + break; + default: + return createManualProxy(proxyProperty); } + return proxy; + } - private static Proxy createManualProxy(String proxyProperty) { - String proxyString = getProxyURL(proxyProperty); - logger.debug("All protocols to use proxy address: {}", proxyString); - Proxy proxy = new Proxy(); - proxy.setProxyType(Proxy.ProxyType.MANUAL) - .setHttpProxy(proxyString) - .setFtpProxy(proxyString) - .setSslProxy(proxyString); - return proxy; - } + private static Proxy createManualProxy(String proxyProperty) { + String proxyString = getProxyURL(proxyProperty); + logger.debug("All protocols to use proxy address: {}", proxyString); + Proxy proxy = new Proxy(); + proxy.setProxyType(Proxy.ProxyType.MANUAL) + .setHttpProxy(proxyString) + .setFtpProxy(proxyString) + .setSslProxy(proxyString); + return proxy; + } - private static String getProxyURL(String proxyProperty) { - try { - URI proxyURI = new URI(proxyProperty); - String host = proxyURI.getHost(); - int port = proxyURI.getPort(); - if (host == null || port == -1) { - throw new URISyntaxException( - proxyProperty, "invalid host or port"); - } - return String.format("%s:%d", host, port); - } catch (NullPointerException | URISyntaxException e) { - String message = "Invalid proxy specified, acceptable values are: " - + "system, autodetect, direct or http://{hostname}:{port}."; - logger.fatal(message); - throw new IllegalArgumentException(message, e); - } + private static String getProxyURL(String proxyProperty) { + try { + URI proxyURI = new URI(proxyProperty); + String host = proxyURI.getHost(); + int port = proxyURI.getPort(); + if (host == null || port == -1) { + throw new URISyntaxException( + proxyProperty, "invalid host or port"); + } + return String.format("%s:%d", host, port); + } catch (NullPointerException | URISyntaxException e) { + String message = "Invalid proxy specified, acceptable values are: " + + "system, autodetect, direct or http://{hostname}:{port}."; + logger.fatal(message); + throw new IllegalArgumentException(message, e); } + } } diff --git a/src/main/java/com/frameworkium/core/ui/tests/BaseUITest.java b/src/main/java/com/frameworkium/core/ui/tests/BaseUITest.java index e4cf0b20..290684bd 100755 --- a/src/main/java/com/frameworkium/core/ui/tests/BaseUITest.java +++ b/src/main/java/com/frameworkium/core/ui/tests/BaseUITest.java @@ -1,145 +1,162 @@ package com.frameworkium.core.ui.tests; -import com.frameworkium.core.common.listeners.*; +import com.frameworkium.core.common.listeners.MethodInterceptor; +import com.frameworkium.core.common.listeners.ResultLoggerListener; +import com.frameworkium.core.common.listeners.TestListener; import com.frameworkium.core.ui.UITestLifecycle; import com.frameworkium.core.ui.capture.ScreenshotCapture; import com.frameworkium.core.ui.driver.Driver; -import com.frameworkium.core.ui.listeners.*; +import com.frameworkium.core.ui.listeners.CaptureListener; +import com.frameworkium.core.ui.listeners.SauceLabsListener; +import com.frameworkium.core.ui.listeners.ScreenshotListener; +import com.frameworkium.core.ui.listeners.VideoListener; import com.saucelabs.common.SauceOnDemandAuthentication; import com.saucelabs.common.SauceOnDemandSessionIdProvider; import com.saucelabs.testng.SauceOnDemandAuthenticationProvider; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.openqa.selenium.*; -import org.openqa.selenium.support.ui.Wait; -import org.testng.annotations.*; - import java.lang.reflect.Method; import java.time.Duration; import java.util.Optional; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.openqa.selenium.NoSuchElementException; +import org.openqa.selenium.StaleElementReferenceException; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.support.ui.Wait; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.AfterSuite; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.BeforeSuite; +import org.testng.annotations.Listeners; +import org.testng.annotations.Test; @Listeners({ - CaptureListener.class, ScreenshotListener.class, MethodInterceptor.class, - SauceLabsListener.class, TestListener.class, ResultLoggerListener.class, - VideoListener.class}) + CaptureListener.class, ScreenshotListener.class, MethodInterceptor.class, + SauceLabsListener.class, TestListener.class, ResultLoggerListener.class, + VideoListener.class}) @Test(groups = "base-ui") public abstract class BaseUITest - implements SauceOnDemandSessionIdProvider, SauceOnDemandAuthenticationProvider { - - /** Logger for subclasses (logs with correct class i.e. not BaseUITest). */ - protected final Logger logger = LogManager.getLogger(this); - - /** - * Runs before the test suite to initialise a pool of drivers, if requested. - */ - @BeforeSuite(alwaysRun = true) - protected static void initialiseDriverPool() { - UITestLifecycle.get().beforeSuite(); - } - - /** - * Runs before each test method, it initialises the following: - *

    - *
  • {@link Driver} and {@link WebDriver}
  • - *
  • {@link Wait}
  • - *
  • {@link ScreenshotCapture}
  • - *
  • userAgent
  • - *
- */ - @BeforeMethod(alwaysRun = true) - protected void configureBrowserBeforeTest(Method testMethod) { - UITestLifecycle.get().beforeTestMethod(testMethod); - } - - /** Tears down the browser after the test method. */ - @AfterMethod(alwaysRun = true) - protected static void tearDownDriver() { - UITestLifecycle.get().afterTestMethod(); - } - - /** - *
    - *
  • Ensures each driver in the pool has {@code quit()} - *
  • Processes remaining screenshot backlog - *
  • Create Allure properties - *
- */ - @AfterSuite(alwaysRun = true) - protected static void afterTestSuiteCleanUp() { - UITestLifecycle.get().afterTestSuite(); - } - - /** - * Create a new {@link Wait} with ThreadLocal driver and default timeout. - * - * @deprecated use {@code UITestLifecycle.get().getWait()}. - */ - @Deprecated - public static Wait newDefaultWait() { - return UITestLifecycle.get().newDefaultWait(); - } - - /** - * Create a new {@link Wait} with timeout. - * - * @param timeout timeout {@link Duration} for the {@link Wait} - * @return a new {@link Wait} for the thread local driver and given timeout - * which also ignores {@link NoSuchElementException} and - * {@link StaleElementReferenceException} - * @deprecated use {@code UITestLifecycle.get().newWaitWithTimeout(Duration)}. - */ - @Deprecated - public static Wait newWaitWithTimeout(Duration timeout) { - return UITestLifecycle.get().newWaitWithTimeout(timeout); - } - - /** - * @return the {@link WebDriver} used by the current thread. - * @deprecated use {@code UITestLifecycle.get().getWebDriver()}. - */ - @Deprecated - public static WebDriver getWebDriver() { - return UITestLifecycle.get().getWebDriver(); - } - - /** - * @deprecated use {@code UITestLifecycle.get().getCapture()}. - */ - @Deprecated - public static ScreenshotCapture getCapture() { - return UITestLifecycle.get().getCapture(); - } - - /** - * @deprecated use {@code UITestLifecycle.get().getWait()}. - */ - @Deprecated - public static Wait getWait() { - return UITestLifecycle.get().getWait(); - } - - /** - * @return the user agent of the browser in the first UI test to run. - * @deprecated use {@code UITestLifecycle.get().getUserAgent()}. - */ - @Deprecated - public static Optional getUserAgent() { - return UITestLifecycle.get().getUserAgent(); - } - - /** @deprecated use {@code UITestLifecycle.get().getRemoteSessionId()}. */ - @Deprecated - public static String getThreadSessionId() { - return UITestLifecycle.get().getRemoteSessionId(); - } - - @Override - public String getSessionId() { - return UITestLifecycle.get().getRemoteSessionId(); - } - - @Override - public SauceOnDemandAuthentication getAuthentication() { - return new SauceOnDemandAuthentication(); - } + implements SauceOnDemandSessionIdProvider, SauceOnDemandAuthenticationProvider { + + /** + * Logger for subclasses (logs with correct class i.e. not BaseUITest). + */ + protected final Logger logger = LogManager.getLogger(this); + + /** + * Runs before the test suite to initialise a pool of drivers, if requested. + */ + @BeforeSuite(alwaysRun = true) + protected static void initialiseDriverPool() { + UITestLifecycle.get().beforeSuite(); + } + + /** + * Tears down the browser after the test method. + */ + @AfterMethod(alwaysRun = true) + protected static void tearDownDriver() { + UITestLifecycle.get().afterTestMethod(); + } + + /** + *
    + *
  • Ensures each driver in the pool has {@code quit()} + *
  • Processes remaining screenshot backlog + *
  • Create Allure properties + *
+ */ + @AfterSuite(alwaysRun = true) + protected static void afterTestSuiteCleanUp() { + UITestLifecycle.get().afterTestSuite(); + } + + /** + * Create a new {@link Wait} with ThreadLocal driver and default timeout. + * + * @deprecated use {@code UITestLifecycle.get().getWait()}. + */ + @Deprecated + public static Wait newDefaultWait() { + return UITestLifecycle.get().newDefaultWait(); + } + + /** + * Create a new {@link Wait} with timeout. + * + * @param timeout timeout {@link Duration} for the {@link Wait} + * @return a new {@link Wait} for the thread local driver and given timeout + * which also ignores {@link NoSuchElementException} and + * {@link StaleElementReferenceException} + * @deprecated use {@code UITestLifecycle.get().newWaitWithTimeout(Duration)}. + */ + @Deprecated + public static Wait newWaitWithTimeout(Duration timeout) { + return UITestLifecycle.get().newWaitWithTimeout(timeout); + } + + /** + * @return the {@link WebDriver} used by the current thread. + * @deprecated use {@code UITestLifecycle.get().getWebDriver()}. + */ + @Deprecated + public static WebDriver getWebDriver() { + return UITestLifecycle.get().getWebDriver(); + } + + /** + * @deprecated use {@code UITestLifecycle.get().getCapture()}. + */ + @Deprecated + public static ScreenshotCapture getCapture() { + return UITestLifecycle.get().getCapture(); + } + + /** + * @deprecated use {@code UITestLifecycle.get().getWait()}. + */ + @Deprecated + public static Wait getWait() { + return UITestLifecycle.get().getWait(); + } + + /** + * @return the user agent of the browser in the first UI test to run. + * @deprecated use {@code UITestLifecycle.get().getUserAgent()}. + */ + @Deprecated + public static Optional getUserAgent() { + return UITestLifecycle.get().getUserAgent(); + } + + /** + * @deprecated use {@code UITestLifecycle.get().getRemoteSessionId()}. + */ + @Deprecated + public static String getThreadSessionId() { + return UITestLifecycle.get().getRemoteSessionId(); + } + + /** + * Runs before each test method, it initialises the following: + *
    + *
  • {@link Driver} and {@link WebDriver}
  • + *
  • {@link Wait}
  • + *
  • {@link ScreenshotCapture}
  • + *
  • userAgent
  • + *
+ */ + @BeforeMethod(alwaysRun = true) + protected void configureBrowserBeforeTest(Method testMethod) { + UITestLifecycle.get().beforeTestMethod(testMethod); + } + + @Override + public String getSessionId() { + return UITestLifecycle.get().getRemoteSessionId(); + } + + @Override + public SauceOnDemandAuthentication getAuthentication() { + return new SauceOnDemandAuthentication(); + } } diff --git a/src/main/java/com/frameworkium/core/ui/video/UrlFetcher.java b/src/main/java/com/frameworkium/core/ui/video/UrlFetcher.java index 404f1c3b..2be07776 100644 --- a/src/main/java/com/frameworkium/core/ui/video/UrlFetcher.java +++ b/src/main/java/com/frameworkium/core/ui/video/UrlFetcher.java @@ -2,39 +2,38 @@ import io.restassured.RestAssured; import io.restassured.response.Response; -import org.apache.http.HttpStatus; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - import java.net.URL; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import org.apache.http.HttpStatus; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; public class UrlFetcher { - private static final Logger logger = LogManager.getLogger(); + private static final Logger logger = LogManager.getLogger(); - /** - * @param url the url to GET - * @param maxTries max number of tries to GET url - * @return the bytes from the downloaded URL - * @throws TimeoutException if download fails and max tries have been exceeded - */ - public byte[] fetchWithRetry(URL url, int maxTries) throws TimeoutException { - logger.debug("Downloading: " + url); - for (int i = 0; i < maxTries; i++) { - Response response = RestAssured.get(url); - if (response.getStatusCode() == HttpStatus.SC_OK) { - return response.asByteArray(); - } - logger.debug("Retrying download: " + url); + /** + * @param url the url to GET + * @param maxTries max number of tries to GET url + * @return the bytes from the downloaded URL + * @throws TimeoutException if download fails and max tries have been exceeded + */ + public byte[] fetchWithRetry(URL url, int maxTries) throws TimeoutException { + logger.debug("Downloading: " + url); + for (int i = 0; i < maxTries; i++) { + Response response = RestAssured.get(url); + if (response.getStatusCode() == HttpStatus.SC_OK) { + return response.asByteArray(); + } + logger.debug("Retrying download: " + url); - try { - TimeUnit.SECONDS.sleep(2); - } catch (InterruptedException e) { - throw new IllegalStateException(e); - } - } - throw new TimeoutException(); + try { + TimeUnit.SECONDS.sleep(2); + } catch (InterruptedException e) { + throw new IllegalStateException(e); + } } + throw new TimeoutException(); + } } diff --git a/src/main/java/com/frameworkium/core/ui/video/VideoCapture.java b/src/main/java/com/frameworkium/core/ui/video/VideoCapture.java index 3e796026..1fbed0cc 100755 --- a/src/main/java/com/frameworkium/core/ui/video/VideoCapture.java +++ b/src/main/java/com/frameworkium/core/ui/video/VideoCapture.java @@ -1,90 +1,93 @@ package com.frameworkium.core.ui.video; -import io.qameta.allure.Attachment; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; +import static com.frameworkium.core.common.properties.Property.VIDEO_CAPTURE_URL; +import io.qameta.allure.Attachment; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; -import java.nio.file.*; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeoutException; - -import static com.frameworkium.core.common.properties.Property.VIDEO_CAPTURE_URL; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; public class VideoCapture { - private static final Path VIDEO_FOLDER = Paths.get("capturedVideo"); + private static final Path VIDEO_FOLDER = Paths.get("capturedVideo"); - private static final Logger logger = LogManager.getLogger(); + private static final Logger logger = LogManager.getLogger(); - private static Map testSessionMap = new ConcurrentHashMap<>(); + private static Map testSessionMap = new ConcurrentHashMap<>(); - private String videoCaptureUrl; - private UrlFetcher urlFetcher; + private String videoCaptureUrl; + private UrlFetcher urlFetcher; - public VideoCapture() { - videoCaptureUrl = VIDEO_CAPTURE_URL.getValue(); - urlFetcher = new UrlFetcher(); - } - - public VideoCapture(String videoCaptureUrl, UrlFetcher urlFetcher) { - this.videoCaptureUrl = videoCaptureUrl; - this.urlFetcher = urlFetcher; - } + public VideoCapture() { + videoCaptureUrl = VIDEO_CAPTURE_URL.getValue(); + urlFetcher = new UrlFetcher(); + } - public static boolean isRequired() { - return VIDEO_CAPTURE_URL.isSpecified(); - } + public VideoCapture(String videoCaptureUrl, UrlFetcher urlFetcher) { + this.videoCaptureUrl = videoCaptureUrl; + this.urlFetcher = urlFetcher; + } - public static void saveTestSessionID(String testName, String sessionId) { - testSessionMap.put(testName, sessionId); - } + public static boolean isRequired() { + return VIDEO_CAPTURE_URL.isSpecified(); + } - /** Fetch video from remote server and save to video folder. */ - public void fetchAndSaveVideo(String testName) { - String sessionId = testSessionMap.get(testName); - URL videoCaptureURL = getVideoCaptureURL(sessionId); - byte[] rawVideo = getVideo(videoCaptureURL); + public static void saveTestSessionID(String testName, String sessionId) { + testSessionMap.put(testName, sessionId); + } - if (rawVideo != null) { - String fileName = getFileName(testName, sessionId, videoCaptureURL.getFile()); - saveVideo(fileName, rawVideo); - } - } + /** + * Fetch video from remote server and save to video folder. + */ + public void fetchAndSaveVideo(String testName) { + String sessionId = testSessionMap.get(testName); + URL videoCaptureURL = getVideoCaptureURL(sessionId); + byte[] rawVideo = getVideo(videoCaptureURL); - private URL getVideoCaptureURL(String sessionId) { - try { - return new URL(String.format(videoCaptureUrl, sessionId)); - } catch (MalformedURLException e) { - throw new IllegalArgumentException("Video Capture URL provided was invalid", e); - } + if (rawVideo != null) { + String fileName = getFileName(testName, sessionId, videoCaptureURL.getFile()); + saveVideo(fileName, rawVideo); } + } - @Attachment(value = "Video on Failure", type = "video/mp4") - private byte[] getVideo(URL videoCaptureURL) { - try { - return urlFetcher.fetchWithRetry(videoCaptureURL, 4); - } catch (TimeoutException e) { - logger.error("Failed fetching URL {}.", videoCaptureURL); - return null; - } + private URL getVideoCaptureURL(String sessionId) { + try { + return new URL(String.format(videoCaptureUrl, sessionId)); + } catch (MalformedURLException e) { + throw new IllegalArgumentException("Video Capture URL provided was invalid", e); } - - private String getFileName(String testName, String sessionId, String fileFromUrl) { - String fileExt = fileFromUrl.substring(fileFromUrl.lastIndexOf('.') + 1); - return String.format("%s-%s.%s", testName, sessionId, fileExt); + } + + @Attachment(value = "Video on Failure", type = "video/mp4") + private byte[] getVideo(URL videoCaptureURL) { + try { + return urlFetcher.fetchWithRetry(videoCaptureURL, 4); + } catch (TimeoutException e) { + logger.error("Failed fetching URL {}.", videoCaptureURL); + return null; } - - private void saveVideo(String fileName, byte[] rawVideo) { - try { - Files.createDirectories(VIDEO_FOLDER); - Files.write(VIDEO_FOLDER.resolve(fileName), rawVideo); - logger.info("Captured video: {}", fileName); - } catch (IOException e) { - logger.error("Failed to save " + fileName, e); - } + } + + private String getFileName(String testName, String sessionId, String fileFromUrl) { + String fileExt = fileFromUrl.substring(fileFromUrl.lastIndexOf('.') + 1); + return String.format("%s-%s.%s", testName, sessionId, fileExt); + } + + private void saveVideo(String fileName, byte[] rawVideo) { + try { + Files.createDirectories(VIDEO_FOLDER); + Files.write(VIDEO_FOLDER.resolve(fileName), rawVideo); + logger.info("Captured video: {}", fileName); + } catch (IOException e) { + logger.error("Failed to save " + fileName, e); } + } }