diff --git a/.gitignore b/.gitignore index b3db729c..094fbbac 100644 --- a/.gitignore +++ b/.gitignore @@ -13,4 +13,5 @@ **/pom.xml.versionsBackup **/test-results/ **/target -**/secret.txt \ No newline at end of file +**/secret.txt +**/.flattened-*.xml diff --git a/pom.xml b/pom.xml index c1ff1937..2f666518 100644 --- a/pom.xml +++ b/pom.xml @@ -1,4 +1,6 @@ - + 4.0.0 com.qmetry @@ -7,7 +9,8 @@ pom qaf-parent https://github.com/qmetry/qaf - Functional test automation framework for web, mobile-web, mobile native and web-service + Functional test automation framework for web, mobile-web, + mobile native and web-service MIT License @@ -42,8 +45,10 @@ 1.8 1.8 4.0.0-SNAPSHOT + ${revision} 4.0.0 1.9.5 + 5.0.0 true @@ -55,208 +60,39 @@ qaf-playwright qaf-tools qaf + qaf-support + qaf-support-ws - - org.hamcrest - hamcrest-core - 1.3 - compile - - - org.hamcrest - hamcrest-library - 1.3 - compile - - - - com.sun.jersey - jersey-client - 1.19 - compile - - - com.sun.jersey - jersey-core - 1.19 - compile - - - com.sun.jersey.contribs - jersey-multipart - 1.19 - compile - - - com.sun.jersey.contribs - jersey-apache-client - 1.17.1 - compile - - - org.javassist - javassist - 3.18.2-GA - provided - - - org.reflections - reflections - 0.9.9 - provided - - - sshtools - j2ssh-core - 0.2.9 - provided - - - org.aspectj - aspectjrt - ${aspectj.version} - compile - - - org.aspectj - aspectjweaver - ${aspectj.version} - compile - - - org.aspectj - aspectjtools - ${aspectj.version} - compile - - - javax.xml.bind - jaxb-api - 2.3.1 - test - - - - commons-codec - commons-codec - 1.8 - compile - - - commons-configuration - commons-configuration - 1.7 - compile - - - commons-io - commons-io - 2.11.0 - compile - - - com.google.code.gson - gson - 2.9.0 - compile - - - com.google.guava - guava - 32.1.2-jre - compile - - - com.google.inject - guice - 3.0 - compile - - - io.github.lukehutch - fast-classpath-scanner - 2.0.6 - provided - - - velocity - velocity-dep - 1.4 - compile - - - org.codehaus.groovy - groovy-all - 2.1.9 - provided - - - org.json - json - 20231013 - compile - - - javax.mail - mail - 1.4.7 - true - - - org.apache.commons - commons-jexl3 - 3.2.1 - compile - - - org.apache.httpcomponents.core5 - httpcore5 - 5.2.1 - compile - - - com.sun.mail - jakarta.mail - 2.0.1 - compile - - - org.apache.logging.log4j - log4j-api - 2.20.0 - true - - - org.apache.commons - commons-compress - 1.25.0 - compile - - - org.seleniumhq.selenium - selenium-api - ${selenium.version} - compile - - - org.seleniumhq.selenium - selenium-leg-rc - ${selenium.version} - true - - - * - * - - - + org.apache.logging.log4j + log4j-api + 2.20.0 + true + + + org.aspectj + aspectjrt + ${aspectj.version} + compile + + + org.aspectj + aspectjweaver + ${aspectj.version} + compile + + + org.aspectj + aspectjtools + ${aspectj.version} + compile + org.testng testng 6.10 - compile + test @@ -266,6 +102,13 @@ build-helper-maven-plugin 1.5 + + initialize + parse-version + + parse-version + + add-test-source process-resources @@ -289,13 +132,10 @@ */test/* - org.apache.maven.plugins maven-failsafe-plugin 3.2.5 - - ${skip.it} @@ -312,20 +152,6 @@ - org.codehaus.mojo flatten-maven-plugin @@ -354,14 +180,13 @@ org.apache.maven.plugins maven-jar-plugin - 3.3.0 + 3.4.2 true - Infostretch Corp. ${java.version} ${os.name} @@ -379,6 +204,41 @@ + + org.apache.maven.plugins + maven-source-plugin + 3.2.1 + + + attach-sources + verify + + jar-no-fork + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 3.11.1 + + + attach-javadocs + deploy + + jar + + + UTF-8 + + none + + + + diff --git a/qaf-core/pom.xml b/qaf-core/pom.xml index 73df1f3d..335cee7d 100644 --- a/qaf-core/pom.xml +++ b/qaf-core/pom.xml @@ -1,4 +1,6 @@ - + 4.0.0 com.qmetry @@ -6,7 +8,8 @@ ${revision} qaf-core - Functional test automation framework for web, mobile-web, mobile native and web-service + Functional test automation framework for web, mobile-web, + mobile native and web-service core @@ -14,10 +17,138 @@ + + org.hamcrest + hamcrest-core + 1.3 + compile + + + org.hamcrest + hamcrest-library + 1.3 + compile + + + org.javassist + javassist + 3.18.2-GA + provided + + + org.reflections + reflections + 0.9.9 + provided + + + sshtools + j2ssh-core + 0.2.9 + provided + + + commons-codec + commons-codec + 1.8 + compile + + + commons-configuration + commons-configuration + 1.7 + compile + + + commons-io + commons-io + 2.11.0 + compile + + + com.google.code.gson + gson + 2.9.0 + compile + + + com.google.guava + guava + 32.1.2-jre + compile + + + com.google.inject + guice + 3.0 + compile + + + io.github.lukehutch + fast-classpath-scanner + 2.0.6 + provided + + + velocity + velocity-dep + 1.4 + compile + + + org.codehaus.groovy + groovy-all + 2.1.9 + provided + + + org.json + json + 20231013 + compile + + + javax.mail + mail + 1.4.7 + true + + + org.apache.commons + commons-jexl3 + 3.2.1 + compile + + + org.apache.httpcomponents.core5 + httpcore5 + 5.2.1 + compile + + + com.sun.mail + jakarta.mail + 2.0.1 + compile + + + org.apache.commons + commons-compress + 1.25.0 + compile + + + org.seleniumhq.selenium + selenium-api + ${selenium.version} + true + + javax.xml.bind jaxb-api - 2.3.0 + 2.3.1 + test com.sun.xml.bind @@ -32,26 +163,23 @@ org.apache.poi poi - 5.0.0 - compile + ${poi.version} org.apache.poi poi-ooxml-lite - 5.0.0 - compile + ${poi.version} org.apache.poi poi-ooxml - 5.0.0 - compile - - - * - * - - + ${poi.version} + + + org.testng + testng + 6.10 + true \ No newline at end of file diff --git a/qaf-core/src/main/java/com/qmetry/qaf/automation/core/AutomationError.java b/qaf-core/src/main/java/com/qmetry/qaf/automation/core/AutomationError.java index 3f6ccda6..f9cea1ad 100644 --- a/qaf-core/src/main/java/com/qmetry/qaf/automation/core/AutomationError.java +++ b/qaf-core/src/main/java/com/qmetry/qaf/automation/core/AutomationError.java @@ -21,7 +21,7 @@ ******************************************************************************/ package com.qmetry.qaf.automation.core; -import org.testng.SkipException; +//import org.testng.SkipException; /** * To indicate automation error,not an AUT failure so that the test case can be @@ -29,7 +29,7 @@ * * @author chirag */ -public class AutomationError extends SkipException { +public class AutomationError extends SkipTestException { /** * */ diff --git a/qaf-core/src/main/java/com/qmetry/qaf/automation/core/QAFTestBase.java b/qaf-core/src/main/java/com/qmetry/qaf/automation/core/QAFTestBase.java index 77dba97e..459d20cc 100644 --- a/qaf-core/src/main/java/com/qmetry/qaf/automation/core/QAFTestBase.java +++ b/qaf-core/src/main/java/com/qmetry/qaf/automation/core/QAFTestBase.java @@ -39,6 +39,7 @@ import com.qmetry.qaf.automation.ui.UiDriver; import com.qmetry.qaf.automation.ui.util.DynamicWait; import com.qmetry.qaf.automation.ui.util.ExpectedCondition; +import com.qmetry.qaf.automation.util.ClassUtil; import com.qmetry.qaf.automation.util.FileUtil; import com.qmetry.qaf.automation.util.PropertyUtil; import com.qmetry.qaf.automation.util.StringMatcher; @@ -406,14 +407,16 @@ public void addAssertionLog(String msg, MessageTypes type) { public PropertyUtil getContext() { try { - ITestResult tr = Reporter.getCurrentTestResult(); - if (null != tr) { - PropertyUtil contextFromTr = (PropertyUtil) Reporter.getCurrentTestResult().getAttribute(CONTEXT); - if (null == contextFromTr) { - Reporter.getCurrentTestResult().setAttribute(CONTEXT, context); - return context; + if(ClassUtil.isPresent("org.testng.ITestResult")){ + org.testng.ITestResult tr = org.testng.Reporter.getCurrentTestResult(); + if (null != tr) { + PropertyUtil contextFromTr = (PropertyUtil) org.testng.Reporter.getCurrentTestResult().getAttribute(CONTEXT); + if (null == contextFromTr) { + org.testng.Reporter.getCurrentTestResult().setAttribute(CONTEXT, context); + return context; + } + return contextFromTr; } - return contextFromTr; } } catch (Exception e) { // ignore - none TestNG implementation diff --git a/qaf-core/src/main/java/com/qmetry/qaf/automation/core/SkipTestException.java b/qaf-core/src/main/java/com/qmetry/qaf/automation/core/SkipTestException.java new file mode 100644 index 00000000..f9974e66 --- /dev/null +++ b/qaf-core/src/main/java/com/qmetry/qaf/automation/core/SkipTestException.java @@ -0,0 +1,58 @@ +/******************************************************************************* + * Copyright (c) 2019 Infostretch Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + ******************************************************************************/ +package com.qmetry.qaf.automation.core; + +/** + * To indicate that the test case can be + * in skip state instead of fail com.qmetry.qaf.automation.AutomationError.java + * + * @author chirag + */ +public class SkipTestException extends RuntimeException { + + + /** + * + */ + private static final long serialVersionUID = -148674252210382159L; + + public SkipTestException(String msg) { + super(msg); + } + + public SkipTestException(String msg, Throwable cause) { + super(msg, cause); + } + + public SkipTestException(Throwable cause) { + this(cause.getMessage(), cause); + } + + public boolean isSkip() { + return true; + } + + public synchronized Throwable getSelfOrCause() { + Throwable retVal = getCause(); + return null!=retVal?retVal:this; + } +} diff --git a/qaf-core/src/main/java/com/qmetry/qaf/automation/data/BaseDataBean.java b/qaf-core/src/main/java/com/qmetry/qaf/automation/data/BaseDataBean.java index 5daf32e3..1f9c6830 100644 --- a/qaf-core/src/main/java/com/qmetry/qaf/automation/data/BaseDataBean.java +++ b/qaf-core/src/main/java/com/qmetry/qaf/automation/data/BaseDataBean.java @@ -47,8 +47,9 @@ import org.apache.commons.logging.LogFactory; import org.json.JSONException; import org.json.JSONObject; -import org.testng.SkipException; +//import org.testng.SkipException; +import com.qmetry.qaf.automation.core.AutomationError; import com.qmetry.qaf.automation.keys.ApplicationProperties; import com.qmetry.qaf.automation.util.ClassUtil; import com.qmetry.qaf.automation.util.DatabaseUtil; @@ -106,7 +107,7 @@ public void fillData(Object obj) { } } - throw new SkipException( + throw new AutomationError( "Unable to fill data with unknown object. It must be either Map or String: valid json / property key / sql statement." + obj); diff --git a/qaf-core/src/main/java/com/qmetry/qaf/automation/data/MetaData.java b/qaf-core/src/main/java/com/qmetry/qaf/automation/data/MetaData.java index 4f73adfa..cef3c9d7 100644 --- a/qaf-core/src/main/java/com/qmetry/qaf/automation/data/MetaData.java +++ b/qaf-core/src/main/java/com/qmetry/qaf/automation/data/MetaData.java @@ -28,8 +28,6 @@ import java.lang.annotation.Retention; import java.lang.annotation.Target; -import org.testng.annotations.Test; - /** * This annotation should be used with {@link Test} annotation to provide * additional test meta-data. This annotation enables to provide custom diff --git a/qaf-core/src/main/java/com/qmetry/qaf/automation/keys/ApplicationProperties.java b/qaf-core/src/main/java/com/qmetry/qaf/automation/keys/ApplicationProperties.java index adc393ed..b78bf2f4 100644 --- a/qaf-core/src/main/java/com/qmetry/qaf/automation/keys/ApplicationProperties.java +++ b/qaf-core/src/main/java/com/qmetry/qaf/automation/keys/ApplicationProperties.java @@ -27,9 +27,9 @@ import java.util.List; import com.qmetry.qaf.automation.util.StringUtil; -import org.testng.IRetryAnalyzer; -import org.testng.ITestContext; -import org.testng.ITestResult; +//import org.testng.IRetryAnalyzer; +//import org.testng.ITestContext; +//import org.testng.ITestResult; import com.qmetry.qaf.automation.core.ConfigurationManager; import com.qmetry.qaf.automation.core.QAFListener; @@ -104,7 +104,7 @@ public enum ApplicationProperties { /** * key: tng.context
- * value: {@link ITestContext} object for current running + * value: {@link org.testng.ITestContext} object for current running * thread/test-case. * */ @@ -123,7 +123,7 @@ public enum ApplicationProperties { CURRENT_TEST_DESCRIPTION("current.testcase.desc"), /** * key: current.testcase.result
- * value: {@link ITestResult} object for the current running test + * value: {@link org.testng.ITestResult} object for the current running test * case. * * @since 2.1.9 @@ -526,7 +526,7 @@ public enum ApplicationProperties { /** * key: retry.analyzer
* value: fully qualified class name that implements - * {@link IRetryAnalyzer}. Provide this property to use your custom retry + * {@link org.testng.IRetryAnalyzer}. Provide this property to use your custom retry * analyzer. */ RETRY_ANALYZER("retry.analyzer"), @@ -661,6 +661,7 @@ public enum ApplicationProperties { * @since 2.1.15 * */ + SCENARIO_FILE_LOC("scenario.file.loc"), METADATA_RULES("metadata.rules"), /** *

diff --git a/qaf-core/src/main/java/com/qmetry/qaf/automation/step/QAFTestStepListener.java b/qaf-core/src/main/java/com/qmetry/qaf/automation/step/QAFTestStepListener.java index aecf150e..28b922a5 100644 --- a/qaf-core/src/main/java/com/qmetry/qaf/automation/step/QAFTestStepListener.java +++ b/qaf-core/src/main/java/com/qmetry/qaf/automation/step/QAFTestStepListener.java @@ -21,7 +21,6 @@ ******************************************************************************/ package com.qmetry.qaf.automation.step; -import org.testng.SkipException; import com.qmetry.qaf.automation.core.QAFListener; diff --git a/qaf-core/src/main/java/com/qmetry/qaf/automation/step/StepInvocationException.java b/qaf-core/src/main/java/com/qmetry/qaf/automation/step/StepInvocationException.java index 2c8d8eae..fb158147 100644 --- a/qaf-core/src/main/java/com/qmetry/qaf/automation/step/StepInvocationException.java +++ b/qaf-core/src/main/java/com/qmetry/qaf/automation/step/StepInvocationException.java @@ -21,8 +21,9 @@ ******************************************************************************/ package com.qmetry.qaf.automation.step; -import org.testng.SkipException; +//import org.testng.SkipException; +import com.qmetry.qaf.automation.core.SkipTestException; import com.qmetry.qaf.automation.util.StackTraceUtils; import com.qmetry.qaf.automation.util.StringUtil; @@ -31,7 +32,7 @@ * * @author chirag.jayswal */ -public class StepInvocationException extends SkipException { +public class StepInvocationException extends SkipTestException { private static final long serialVersionUID = 5737290921256174216L; private boolean isSkip = false; @@ -66,8 +67,8 @@ public boolean isSkip() { */ public StepInvocationException(TestStep step, Throwable cause) { this(step, cause, false); - if (cause instanceof SkipException) { - isSkip = ((SkipException) cause).isSkip(); + if (cause instanceof SkipTestException) { + isSkip = ((SkipTestException) cause).isSkip(); } } diff --git a/qaf-core/src/main/java/com/qmetry/qaf/automation/step/StepNotFoundException.java b/qaf-core/src/main/java/com/qmetry/qaf/automation/step/StepNotFoundException.java index c4552278..7d0e4a41 100644 --- a/qaf-core/src/main/java/com/qmetry/qaf/automation/step/StepNotFoundException.java +++ b/qaf-core/src/main/java/com/qmetry/qaf/automation/step/StepNotFoundException.java @@ -23,8 +23,9 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.impl.LogFactoryImpl; -import org.testng.SkipException; +//import org.testng.SkipException; +import com.qmetry.qaf.automation.core.SkipTestException; import com.qmetry.qaf.automation.keys.ApplicationProperties; import com.qmetry.qaf.automation.util.StackTraceUtils; @@ -33,7 +34,7 @@ * * @author chirag.jayswal */ -public class StepNotFoundException extends SkipException { +public class StepNotFoundException extends SkipTestException { private static final long serialVersionUID = -6115930100096312628L; private static final Log logger = LogFactoryImpl.getLog(StepNotFoundException.class); diff --git a/qaf-core/src/main/java/com/qmetry/qaf/automation/ui/AbstractTestPage.java b/qaf-core/src/main/java/com/qmetry/qaf/automation/ui/AbstractTestPage.java index 60580507..8bc628e5 100644 --- a/qaf-core/src/main/java/com/qmetry/qaf/automation/ui/AbstractTestPage.java +++ b/qaf-core/src/main/java/com/qmetry/qaf/automation/ui/AbstractTestPage.java @@ -170,7 +170,7 @@ protected void initParent() { Class

class1 = (Class

) ((ParameterizedType) this.getClass().getGenericSuperclass()) .getActualTypeArguments()[0]; if (!class1.isInterface()) { - parent = class1.newInstance(); + parent = class1.getDeclaredConstructor().newInstance(); } } catch (Exception e) { logger.warn("Unable to init parent class" + e.getMessage()); @@ -206,7 +206,7 @@ public final P getParent() { return this.parent; } - abstract protected void initWebElements(); + protected void initWebElements() {}; public void assertActive() { diff --git a/qaf-core/src/main/java/com/qmetry/qaf/automation/util/ClassUtil.java b/qaf-core/src/main/java/com/qmetry/qaf/automation/util/ClassUtil.java index 6c245a3a..60598d86 100644 --- a/qaf-core/src/main/java/com/qmetry/qaf/automation/util/ClassUtil.java +++ b/qaf-core/src/main/java/com/qmetry/qaf/automation/util/ClassUtil.java @@ -715,5 +715,15 @@ public static Class getClass(Type typeOfT) { } } + + public static boolean isPresent(String className) { + try { + Class.forName(className, false, ClassLoader.getSystemClassLoader()); + return true; + } catch (Throwable ex) { + // Class or one of its dependencies is not present... + return false; + } + } } diff --git a/qaf-core/src/main/java/com/qmetry/qaf/automation/util/Reporter.java b/qaf-core/src/main/java/com/qmetry/qaf/automation/util/Reporter.java index f31a5398..94acc955 100644 --- a/qaf-core/src/main/java/com/qmetry/qaf/automation/util/Reporter.java +++ b/qaf-core/src/main/java/com/qmetry/qaf/automation/util/Reporter.java @@ -21,13 +21,11 @@ ******************************************************************************/ package com.qmetry.qaf.automation.util; -import static com.qmetry.qaf.automation.core.ConfigurationManager.getBundle; import static com.qmetry.qaf.automation.core.TestBaseProvider.instance; -import org.testng.ITestResult; +//import org.testng.ITestResult; import com.qmetry.qaf.automation.core.MessageTypes; -import com.qmetry.qaf.automation.keys.ApplicationProperties; //import com.qmetry.qaf.automation.step.client.TestNGScenario; /** @@ -82,11 +80,11 @@ public static void logWithScreenShot(String msg) { * Add meta-data to current test case. Useful to link cloud session, video etc. * @param key * @param val - */ + public static void addMetadata(String key, String val) { ITestResult tr = (ITestResult) getBundle().getProperty(ApplicationProperties.CURRENT_TEST_RESULT.key); addMetadata(tr, key, val); - } + } */ /** * Add meta-data to current test case. Useful to link cloud session, video etc. @@ -94,11 +92,11 @@ public static void addMetadata(String key, String val) { * @param tr * @param key * @param val - */ + public static void addMetadata(ITestResult tr, String key, String val) { //if(null!=tr && tr.getMethod() instanceof TestNGScenario) { //((TestNGScenario) tr.getMethod()).getMetaData().put(key, val); //} - } + } */ } diff --git a/qaf-core/src/main/java/com/qmetry/qaf/automation/util/Validator.java b/qaf-core/src/main/java/com/qmetry/qaf/automation/util/Validator.java index ab01b2c4..48664c5c 100644 --- a/qaf-core/src/main/java/com/qmetry/qaf/automation/util/Validator.java +++ b/qaf-core/src/main/java/com/qmetry/qaf/automation/util/Validator.java @@ -26,10 +26,11 @@ import org.hamcrest.Description; import org.hamcrest.Matcher; import org.hamcrest.StringDescription; -import org.testng.SkipException; +//import org.testng.SkipException; import com.google.common.collect.MapDifference; import com.qmetry.qaf.automation.core.MessageTypes; +import com.qmetry.qaf.automation.core.SkipTestException; /** * com.qmetry.qaf.automation.util.Validator.java @@ -70,7 +71,7 @@ public static void assertThat(String reason, T actual, Matcher ma public static void givenThat(String reason, T actual, Matcher matcher) { if (!verifyThat(reason, actual, matcher)) { - throw new SkipException("Precondition not satisfied"); + throw new SkipTestException("Precondition not satisfied"); } } diff --git a/qaf-core/src/main/resources/META-INF/MANIFEST.MF b/qaf-core/src/main/resources/META-INF/MANIFEST.MF index 290c3fb4..73e802bb 100644 --- a/qaf-core/src/main/resources/META-INF/MANIFEST.MF +++ b/qaf-core/src/main/resources/META-INF/MANIFEST.MF @@ -1,4 +1,3 @@ -Vendor: Infostretch Corp. Built-By: ${user.name} Build-Java: ${java.version} Build-OS: ${os.name} @@ -7,4 +6,4 @@ qaf-Build-Time: ${maven.build.timestamp} qaf-Build-Label: ${project.version} qaf-Version: ${project.artifact.selectedVersion.majorVersion} qaf-Revision: ${project.artifact.selectedVersion.minorVersion} -qaf-Type: core +qaf-Type: core \ No newline at end of file diff --git a/qaf-playwright/pom.xml b/qaf-playwright/pom.xml index f99b41df..6cb47dd0 100644 --- a/qaf-playwright/pom.xml +++ b/qaf-playwright/pom.xml @@ -13,12 +13,12 @@ com.qmetry qaf-core - ${project.version} + ${revision} com.qmetry qaf-testng - ${project.version} + ${revision} true diff --git a/qaf-selenium/pom.xml b/qaf-selenium/pom.xml index 367bb6c9..fdbe2028 100644 --- a/qaf-selenium/pom.xml +++ b/qaf-selenium/pom.xml @@ -1,4 +1,6 @@ - + 4.0.0 com.qmetry @@ -14,7 +16,8 @@ com.qmetry qaf-core - ${project.version} + ${revision} + compile org.seleniumhq.selenium @@ -27,12 +30,6 @@ selenium-java ${selenium.version} compile - - - com.codeborne - * - - io.github.bonigarcia @@ -40,5 +37,17 @@ 5.6.3 compile + + org.seleniumhq.selenium + selenium-leg-rc + ${selenium.version} + true + + + * + * + + + \ No newline at end of file diff --git a/qaf-selenium/src/main/java/com/qmetry/qaf/automation/ui/webdriver/QAFExtendedWebDriver.java b/qaf-selenium/src/main/java/com/qmetry/qaf/automation/ui/webdriver/QAFExtendedWebDriver.java index 962ec40f..fd44b663 100644 --- a/qaf-selenium/src/main/java/com/qmetry/qaf/automation/ui/webdriver/QAFExtendedWebDriver.java +++ b/qaf-selenium/src/main/java/com/qmetry/qaf/automation/ui/webdriver/QAFExtendedWebDriver.java @@ -247,11 +247,13 @@ private Response executeSuper(CommandPayload payload) { } private Response executeWithoutLog(CommandPayload payload) { + //min version is now 4.0.0 + Response response = super.execute(payload); + // in order to compatibility with 3.x, compiled with 3.x. so method from 4.x super class will not be available. // Once min version set to 4.0 we don't need executeSuper method. - //Response response = super.execute(payload); - Response response = executeSuper(payload); + //Response response = executeSuper(payload); if (response == null) { return null; diff --git a/qaf-selenium/src/main/java/com/qmetry/qaf/automation/ui/webdriver/QAFExtendedWebElement.java b/qaf-selenium/src/main/java/com/qmetry/qaf/automation/ui/webdriver/QAFExtendedWebElement.java index 5234afed..2647aedb 100644 --- a/qaf-selenium/src/main/java/com/qmetry/qaf/automation/ui/webdriver/QAFExtendedWebElement.java +++ b/qaf-selenium/src/main/java/com/qmetry/qaf/automation/ui/webdriver/QAFExtendedWebElement.java @@ -46,12 +46,13 @@ import org.openqa.selenium.remote.RemoteWebElement; import org.openqa.selenium.remote.Response; //import org.openqa.selenium.remote.internal.JsonToWebElementConverter; -import org.testng.SkipException; +//import org.testng.SkipException; import com.google.common.collect.ImmutableMap; import com.qmetry.qaf.automation.core.ConfigurationManager; import com.qmetry.qaf.automation.core.MessageTypes; import com.qmetry.qaf.automation.core.QAFListener; +import com.qmetry.qaf.automation.core.SkipTestException; import com.qmetry.qaf.automation.keys.ApplicationProperties; import com.qmetry.qaf.automation.ui.WebDriverCommandLogger; import com.qmetry.qaf.automation.ui.WebDriverTestBase; @@ -1083,13 +1084,13 @@ public boolean verifyNotCssStyleColor(String prop, String value, String... label // preconditions public void givenPresent() { if (!verifyPresent()) { - throw new SkipException("Precondition failed:" + getDescription() + " should be present"); + throw new SkipTestException("Precondition failed:" + getDescription() + " should be present"); } } public void givenNotPresent(String... label) { if (!verifyNotPresent(label)) { - throw new SkipException("Precondition failed:" + throw new SkipTestException("Precondition failed:" + WebDriverCommandLogger.getMsgForElementOp("notpresent", false, getDescription(label))); } } diff --git a/qaf-support-ws/pom.xml b/qaf-support-ws/pom.xml new file mode 100644 index 00000000..e6476307 --- /dev/null +++ b/qaf-support-ws/pom.xml @@ -0,0 +1,66 @@ + + 4.0.0 + + com.qmetry + qaf-parent + ${revision} + + qaf-support-ws + + support + + + + com.qmetry + qaf-ws + ${qaf.version} + + + com.jayway.jsonpath + json-path + 2.9.0 + compile + + + com.jayway.jsonpath + json-path-assert + 2.9.0 + compile + + + com.github.java-json-tools + json-schema-validator + 2.2.14 + + + com.google.guava + * + + + org.testng + * + + + + + com.wealdtech.hawk + hawk-client-jersey + 1.2.3 + true + + + com.googlecode.json-simple + json-simple + 1.1.1 + true + + + junit + * + + + + + \ No newline at end of file diff --git a/qaf-support-ws/resources/data.xml b/qaf-support-ws/resources/data.xml new file mode 100644 index 00000000..0646e4eb --- /dev/null +++ b/qaf-support-ws/resources/data.xml @@ -0,0 +1,45 @@ + + + + + {"Content-type":"${content-type}", +"Accept":"${accept}"} + /myservice-endpoint + ${env.baseurl} + POST + {'param1':'${val1}','param2':'${val2}'} + + {'a':'b','i':10} + {'val1':'abc','val2':'xyz','content-type':'application/json', +'accept":"application/json'} + + + + tmpl.a +POST + +{"Content-type":"application/json", +"Accept":"application/json"} + + + diff --git a/qaf-support-ws/resources/requestcall.xml b/qaf-support-ws/resources/requestcall.xml new file mode 100644 index 00000000..cdddb74b --- /dev/null +++ b/qaf-support-ws/resources/requestcall.xml @@ -0,0 +1,47 @@ + + + + https://httpbin.org/ + + {"Content-type":"${content-type}", + "Accept":"application/json", + "X-requestID":"${expr:java.util.UUID.randomUUID()}" + } + + {'a':'a','b':'b'} + + {"content-type":"application/json", + "accept":"application/json"} + + + + reference + GET + /get + {'a':'a','b':''} + + + reference + GET + /get + + { + "Content-type":"application/xml", + "Accept":"application/json" + } + + + diff --git a/qaf-support-ws/resources/res.xml b/qaf-support-ws/resources/res.xml new file mode 100644 index 00000000..57632917 --- /dev/null +++ b/qaf-support-ws/resources/res.xml @@ -0,0 +1,35 @@ + + + + + + + 1.90 + 1.91 + + + + + diff --git a/qaf-support-ws/src/main/java/com/qmetry/qaf/automation/step/WsStep.java b/qaf-support-ws/src/main/java/com/qmetry/qaf/automation/step/WsStep.java new file mode 100644 index 00000000..9739d20e --- /dev/null +++ b/qaf-support-ws/src/main/java/com/qmetry/qaf/automation/step/WsStep.java @@ -0,0 +1,1171 @@ +/******************************************************************************* + * Copyright (c) 2019 Infostretch Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + ******************************************************************************/ +package com.qmetry.qaf.automation.step; + +import static com.qmetry.qaf.automation.core.ConfigurationManager.getBundle; +import static com.qmetry.qaf.automation.util.Validator.assertFalse; +import static com.qmetry.qaf.automation.util.Validator.assertThat; +import static com.qmetry.qaf.automation.util.Validator.assertTrue; +import static com.qmetry.qaf.automation.util.Validator.verifyFalse; +import static com.qmetry.qaf.automation.util.Validator.verifyThat; +import static com.qmetry.qaf.automation.util.Validator.verifyTrue; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasEntry; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.math.BigDecimal; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Map; +import java.util.Map.Entry; + +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.MultivaluedMap; + +import org.apache.commons.io.FileUtils; +import org.hamcrest.Matchers; +import org.json.JSONObject; + +import com.github.fge.jackson.JsonLoader; +import com.github.fge.jsonschema.core.exceptions.ProcessingException; +import com.github.fge.jsonschema.core.report.ProcessingMessage; +import com.github.fge.jsonschema.core.report.ProcessingReport; +import com.github.fge.jsonschema.main.JsonSchema; +import com.github.fge.jsonschema.main.JsonSchemaFactory; +import com.google.gson.Gson; +import com.jayway.jsonpath.JsonPath; +import com.qmetry.qaf.automation.core.AutomationError; +import com.qmetry.qaf.automation.core.ConfigurationManager; +import com.qmetry.qaf.automation.core.MessageTypes; +import com.qmetry.qaf.automation.keys.ApplicationProperties; +import com.qmetry.qaf.automation.util.JSONUtil; +import com.qmetry.qaf.automation.util.Reporter; +import com.qmetry.qaf.automation.util.StringMatcher; +import com.qmetry.qaf.automation.util.StringUtil; +import com.qmetry.qaf.automation.util.Validator; +import com.qmetry.qaf.automation.util.XPathUtils; +import com.qmetry.qaf.automation.ws.WSCRepositoryConstants; +import com.qmetry.qaf.automation.ws.WsRequestBean; +import com.qmetry.qaf.automation.ws.rest.RestTestBase; +import com.sun.jersey.api.client.ClientResponse; +import com.sun.jersey.api.client.ClientResponse.Status; +import com.sun.jersey.api.client.WebResource; +import com.sun.jersey.api.client.WebResource.Builder; +import com.sun.jersey.core.util.MultivaluedMapImpl; +import com.sun.jersey.multipart.FormDataMultiPart; +import com.sun.jersey.multipart.file.FileDataBodyPart; + +/** + * com.qmetry.qaf.automation.step.CommonStep.java + * + * @author chirag + */ +public final class WsStep { + + /** + * This method check for the response status of web service + *

+ * Example: + *

+ * BDD + *

+ * + * response should have status 'ResponceStatus'
+ *
+ *

+ * KWD + *

+ * + * @param status + * : {0} : Status String for Exampe: OK, CREATED + * @see Status + */ + @QAFTestStep(description = "response should have status {status}") + public static void responseShouldHaveStatus(String status) { + assertThat("Response Status", new RestTestBase().getResponse().getStatus().name(), + Matchers.equalToIgnoringCase(status)); + } + + /** + * This method check for the response status of web service + *

+ * Example: + *

+ * BDD + *

+ * + * response should have status 'ResponceStatus'
+ *
+ *

+ * KWD + *

+ * + * @param status + * : {0} : Status code, for example 200, 301 + * @see Status + */ + @QAFTestStep(description = "response should have status code {statusCode}") + public static void responseShouldHaveStatusCode(int statusCode) { + assertThat("Response Status", new RestTestBase().getResponse().getStatus().getStatusCode(), + Matchers.equalTo(statusCode)); + } + + /** + * This method request for the given parameters + * + * @param request + * key or map + * @return + */ + @QAFTestStep(description = "user requests {0}") + public static ClientResponse userRequests(Object request) { + WsRequestBean bean = new WsRequestBean(); + bean.fillData(request); + bean.resolveParameters(null); + return request(bean); + } + + /** + * This method request for given parameters with given dataset + * + * @param request + * key or map + * @param data + * data set of key value pair + * @return + */ + @QAFTestStep(description = "user requests {request} with data {data}", stepName = "userRequestsWithData") + public static ClientResponse userRequests(Object request, Map data) { + WsRequestBean bean = new WsRequestBean(); + bean.fillData(request); + bean.resolveParameters(data); + return request(bean); + } + + /** + * This method check given header is there in response of web service + *

+ * Example: + *

+ * BDD + *

+ * + * response should have header 'Content-Type'
+ *

+ * + * @param header + * : header to be verified in respose + */ + @QAFTestStep(description = "response should have header {0}") + public static void responseShouldHaveHeader(String header) { + assertThat(new RestTestBase().getResponse().getHeaders(), Matchers.hasKey(header)); + } + + /** + * This method check given header with specific value present in response of + * web service + *

+ * Example: + *

+ * BDD + *

+ * + * response should have header 'Content-Type' with value 'application/json'
+ *

+ * + * @param header + * : header to be present in respose + * @param value + * : value to be verified for header + */ + @QAFTestStep(description = "response should have header {0} with value {1}") + public static void responseShouldHaveHeaderWithValue(String header, String value) { + assertThat(new RestTestBase().getResponse().getHeaders(), hasEntry(equalTo(header), Matchers.hasItem(value))); + } + + /** + * This method check given jsonpath is there in response of web service + *

+ * Example: + *

+ * + * response should have 'user.username' + * + *

+ * + * @param path + * : jsonpath + */ + @QAFTestStep(description = "response should have {jsonpath}") + public static void responseShouldHaveJsonPath(String path) { + if (!path.startsWith("$")) + path = "$." + path; + assertThat("Response Body has " + path, hasJsonPath(new RestTestBase().getResponse().getMessageBody(), path), + Matchers.equalTo(true)); + } + + /** + * This method check given jsonpath is not in response of web service + *

+ * Example: + *

+ * + * response should not have 'user.username' + * + *

+ * + * @param path + * : jsonpath + */ + @QAFTestStep(description = "response should not have {jsonpath}") + public static void responseShouldNotHaveJsonPath(String path) { + if (!path.startsWith("$")) + path = "$." + path; + assertThat("Response Body has not " + path, + hasJsonPath(new RestTestBase().getResponse().getMessageBody(), path), Matchers.equalTo(false)); + } + + /** + * This method validates value for given jsonpath + *

+ * Example: + *

+ * + * response should have 'admin' at 'user.username' + * + *

+ * + * @param expectedValue + * : expected value + * @param path + * : jsonpath + */ + @QAFTestStep(description = "response should have {expectedvalue} at {jsonpath}") + public static void responseShouldHaveKeyWithValue(Object expectedValue, String path) { + if (!path.startsWith("$")) + path = "$." + path; + Object actual = JsonPath.read(new RestTestBase().getResponse().getMessageBody(), path); + if (null != actual && Number.class.isAssignableFrom(actual.getClass())) { + assertThat(new BigDecimal(String.valueOf(actual)), + Matchers.equalTo(new BigDecimal(String.valueOf(expectedValue)))); + } else { + assertThat(actual, Matchers.equalTo((Object) expectedValue)); + } + } + + /** + * This method store value of given json path to + * {@link ConfigurationManager} + *

+ * Example: + *

+ * + * store response body 'user.username' to 'loginuser' + * + *

+ * + * @deprecated user {@link #sayValueAtJsonPath(String, String)} + * @param path + * jsonpath + * @param variable + * variable that can be use later + */ + @QAFTestStep(description = "store response body {0} (in)to {1}") + public static void storeResponseBodyto(String path, String variable) { + if (!path.startsWith("$")) + path = "$." + path; + Object value = JsonPath.read(new RestTestBase().getResponse().getMessageBody(), path); + getBundle().setProperty(variable, value); + } + + /** + * This method validates value of jsonpath contains expected value or not + *

+ * Example: + *

+ * + * response should have value contains 'admin' at 'user.username' + * + *

+ * + * @param value + * : expected value + * @param path + * : jsonpath + */ + @QAFTestStep(description = "response should have value contains {expectedvalue} at {jsonpath}") + public static void responseShouldHaveKeyAndValueContains(String value, String path) { + if (!path.startsWith("$")) + path = "$." + path; + Object actual = JsonPath.read(new RestTestBase().getResponse().getMessageBody(), path); + assertThat(String.valueOf(actual), Matchers.containsString(value)); + } + + /** + * This method store value of given header to {@link ConfigurationManager} + *

+ * Example: + *

+ * + * store response header 'X-Auth-token' to 'token' + * + *

+ * + * @param header + * header + * @param property + * variable that can be use later + */ + @QAFTestStep(description = "store response header {0} (in)to {1}") + public static void storeResponseHeaderTo(String header, String property) { + getBundle().setProperty(property, new RestTestBase().getResponse().getHeaders().get(header)); + } + + /** + * This method validates that value at jsonpath should be less than + * expectedvalue + *

+ * Example: + *

+ * + * response should be less than 500 at 'student.totalmarks' + * + *

+ * + * @param value + * : expected value + * @param path + * : jsonpath + */ + @QAFTestStep(description = "response should be less than {expectedvalue} at {jsonpath}") + public static void responseShouldLessThan(double expectedValue, String path) { + Object actual = JsonPath.read(new RestTestBase().getResponse().getMessageBody(), getPath(path)); + assertThat(Double.parseDouble(String.valueOf(actual)), Matchers.lessThan(expectedValue)); + } + + /** + * This method downloads and save file from the response in report directory for current execution. + *

+ * BDD Example: + *

+ *
+	 * 
+	 *    Given user requests "download.file.req"
+	 *    And store into 'file.response'
+	 *    Then save file as "logo.png" from "${file.response}"
+	 * 
+	 * 
+ *

+ * Java Example: + *

+ *
+	 * 
+	 *    ClientResponse response  = userRequests("download.file.req");
+	 *    downloadFileFromResponse("logo.png", response);
+	 * 
+	 * 
+ * @param name + * @param response + * @throws IOException + */ + @QAFTestStep(description = "download file as {file-name} from {response}") + public static void downloadFileFromResponse(String name, ClientResponse response) throws IOException { + InputStream in = response.getEntityInputStream(); + File logo = new File(ApplicationProperties.JSON_REPORT_DIR.getStringVal("."), name); + Files.copy(in, logo.toPath()); + } + + /** + * This method validates that value at jsonpath should be less than or equal + * to expectedvalue + *

+ * Example: + *

+ * + * response should be less than or equals to 500 at 'student.totalmarks' + * + *

+ * + * @param value + * : expected value + * @param path + * : jsonpath + */ + @QAFTestStep(description = "response should be less than or equals to {expectedvalue} at {jsonpath}") + public static void responseShouldLessThanOrEqualsTo(double expectedValue, String path) { + Object actual = JsonPath.read(new RestTestBase().getResponse().getMessageBody(), getPath(path)); + assertThat(Double.parseDouble(String.valueOf(actual)), Matchers.lessThanOrEqualTo(expectedValue)); + } + + /** + * This method validates that value at jsonpath should be greater than + * expectedvalue + *

+ * Example: + *

+ * + * response should be greater than 500 at 'student.totalmarks' + * + *

+ * + * @param value + * : expected value + * @param path + * : jsonpath + */ + @QAFTestStep(description = "response should be greater than {expectedvalue} at {jsonpath}") + public static void responseShouldGreaterThan(double expectedValue, String path) { + Object actual = JsonPath.read(new RestTestBase().getResponse().getMessageBody(), getPath(path)); + assertThat(Double.parseDouble(String.valueOf(actual)), Matchers.greaterThan(expectedValue)); + } + + /** + * This method validates that value at jsonpath should be greater than or + * equal to expectedvalue + *

+ * Example: + *

+ * + * response should be greater than or equals to 500 at 'student.totalmarks' + * + *

+ * + * @param value + * : expected value + * @param path + * : jsonpath + */ + @QAFTestStep(description = "response should be greater than or equals to {expectedvalue} at {jsonpath}") + public static void responseShouldGreaterThanOrEqualsTo(double expectedValue, String path) { + Object actual = JsonPath.read(new RestTestBase().getResponse().getMessageBody(), getPath(path)); + assertThat(Double.parseDouble(String.valueOf(actual)), Matchers.greaterThanOrEqualTo(expectedValue)); + } + + /** + * This method validates value at jsonpath equals to expected value with + * ignoring case or not + *

+ * Example: + *

+ * + * response should have value ignoring case 'admin' at 'user.username' + * + *

+ * + * @param value + * : expected value + * @param path + * : jsonpath + */ + @QAFTestStep(description = "response should have value ignoring case {expectedvalue} at {jsonpath}") + public static void responseShouldHaveValueIgnoringCase(String expectedValue, String path) { + Object actual = JsonPath.read(new RestTestBase().getResponse().getMessageBody(), getPath(path)); + assertThat(String.valueOf(actual), Matchers.equalToIgnoringCase(expectedValue)); + } + + /** + * This method validates value at jsonpath contains expected value with + * ignoring case or not + *

+ * Example: + *

+ * + * response should have value contains ignoring case 'admin' at 'user.username' + * + *

+ * + * @param value + * : expected value + * @param path + * : jsonpath + */ + @QAFTestStep(description = "response should have value contains ignoring case {expectedvalue} at {jsonpath}") + public static void responseShouldHaveValueContainsIgnoringCase(String expectedValue, String path) { + Object actual = JsonPath.read(new RestTestBase().getResponse().getMessageBody(), getPath(path)); + assertThat(String.valueOf(actual).toUpperCase(), Matchers.containsString(expectedValue.toUpperCase())); + } + + /** + * This method validates value of jsonpath matches with regEx value or not + *

+ * Example: + *

+ * + * response should have value matches with '[a-z]*' at 'user.username' + * + *

+ * + * @param value + * : expected value + * @param path + * : jsonpath + */ + @QAFTestStep(description = "response should have value matches with {regEx} at {jsonpath}") + public static void responseShouldHaveValueMatchesWith(String regEx, String path) { + Object actual = JsonPath.read(new RestTestBase().getResponse().getMessageBody(), getPath(path)); + assertThat(String.valueOf(actual).matches(regEx), Matchers.equalTo(true)); + } + + /** + * This method validates value of jsonpath is not equal to expected value + *

+ * Example: + *

+ * + * response should not have value 'admin' at 'user.username' + * + *

+ * + * @param value + * : expected value + * @param path + * : jsonpath + */ + @QAFTestStep(description = "response should not have value {expectedvalue} at {jsonpath}") + public static void responseShouldNotHaveValue(Object expectedValue, String path) { + Object actual = JsonPath.read(new RestTestBase().getResponse().getMessageBody(), getPath(path)); + assertThat(actual, Matchers.not(expectedValue)); + } + + @QAFTestStep(description = "verify response schema for {0}") + public static boolean verifyResponseSchema(String requestKey) { + ProcessingReport result = null; + try { + com.fasterxml.jackson.databind.JsonNode responseNode = JsonLoader + .fromString(new RestTestBase().getResponse().getMessageBody()); + Map map = JSONUtil + .toMap(ConfigurationManager.getBundle().getString(requestKey, requestKey)); + Object responseSchema = map.get(WSCRepositoryConstants.RESPONSE_SCHEMA); + if (responseSchema instanceof Map) { + responseSchema = new Gson().toJson(responseSchema); + } else { + File file = new File(responseSchema.toString()); + if (file.exists()) + responseSchema = FileUtils.readFileToString(file, "UTF-8"); + } + com.fasterxml.jackson.databind.JsonNode schemaNode = JsonLoader.fromString(String.valueOf(responseSchema)); + JsonSchema schema = JsonSchemaFactory.byDefault().getJsonSchema(schemaNode); + result = schema.validate(responseNode); + if (!result.isSuccess()) { + for (ProcessingMessage processingMessage : result) { + Reporter.log(processingMessage.getMessage(), MessageTypes.Fail); + } + } + } catch (IOException e) { + e.printStackTrace(); + } catch (ProcessingException e) { + e.printStackTrace(); + } + return result != null && result.isSuccess(); + } + + /** + * This is verification method to check value at jsonpath in response status + * of web service. It will continue test case even if failure. It uses + * {@link StringMatcher} to match expected vs actual values. You can specify + * matcher by providing prefix separated by ':', For example, + * 'containsIgnoringCase:someValue' will use + * {@link StringMatcher#containsIgnoringCase(String)} Default is + * {@link StringMatcher#exact(String)} + *

+ * Example: + *

+ * BDD + *

+ * + * response should have value '1.90' at jsonpath '$.Price'
+ * response should have value 'gte:1.90' at jsonpath '$.Price'
+ *
+ *

+ * KWD + *

+ * + * @param val + * : {val} : value to be verified in response + * @param jsonpath + * : {jsonpath} : jsonpath to look value in response + */ + @QAFTestStep(description = "response should have value {val} at jsonpath {path}") + public static void responseShouldHaveValueAtJsonpath(Object val, String jsonpath) { + Object actual = JsonPath.read(new RestTestBase().getResponse().getMessageBody(), getPath(jsonpath)); + StringMatcher matcher = getMatcher(val); + boolean res = matcher.match(String.valueOf(actual)); + String message = "Expected value at jsonpath " + jsonpath + " [" + matcher + "] actual [" + actual + "]"; + verifyTrue(res, message, message); + + } + + /** + * This is verification method to check value is not at jsonpath in response + * status of web service. It will continue test case even if failure. It + * uses {@link StringMatcher} to match expected vs actual values. You can + * specify matcher by providing prefix separated by ':', For example, + * 'containsIgnoringCase:someValue' will use + * {@link StringMatcher#containsIgnoringCase(String)} Default is + * {@link StringMatcher#exact(String)} + *

+ * Example: + *

+ * BDD + *

+ * + * response should not have value '1.90' at jsonpath '$.Price'
+ * response should not have value 'gte:1.90' at jsonpath '$.Price'
+ *
+ *

+ * KWD + *

+ * + * @param val + * : {val} : value to be verified in response + * @param jsonpath + * : {jsonpath} : jsonpath to look value in response + */ + @QAFTestStep(description = "response should not have value {val} at jsonpath {path}") + public static void responseShouldNotHaveValueAtJsonpath(Object val, String jsonpath) { + Object actual = JsonPath.read(new RestTestBase().getResponse().getMessageBody(), getPath(jsonpath)); + StringMatcher matcher = getMatcher(val); + boolean res = matcher.match(String.valueOf(actual)); + String message = "Expected value at jsonpath " + jsonpath + " is not [" + matcher + "] actual [" + actual + "]"; + verifyFalse(res, message, message); + + } + + /** + * This is assertion method to check value at jsonpath in response status of + * web service. It will break test case on failure. It uses + * {@link StringMatcher} to match expected vs actual values. You can specify + * matcher by providing prefix separated by ':', For example, + * 'containsIgnoringCase:someValue' will use + * {@link StringMatcher#containsIgnoringCase(String)} Default is + * {@link StringMatcher#exact(String)} + *

+ * Example: + *

+ * BDD + *

+ * + * response has value '1.90' at jsonpath '$.Price'
+ * response has value 'gte:1.90' at jsonpath '$.Price'
+ *
+ *

+ * KWD + *

+ * + * @param val + * : {val} : value to be verified in response + * @param jsonpath + * : {jsonpath} : jsonpath to look value in response + */ + @QAFTestStep(description = "response has value {val} at jsonpath {jsonpath}") + public static void responseHasValueAtJsonpath(Object val, String jsonpath) { + Object actual = JsonPath.read(new RestTestBase().getResponse().getMessageBody(), getPath(jsonpath)); + StringMatcher matcher = getMatcher(val); + boolean res = matcher.match(String.valueOf(actual)); + String message = "Expected value at jsonpath " + jsonpath + " [" + matcher + "] actual [" + actual + "]"; + assertTrue(res, message, message); + } + + /** + * This is assertion method to check value is not at jsonpath in response + * status of web service. It will break test case on failure. It uses + * {@link StringMatcher} to match expected vs actual values. You can specify + * matcher by providing prefix separated by ':', For example, + * 'containsIgnoringCase:someValue' will use + * {@link StringMatcher#containsIgnoringCase(String)} Default is + * {@link StringMatcher#exact(String)} + *

+ * Example: + *

+ * BDD + *

+ * + * response has not value '1.90' at jsonpath '$.Price'
+ * response has not value 'gte:1.90' at jsonpath '$.Price'
+ *
+ *

+ * KWD + *

+ * + * @param val + * : {val} : value to be verified in response + * @param jsonpath + * : {jsonpath} : jsonpath to look value in response + */ + @QAFTestStep(description = "response has not value {val} at jsonpath {jsonpath}") + public static void responseHasValueNotAtJsonpath(Object val, String jsonpath) { + Object actual = JsonPath.read(new RestTestBase().getResponse().getMessageBody(), getPath(jsonpath)); + StringMatcher matcher = getMatcher(val); + boolean res = matcher.match(String.valueOf(actual)); + String message = "Expected value at jsonpath " + jsonpath + " is not [" + matcher + "] actual [" + actual + "]"; + assertFalse(res, message, message); + } + + @QAFTestStep(description = "response contains json {expectedJsonStr}") + public static void assertResponseContains(String expectedJsonStr) { + Validator.assertJsonContains(new RestTestBase().getResponse().getMessageBody(), expectedJsonStr); + } + + @QAFTestStep(description = "response should contain json {expectedJsonStr}") + public static void verifyResponseContains(String expectedJsonStr) { + Validator.verifyJsonContains(new RestTestBase().getResponse().getMessageBody(), expectedJsonStr); + } + + @QAFTestStep(description = "response matches json {expectedJsonStr}") + public static void assertResponseMatches(String expectedJsonStr) { + Validator.assertJsonMatches(new RestTestBase().getResponse().getMessageBody(), expectedJsonStr); + } + + @QAFTestStep(description = "response should match json {expectedJsonStr}") + public static void verifyResponseMatches(String expectedJsonStr) { + Validator.verifyJsonMatches(new RestTestBase().getResponse().getMessageBody(), expectedJsonStr); + } + + /** + * This method store value of given json path to + * {@link ConfigurationManager} + *

+ * Example: + *

+ * + * say 'loginuser' is value at jsonpath 'user.username' + * + *

+ * + * + * @param variable + * variable that can be use later + * @param path + * jsonpath + */ + @QAFTestStep(description = "say {var-name} is value at jsonpath {jsonpath}") + public static void sayValueAtJsonPath(String variable, String path) { + if (!path.startsWith("$")) + path = "$." + path; + Object value = JsonPath.read(new RestTestBase().getResponse().getMessageBody(), path); + getBundle().setProperty(variable, value); + } + + /** + * This is verification method to check given Xpath is there in response + * status of web service. It will continue test case even if failure. + *

+ * Example: + *

+ * BDD + *

+ * + * response should have xpath 'Xpath String'
+ *
+ *

+ * KWD + *

+ * + * @param xpath + * : {0} : xpath string to be verified in response + */ + @QAFTestStep(description = "response should have xpath {xpath}") + public static void responseShouldHaveXpath(String xpath) { + boolean hasXPath = !XPathUtils.read(new RestTestBase().getResponse().getMessageBody()).configurationsAt(xpath) + .isEmpty(); + verifyThat("Expected xpath " + xpath, hasXPath, Matchers.is(true)); + // assertThat(the(new RestTestBase().getResponse().getMessageBody()), + // hasXPath(xpath)); + } + + /** + * This is verification method to check given Xpath is not there in response + * status of web service. It will continue test case even if failure. + *

+ * Example: + *

+ * BDD + *

+ * + * response should not have xpath 'Xpath String'
+ *
+ *

+ * KWD + *

+ * + * @param xpath + * : {0} : xpath to be verified in response + */ + @QAFTestStep(description = "response should not have xpath {xpath}") + public static void responseShouldNotHaveXpath(String xpath) { + boolean hasNoXPath = XPathUtils.read(new RestTestBase().getResponse().getMessageBody()).configurationsAt(xpath) + .isEmpty(); + verifyThat("Expected xpath " + xpath + "not present", hasNoXPath, Matchers.is(false)); + } + + /** + * This is verification method to check value at XPATH in response status of + * web service. It will continue test case even if failure. It uses + * {@link StringMatcher} to match expected vs actual values. You can specify + * matcher by providing prefix separated by ':', For example, + * 'containsIgnoringCase:someValue' will use + * {@link StringMatcher#containsIgnoringCase(String)} Default is + * {@link StringMatcher#exact(String)} + *

+ * Example: + *

+ * BDD + *

+ * + * response should have value '1.90' at xpath '//Price'
+ * response should have value 'gte:1.90' at xpath '//Price'
+ *
+ *

+ * KWD + *

+ * + * @param val + * : {val} : value to be verified in response + * @param xpath + * : {xpath} : xpath to look value in response + */ + @QAFTestStep(description = "response should have value {val} at xpath {xpath}") + public static void responseShouldHaveValueAtXpath(Object val, String xpath) { + String actual = XPathUtils.read(new RestTestBase().getResponse().getMessageBody()).getString(xpath); + StringMatcher matcher = getMatcher(val); + boolean res = matcher.match(actual); + String message = "Expected value at xpath " + xpath + " [" + matcher + "] actual [" + actual + "]"; + verifyTrue(res, message, message); + // assertThat(the(new RestTestBase().getResponse().getMessageBody()), + // hasXPath(xpath)); + } + + /** + * This is verification method to check value at XPATH in response status of + * web service. It will continue test case even if failure. It uses + * {@link StringMatcher} to match expected vs actual values. You can specify + * matcher by providing prefix separated by ':', For example, + * 'containsIgnoringCase:someValue' will use + * {@link StringMatcher#containsIgnoringCase(String)} Default is + * {@link StringMatcher#exact(String)} + *

+ * Example: + *

+ * BDD + *

+ * + * response should have value '1.90' at xpath '//Price'
+ * response should have value 'gte:1.90' at xpath '//Price'
+ *
+ *

+ * KWD + *

+ * + * @param val + * : {val} : value to be verified in response + * @param xpath + * : {xpath} : xpath to look value in response + */ + @QAFTestStep(description = "response should not have value {val} at xpath {xpath}") + public static void responseShouldNotHaveValueAtXpath(Object val, String xpath) { + String actual = XPathUtils.read(new RestTestBase().getResponse().getMessageBody()).getString(xpath); + StringMatcher matcher = getMatcher(val); + boolean res = matcher.match(actual); + String message = "Expected value at xpath " + xpath + " is not [" + matcher + "] actual [" + actual + "]"; + verifyFalse(res, message, message); + // assertThat(the(new RestTestBase().getResponse().getMessageBody()), + // hasXPath(xpath)); + } + + /** + * This assertion method check given Xpath is there in response status of + * web service. It will break test case on failure. + *

+ * Example: + *

+ * BDD + *

+ * + * response should have xpath 'Xpath String'
+ *
+ *

+ * KWD + *

+ * + * @param xpath + * : {0} : xpath string to be verified in response + */ + @QAFTestStep(description = "response has xpath {xpath}") + public static void responseHasXpath(String xpath) { + boolean hasXPath = !XPathUtils.read(new RestTestBase().getResponse().getMessageBody()).configurationsAt(xpath) + .isEmpty(); + assertThat("Expected xpath " + xpath, hasXPath, Matchers.is(true)); + } + + /** + * This assertion method check given Xpath is not there in response status + * of web service. It will break test case on failure. + *

+ * Example: + *

+ * BDD + *

+ * + * response has not xpath 'Xpath String'
+ *
+ *

+ * KWD + *

+ * + * @param xpath + * : {0} : xpath to be verified in response + */ + @QAFTestStep(description = "response has not xpath {xpath}") + public static void responseHasNotXpath(String xpath) { + boolean hasNoXPath = XPathUtils.read(new RestTestBase().getResponse().getMessageBody()).configurationsAt(xpath) + .isEmpty(); + assertThat("Expected xpath " + xpath + " not present", hasNoXPath, Matchers.is(true)); + } + + /** + * This is assertion method to check value at XPATH in response status of + * web service. It will break test case on failure. It uses + * {@link StringMatcher} to match expected vs actual values. You can specify + * matcher by providing prefix separated by ':', For example, + * 'containsIgnoringCase:someValue' will use + * {@link StringMatcher#containsIgnoringCase(String)} Default is + * {@link StringMatcher#exact(String)} + *

+ * Example: + *

+ * BDD + *

+ * + * response has value '1.90' at xpath '//Price'
+ * response has value 'gte:1.90' at xpath '//Price'
+ *
+ *

+ * KWD + *

+ * + * @param val + * : {val} : value to be verified in response + * @param xpath + * : {xpath} : xpath to look value in response + */ + @QAFTestStep(description = "response has value {val} at xpath {xpath}") + public static void responseHasValueAtXpath(Object val, String xpath) { + String actual = XPathUtils.read(new RestTestBase().getResponse().getMessageBody()).getString(xpath); + StringMatcher matcher = getMatcher(val); + boolean res = matcher.match(actual); + String message = "Expected value at xpath " + xpath + " [" + matcher + "] actual [" + actual + "]"; + assertTrue(res, message, message); + } + + /** + * This is assertion method to check value is not at XPATH in response + * status of web service. It will break test case on failure. It uses + * {@link StringMatcher} to match expected vs actual values. You can specify + * matcher by providing prefix separated by ':', For example, + * 'containsIgnoringCase:someValue' will use + * {@link StringMatcher#containsIgnoringCase(String)} Default is + * {@link StringMatcher#exact(String)} + *

+ * Example: + *

+ * BDD + *

+ * + * response has not value '1.90' at xpath '//Price'
+ * response has not value 'gte:1.90' at xpath '//Price'
+ *
+ *

+ * KWD + *

+ * + * @param val + * : {val} : value to be verified in response + * @param xpath + * : {xpath} : xpath to look value in response + */ + @QAFTestStep(description = "response has not value {val} at xpath {xpath}") + public static void responseHasNotValueAtXpath(Object val, String xpath) { + String actual = XPathUtils.read(new RestTestBase().getResponse().getMessageBody()).getString(xpath); + StringMatcher matcher = getMatcher(val); + boolean res = matcher.match(actual); + String message = "Expected value at xpath " + xpath + " is not [" + matcher + "] actual [" + actual + "]"; + assertFalse(res, message, message); + } + + /** + * This method store value of given xpath to {@link ConfigurationManager} + *

+ * Example: + *

+ * + * say 'loginuser' is value at xpath '//user/username' + * + *

+ * + * + * @param variable + * variable that can be use later + * @param path + * xpath + */ + @QAFTestStep(description = "say {var-name} is value at xpath {xpath}") + public static void sayValueAtXPath(String variable, String path) { + Object value = XPathUtils.read(new RestTestBase().getResponse().getMessageBody()).getProperty(path); + getBundle().setProperty(variable, value); + } + @QAFTestStep(description = "resolve request call {0} with {data}") + public WsRequestBean resolveWSCwithData(Object request, Map data) { + WsRequestBean bean = new WsRequestBean(); + bean.fillData(request); + bean.resolveParameters(data); + return bean; + } + // move to rest test-base + public static ClientResponse request(WsRequestBean bean) { + + WebResource resource = new RestTestBase().getWebResource(bean.getBaseUrl(), bean.getEndPoint()); + + MultivaluedMap queryParams = new MultivaluedMapImpl(); + + for (Entry entry : bean.getQueryParameters().entrySet()) { + queryParams.add(entry.getKey(), entry.getValue().toString()); + } + resource = resource.queryParams(queryParams); + + Builder builder = resource.getRequestBuilder(); + + for (Entry header : bean.getHeaders().entrySet()) { + if (header.getKey().equalsIgnoreCase("Accept")) { + builder.accept((String) header.getValue()); + } + builder.header(header.getKey(), header.getValue()); + } + + String body = bean.getBody(); + if (StringUtil.isNotBlank(body)) { + // if body then post only body + + // binary stream? + if (StringMatcher.startsWithIgnoringCase("binary:").match(body)) { + byte[] bytes = new byte[0];// empty content + String file = body.split(":", 2)[1]; + if (StringUtil.isNotBlank(file)) { + Path path = Paths.get(new File(file).getAbsolutePath()); + try { + bytes = Files.readAllBytes(path); + } catch (IOException e) { + throw new AutomationError(e); + } + } + return builder.method(bean.getMethod(), ClientResponse.class, bytes); + } + // raw body + return builder.method(bean.getMethod(), ClientResponse.class, body); + } else if (isFileUpload(bean.getFormParameters())) { + String fileName = ""; + // if contains file then upload as multipart/octet-stream as per + // Content-Type header + try (FormDataMultiPart multiPart = new FormDataMultiPart()) { + for (Entry entry : bean.getFormParameters().entrySet()) { + String value = String.valueOf(entry.getValue()); + if (value.startsWith("file:")) { + fileName = value.split("file:", 2)[1]; + multiPart.bodyPart(new FileDataBodyPart(entry.getKey(), new File(fileName))); + } else { + multiPart.field(entry.getKey(), value); + } + } + if (bean.getHeaders().containsValue(MediaType.APPLICATION_OCTET_STREAM)) { + Path path = Paths.get(new File(fileName).getAbsolutePath()); + return builder.type(MediaType.APPLICATION_OCTET_STREAM).method(bean.getMethod(), + ClientResponse.class, Files.readAllBytes(path)); + } else { + return builder.type(MediaType.MULTIPART_FORM_DATA).method(bean.getMethod(), ClientResponse.class, + multiPart); + } + } catch (Exception e) { + throw new AutomationError(e); + } + } else { + // does not contain files + MultivaluedMap formParam = new MultivaluedMapImpl(); + for (Entry entry : bean.getFormParameters().entrySet()) { + formParam.add(entry.getKey(), String.valueOf(entry.getValue())); + } + if (formParam.isEmpty()) { + return builder.method(bean.getMethod(), ClientResponse.class); + } else { + return builder.method(bean.getMethod(), ClientResponse.class, formParam); + } + } + } + + /** + * @param json + * @param path + * @return + */ + private static boolean hasJsonPath(String json, String path) { + try { + Object res = JsonPath.read(json, path); + JSONObject resObject = new JSONObject(res); + return !resObject.optBoolean("empty"); + } catch (Exception exception) { + return false; + } + } + + private static boolean isFileUpload(Map formParameters) { + for (Entry params : formParameters.entrySet()) { + String value = String.valueOf(params.getValue()).trim(); + if (value.startsWith("file:")) + return true; + } + return false; + } + + /** + * @param jsonpath + * @return + */ + private static String getPath(String jsonpath) { + if (!jsonpath.startsWith("$")) + jsonpath = "$." + jsonpath; + return jsonpath; + } + + private static StringMatcher getMatcher(Object o) { + if (o instanceof StringMatcher) + return (StringMatcher) o; + String s = o.toString(); + if (s.indexOf(':') > 0) { + String[] parts = s.split(":", 2); + StringMatcher m = StringMatcher.get(parts[0], parts[1]); + if (null != m) + return m; + } + return StringMatcher.exact(s); + } +} diff --git a/qaf-support-ws/src/main/java/com/qmetry/qaf/automation/step/aop.xml b/qaf-support-ws/src/main/java/com/qmetry/qaf/automation/step/aop.xml new file mode 100644 index 00000000..d15c7a63 --- /dev/null +++ b/qaf-support-ws/src/main/java/com/qmetry/qaf/automation/step/aop.xml @@ -0,0 +1,27 @@ + + + + + + \ No newline at end of file diff --git a/qaf-support-ws/src/main/java/com/qmetry/qaf/automation/ws/WSCRepositoryConstants.java b/qaf-support-ws/src/main/java/com/qmetry/qaf/automation/ws/WSCRepositoryConstants.java new file mode 100644 index 00000000..7f41bb37 --- /dev/null +++ b/qaf-support-ws/src/main/java/com/qmetry/qaf/automation/ws/WSCRepositoryConstants.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2019 Infostretch Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + ******************************************************************************/ +package com.qmetry.qaf.automation.ws; + +/** + * @author amit.bhoraniya + */ +public interface WSCRepositoryConstants { + String BASE_URL = "baseUrl"; + String END_POINT = "endPoint"; + String METHOD = "method"; + String BODY = "body"; + String SCHEMA = "schema"; + String HEADERS = "headers"; + String QUERY_PARAMETERS = "query-parameters"; + String FORM_PARAMETERS = "form-parameters"; + Object RESPONSE_SCHEMA = "response-schema"; + String REFERENCE = "reference"; + String PARAMETERS = "parameters"; +} diff --git a/qaf-support-ws/src/main/java/com/qmetry/qaf/automation/ws/WsRequestBean.java b/qaf-support-ws/src/main/java/com/qmetry/qaf/automation/ws/WsRequestBean.java new file mode 100644 index 00000000..5ca0f089 --- /dev/null +++ b/qaf-support-ws/src/main/java/com/qmetry/qaf/automation/ws/WsRequestBean.java @@ -0,0 +1,368 @@ +/******************************************************************************* + * Copyright (c) 2019 Infostretch Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + ******************************************************************************/ +package com.qmetry.qaf.automation.ws; + +import static com.qmetry.qaf.automation.core.ConfigurationManager.getBundle; + +import java.io.File; +import java.io.IOException; +import java.io.Serializable; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Map.Entry; + +import org.apache.commons.configuration.HierarchicalConfiguration.Node; +import org.apache.commons.configuration.tree.ConfigurationNode; +import org.apache.commons.lang.text.StrSubstitutor; +import org.json.JSONException; +import org.json.JSONObject; + +import com.google.gson.annotations.SerializedName; +import com.qmetry.qaf.automation.core.AutomationError; +import com.qmetry.qaf.automation.data.BaseDataBean; +import com.qmetry.qaf.automation.keys.ApplicationProperties; +import com.qmetry.qaf.automation.util.FileUtil; +import com.qmetry.qaf.automation.util.JSONUtil; +import com.qmetry.qaf.automation.util.StringMatcher; +import com.qmetry.qaf.automation.util.StringUtil; + +/** + * @author chirag.jayswal + */ +public class WsRequestBean extends BaseDataBean implements Serializable { + + /** + * + */ + private static final long serialVersionUID = 423394605353099602L; + + private String method = "GET"; + + private String baseUrl = ""; + + private String endPoint = ""; + + private Map headers = new HashMap(); + + private String[] accept = {}; + + private String schema = ""; + + private String body = ""; + + @SerializedName(value = WSCRepositoryConstants.QUERY_PARAMETERS) + private Map queryParameters = new HashMap(); + + @SerializedName(value = WSCRepositoryConstants.FORM_PARAMETERS) + private Map formParameters = new HashMap(); + + private Map parameters = new HashMap(); + + private String reference = ""; + + // private final transient Gson gson = getGson(); + + public String getBaseUrl() { + return StringUtil.isNotBlank(baseUrl) ? baseUrl : ApplicationProperties.SELENIUM_BASE_URL.getStringVal(""); + } + + public void setBaseUrl(String baseUrl) { + this.baseUrl = baseUrl; + } + + public String getMethod() { + return method; + } + + public void setMethod(String method) { + this.method = method; + } + + public Map getHeaders() { + return headers; + } + + public void setHeaders(Map headers) { + this.headers = headers; + } + + public String getBody() { + return body; + } + + public void setBody(String body) { + this.body = body; + } + + public Map getQueryParameters() { + return queryParameters; + } + + public void setQueryParameters(Map parameters) { + this.queryParameters = parameters; + } + + public String getEndPoint() { + return endPoint; + } + + public void setEndPoint(String endpoint) { + this.endPoint = endpoint; + } + + public String[] getAccept() { + return accept; + } + + public void setAccept(String[] accept) { + this.accept = accept; + } + + public String getSchema() { + return schema; + } + + public void setSchema(String schema) { + this.schema = schema; + } + + public Map getFormParameters() { + return formParameters; + } + + public void setFormParameters(Map formParameters) { + this.formParameters = formParameters; + } + + public Map getParameters() { + return parameters; + } + + public void setParameters(Map parameters) { + this.parameters = parameters; + } + + public String getReference() { + return reference; + } + + public void setReference(String reference) { + this.reference = reference; + } + + /** + * Priority for resolver is: + *

    + *
  1. data provided in argument + *
  2. parameter in request call + *
  3. parameter in request reference + *
  4. configuration property + *
+ * To ignore specific query or form parameter provide blank ('') value for that key. + * @param data + */ + public void resolveParameters(Map data) { + + JSONObject j = new JSONObject(this); + j.remove("reference"); + String source = j.toString(); + + // highest: data provided in argument while doing request + if (null != data && !data.isEmpty()) { + source = StrSubstitutor.replace(source, data); + } + //second: configuration manager + source = getBundle().getSubstitutor().replace(source); + + fillFromJsonString(source); + + // lowest: default value in request call + if (null != getParameters() && !getParameters().isEmpty()) { + source = StrSubstitutor.replace(source, getParameters()); + fillFromJsonString(source); + } + // body from file? + if (StringUtil.isNotBlank(body) && StringMatcher.startsWithIgnoringCase("file:").match(body)) { + String file = body.split(":", 2)[1].trim(); + try { + body = FileUtil.readFileToString(new File(file), StandardCharsets.UTF_8); + resolveParameters(data); + } catch (IOException e) { + throw new AutomationError("Unable to read file: " + file, e); + } + }else { + removeNulls(formParameters); + removeNulls(queryParameters); + removeNulls(headers); + } + } + + + + @SuppressWarnings("unchecked") + @Override + public void fillData(Object obj) { + try { + boolean isString = (obj instanceof String); + if(obj instanceof Map) { + fillData((Map)obj); + }else if (isString && (getBundle().containsKey((String) obj) || !getBundle().subset((String) obj).isEmpty())) { + fillFromConfig((String) obj); + + } else { + String jsonStr = (isString ? (String) obj : JSONUtil.toString(obj)); + fillFromJsonString(jsonStr); + } + } catch (Exception e) { + throw new AutomationError("Unable to populate request from" + obj, e); + } + } + + @Override + public void fillFromConfig(String reqkey) { + ConfigurationNode node = getBundle().configurationAt(reqkey).getRootNode(); + if (node.getValue()!=null) { + fillFromJsonString((String)node.getValue()); + } else { + Map map = nodeToMap(node); + fillData(map); + } + } + + private Map nodeToMap(ConfigurationNode node){ + Map map = new HashMap(); + Iterator nodes = node.getChildren().iterator(); + while (nodes.hasNext()) { + Node cNode = (Node) nodes.next(); + if (!cNode.hasChildren()) { + map.put(cNode.getName(), cNode.getValue()); + }else { + map.put(cNode.getName(), nodeToMap(cNode)); + } + } + return map; + } + + + @Override + public void fillData(Map map) { + if (map.containsKey(WSCRepositoryConstants.REFERENCE)) { + fillFromConfig((String)map.get(WSCRepositoryConstants.REFERENCE)); + } + + updateKey(map, WSCRepositoryConstants.FORM_PARAMETERS, "formParameters"); + updateKey(map, WSCRepositoryConstants.QUERY_PARAMETERS, "queryParameters"); + + super.fillData(map); + } + + /** + * fill bean from json data. + * + * @param jsonstr + */ + public void fillFromJsonString(String jsonstr) { + try { + JSONObject jsonObject = new JSONObject(jsonstr); + String[] keys = JSONObject.getNames(jsonObject); + if (null != keys) { + Map map = new HashMap(); + for (String key : keys) { + try { + map.put(key, jsonObject.getJSONObject(key).toString()); + } catch (Exception e) { + map.put(key, jsonObject.get(key).toString()); + } + } + fillData(map); + } + } catch (JSONException e) { + throw new AutomationError(jsonstr + " is not valid Json", e); + } + + } + + public void setFormParameters(String val) { + setMap(val, formParameters); + } + + public void setQueryParameters(String val) { + setMap(val, queryParameters); + } + + public void setHeaders(String val) { + setMap(val, headers); + } + + public void setParameters(String val) { + setMap(val, parameters); + } + + private void setMap(String val, Map map) { + if (StringUtil.isNotBlank(val)) { + map.putAll(JSONUtil.toMap(val)); + } + } + + private void updateKey(Map map, String oldKey, String newKey) { + if (map.containsKey(oldKey)) { + Object value = map.remove(oldKey); + map.put(newKey, value); + } + } + + private void removeNulls(Map map) { + // clear null values + Iterator> itr = map.entrySet().iterator(); + while (itr.hasNext()) { + Entry entry = itr.next(); + if (entry.getValue() == null ){ + //keep blank values as that may be intention to test + itr.remove(); + } + } + } + + public static void main(String[] args) { + getBundle().setProperty("env.baseurl", "http://httpbin.org"); + getBundle().setProperty("get.sample.ref", + "{'headers':{},'endPoint':'/post','baseUrl':'${env.baseurl}','method':'POST','query-parameters':{'param1':'${val1}','param2':'${val2}'},'form-parameters':{'a':'b','i':'${i}','j':'${j}','k':10.01},'body':'','parameters':{'val1':'abc','val2':'xyz','i':10,'j':20}}"); + + getBundle().setProperty("get.sample.call", + "{'reference':'get.sample.ref','parameters':{'val1':'','val3':'xyz123','i':20,'j':''},'body':'fileabcd123'}"); + WsRequestBean r = new WsRequestBean(); + r.fillData("get.sample.call"); + + System.out.println(r); + + r.resolveParameters(null); + System.out.println(r); + + //System.out.println(WsStep.userRequests(r).getEntity(String.class)); + } + + public String toString() { + return JSONUtil.toString(this); + } +} diff --git a/qaf-support-ws/src/main/java/com/qmetry/qaf/automation/ws/auth/oauth/Base64Encoded.java b/qaf-support-ws/src/main/java/com/qmetry/qaf/automation/ws/auth/oauth/Base64Encoded.java new file mode 100644 index 00000000..370a38be --- /dev/null +++ b/qaf-support-ws/src/main/java/com/qmetry/qaf/automation/ws/auth/oauth/Base64Encoded.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2019 Infostretch Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + ******************************************************************************/ +package com.qmetry.qaf.automation.ws.auth.oauth; + +import org.apache.commons.codec.binary.Base64; + +public class Base64Encoded { + + public static void main(String...strings){ + + String clientId = "SuperOAuthArticle"; + String clientSecret = "YourFeedbackIsAppreciated"; + System.out.println(encodeCredentials(clientId, clientSecret)); + + } + + public static String encodeCredentials(String username, String password) { + String cred = username + ":" + password; + String encodedValue = null; + byte[] encodedBytes = Base64.encodeBase64(cred.getBytes()); + encodedValue = new String(encodedBytes); + System.out.println("encodedBytes " + new String(encodedBytes)); + + byte[] decodedBytes = Base64.decodeBase64(encodedBytes); + System.out.println("decodedBytes " + new String(decodedBytes)); + + return encodedValue; + + } + +} diff --git a/qaf-support-ws/src/main/java/com/qmetry/qaf/automation/ws/auth/oauth/OAuth2Details.java b/qaf-support-ws/src/main/java/com/qmetry/qaf/automation/ws/auth/oauth/OAuth2Details.java new file mode 100644 index 00000000..4a695f1e --- /dev/null +++ b/qaf-support-ws/src/main/java/com/qmetry/qaf/automation/ws/auth/oauth/OAuth2Details.java @@ -0,0 +1,105 @@ +/******************************************************************************* + * Copyright (c) 2019 Infostretch Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + ******************************************************************************/ +package com.qmetry.qaf.automation.ws.auth.oauth; +public class OAuth2Details { + + private String scope; + private String grantType; + private String clientId; + private String clientSecret; + private String accessToken; + private String refreshToken; + private String username; + private String password; + private String authenticationServerUrl; + private String resourceServerUrl; + private boolean isAccessTokenRequest; + + + + public String getScope() { + return scope; + } + public void setScope(String scope) { + this.scope = scope; + } + public String getGrantType() { + return grantType; + } + public void setGrantType(String grantType) { + this.grantType = grantType; + } + public String getClientId() { + return clientId; + } + public void setClientId(String clientId) { + this.clientId = clientId; + } + public String getClientSecret() { + return clientSecret; + } + public void setClientSecret(String clientSecret) { + this.clientSecret = clientSecret; + } + public String getAccessToken() { + return accessToken; + } + public void setAccessToken(String accessToken) { + this.accessToken = accessToken; + } + public String getRefreshToken() { + return refreshToken; + } + public void setRefreshToken(String refreshToken) { + this.refreshToken = refreshToken; + } + public String getAuthenticationServerUrl() { + return authenticationServerUrl; + } + public void setAuthenticationServerUrl(String authenticationServerUrl) { + this.authenticationServerUrl = authenticationServerUrl; + } + public String getUsername() { + return username; + } + public void setUsername(String username) { + this.username = username; + } + public String getPassword() { + return password; + } + public void setPassword(String password) { + this.password = password; + } + public boolean isAccessTokenRequest() { + return isAccessTokenRequest; + } + public void setAccessTokenRequest(boolean isAccessTokenRequest) { + this.isAccessTokenRequest = isAccessTokenRequest; + } + public String getResourceServerUrl() { + return resourceServerUrl; + } + public void setResourceServerUrl(String resourceServerUrl) { + this.resourceServerUrl = resourceServerUrl; + } +} diff --git a/qaf-support-ws/src/main/java/com/qmetry/qaf/automation/ws/auth/oauth/OAuthConstants.java b/qaf-support-ws/src/main/java/com/qmetry/qaf/automation/ws/auth/oauth/OAuthConstants.java new file mode 100644 index 00000000..9d94d138 --- /dev/null +++ b/qaf-support-ws/src/main/java/com/qmetry/qaf/automation/ws/auth/oauth/OAuthConstants.java @@ -0,0 +1,53 @@ +/******************************************************************************* + * Copyright (c) 2019 Infostretch Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + ******************************************************************************/ +package com.qmetry.qaf.automation.ws.auth.oauth; + +public class OAuthConstants { + public static final String PREFIX_KEY = "rest.client.oauth.auth."; + public static final String ACCESS_TOKEN = PREFIX_KEY + "access_token"; + public static final String CLIENT_ID = PREFIX_KEY + "client_id"; + public static final String CLIENT_SECRET = PREFIX_KEY + "client_secret"; + public static final String REFRESH_TOKEN = PREFIX_KEY + "refresh_token"; + public static final String USERNAME = PREFIX_KEY + "username"; + public static final String PASSWORD = PREFIX_KEY + "password"; + public static final String AUTHENTICATION_SERVER_URL = + PREFIX_KEY + "authentication_server_url"; + public static final String RESOURCE_SERVER_URL = PREFIX_KEY + "resource_server_url"; + public static final String GRANT_TYPE = PREFIX_KEY + "grant_type"; + public static final String CODE = "code"; + public static final String CALLER = "caller"; + public static final String GRANT_TYPE_PASSWORD = "password"; + public static final String GRANT_TYPE_AUTHORIZATION_CODE = "authorization_code"; + public static final String GRANT_TYPE_CLIENT_CREDENTIALS = "client_credentials"; + public static final String SCOPE = "scope"; + public static final String AUTHORIZATION = "Authorization"; + public static final String BEARER = "Bearer"; + public static final String BASIC = "Basic"; + public static final String JSON_CONTENT = "application/json"; + public static final String XML_CONTENT = "application/xml"; + public static final String URL_ENCODED_CONTENT = "application/x-www-form-urlencoded"; + + public static final int HTTP_OK = 200; + public static final int HTTP_FORBIDDEN = 403; + public static final int HTTP_UNAUTHORIZED = 401; + +} diff --git a/qaf-support-ws/src/main/java/com/qmetry/qaf/automation/ws/auth/oauth/OAuthUtils.java b/qaf-support-ws/src/main/java/com/qmetry/qaf/automation/ws/auth/oauth/OAuthUtils.java new file mode 100644 index 00000000..2a8cd16a --- /dev/null +++ b/qaf-support-ws/src/main/java/com/qmetry/qaf/automation/ws/auth/oauth/OAuthUtils.java @@ -0,0 +1,416 @@ +/******************************************************************************* + * Copyright (c) 2019 Infostretch Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + ******************************************************************************/ +package com.qmetry.qaf.automation.ws.auth.oauth; + +import java.io.IOException; +import java.io.InputStream; +import java.io.StringReader; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; + +import org.apache.commons.codec.binary.Base64; +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.NameValuePair; +import org.apache.http.ParseException; +import org.apache.http.client.ClientProtocolException; +import org.apache.http.client.entity.UrlEncodedFormEntity; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.client.utils.URLEncodedUtils; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.message.BasicNameValuePair; +import org.apache.http.util.EntityUtils; +import org.json.simple.parser.JSONParser; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; +import org.xml.sax.InputSource; + +import com.qmetry.qaf.automation.util.PropertyUtil; + +public class OAuthUtils { + + public static OAuth2Details createOAuthDetails(PropertyUtil propertyUtil) { + OAuth2Details oauthDetails = new OAuth2Details(); + oauthDetails.setAccessToken(propertyUtil.getString(OAuthConstants.ACCESS_TOKEN)); + oauthDetails + .setRefreshToken(propertyUtil.getString(OAuthConstants.REFRESH_TOKEN)); + oauthDetails.setGrantType(propertyUtil.getString(OAuthConstants.GRANT_TYPE)); + oauthDetails.setClientId(propertyUtil.getString(OAuthConstants.CLIENT_ID)); + oauthDetails + .setClientSecret(propertyUtil.getString(OAuthConstants.CLIENT_SECRET)); + oauthDetails.setScope(propertyUtil.getString(OAuthConstants.SCOPE)); + oauthDetails.setAuthenticationServerUrl( + propertyUtil.getString(OAuthConstants.AUTHENTICATION_SERVER_URL)); + oauthDetails.setUsername(propertyUtil.getString(OAuthConstants.USERNAME)); + oauthDetails.setPassword(propertyUtil.getString(OAuthConstants.PASSWORD)); + oauthDetails.setResourceServerUrl( + propertyUtil.getString(OAuthConstants.RESOURCE_SERVER_URL)); + + if (!isValid(oauthDetails.getResourceServerUrl())) { + System.out.println( + "Resource server url is null. Will assume request is for generating Access token"); + oauthDetails.setAccessTokenRequest(true); + } + + return oauthDetails; + } + + public static Properties getClientConfigProps(String path) { + InputStream is = OAuthUtils.class.getClassLoader().getResourceAsStream(path); + Properties config = new Properties(); + try { + config.load(is); + } catch (IOException e) { + System.out.println("Could not load properties from " + path); + e.printStackTrace(); + return null; + } + return config; + } + + public static void getProtectedResource(OAuth2Details oauthDetails) { + String resourceURL = oauthDetails.getResourceServerUrl(); + + HttpGet get = new HttpGet(resourceURL); + get.addHeader(OAuthConstants.AUTHORIZATION, + getAuthorizationHeaderForAccessToken(oauthDetails.getAccessToken())); + CloseableHttpClient client = HttpClientBuilder.create().build(); + HttpResponse response = null; + int code = -1; + try { + response = client.execute(get); + code = response.getStatusLine().getStatusCode(); + if (code == 401 || code == 403) { + // Access token is invalid or expired.Regenerate the access + // token + System.out.println( + "Access token is invalid or expired. Regenerating access token...."); + String accessToken = getAccessToken(oauthDetails); + if (isValid(accessToken)) { + // update the access token + // System.out.println("New access token: " + accessToken); + oauthDetails.setAccessToken(accessToken); + get.removeHeaders(OAuthConstants.AUTHORIZATION); + get.addHeader(OAuthConstants.AUTHORIZATION, + getAuthorizationHeaderForAccessToken( + oauthDetails.getAccessToken())); + get.releaseConnection(); + response = client.execute(get); + code = response.getStatusLine().getStatusCode(); + if (code >= 400) { + throw new RuntimeException( + "Could not access protected resource. Server returned http code: " + + code); + + } + + } else { + throw new RuntimeException("Could not regenerate access token"); + } + + } + + handleResponse(response); + + } catch (ClientProtocolException e) { + e.printStackTrace(); + } catch (IOException e) { + + e.printStackTrace(); + } finally { + get.releaseConnection(); + } + + } + + public static String getAccessToken(OAuth2Details oauthDetails) { + HttpPost post = new HttpPost(oauthDetails.getAuthenticationServerUrl()); + String clientId = oauthDetails.getClientId(); + String clientSecret = oauthDetails.getClientSecret(); + String scope = oauthDetails.getScope(); + + List parametersBody = new ArrayList(); + parametersBody.add(new BasicNameValuePair( + OAuthConstants.GRANT_TYPE.replace(OAuthConstants.PREFIX_KEY, ""), + oauthDetails.getGrantType())); + + parametersBody.add(new BasicNameValuePair( + OAuthConstants.CLIENT_ID.replace(OAuthConstants.PREFIX_KEY, ""), + clientId)); + + parametersBody.add(new BasicNameValuePair( + OAuthConstants.CLIENT_SECRET.replace(OAuthConstants.PREFIX_KEY, ""), + clientSecret)); + + if (isValid(scope)) { + parametersBody.add(new BasicNameValuePair( + OAuthConstants.SCOPE.replace(OAuthConstants.PREFIX_KEY, ""), scope)); + } + CloseableHttpClient client = HttpClientBuilder.create().build(); + HttpResponse response = null; + String accessToken = null; + try { + post.setEntity(new UrlEncodedFormEntity(parametersBody, "UTF-8")); + + response = client.execute(post); + int code = response.getStatusLine().getStatusCode(); + if (code == OAuthConstants.HTTP_UNAUTHORIZED) { + System.out.println("Authorization server expects Basic authentication"); + // Add Basic Authorization header + post.addHeader(OAuthConstants.AUTHORIZATION, getBasicAuthorizationHeader( + oauthDetails.getClientId(), oauthDetails.getClientSecret())); + System.out.println("Retry with client credentials"); + post.releaseConnection(); + response = client.execute(post); + code = response.getStatusLine().getStatusCode(); + if (code == 401 || code == 403) { + System.out + .println("Could not authenticate using client credentials."); + throw new RuntimeException( + "Could not retrieve access token for client: " + + oauthDetails.getClientId()); + + } + + } + Map map = handleResponse(response); + accessToken = map.get(OAuthConstants.ACCESS_TOKEN.replace(OAuthConstants.PREFIX_KEY, "")); + } catch (ClientProtocolException e) { + + e.printStackTrace(); + } catch (IOException e) { + + e.printStackTrace(); + } + + return accessToken; + } + + public static Map handleResponse(HttpResponse response) { + String contentType = OAuthConstants.JSON_CONTENT; + if (response.getEntity().getContentType() != null) { + contentType = response.getEntity().getContentType().getValue(); + } + if (contentType.contains(OAuthConstants.JSON_CONTENT)) { + return handleJsonResponse(response); + } else if (contentType.contains(OAuthConstants.URL_ENCODED_CONTENT)) { + return handleURLEncodedResponse(response); + } else if (contentType.contains(OAuthConstants.XML_CONTENT)) { + return handleXMLResponse(response); + } else { + // Unsupported Content type + throw new RuntimeException("Cannot handle " + contentType + + " content type. Supported content types include JSON, XML and URLEncoded"); + } + + } + + @SuppressWarnings("unchecked") + public static Map handleJsonResponse(HttpResponse response) { + Map oauthLoginResponse = null; + // String contentType = + // response.getEntity().getContentType().getValue(); + try { + oauthLoginResponse = (Map) new JSONParser() + .parse(EntityUtils.toString(response.getEntity())); + } catch (ParseException e) { + + e.printStackTrace(); + throw new RuntimeException(); + } catch (org.json.simple.parser.ParseException e) { + + e.printStackTrace(); + throw new RuntimeException(); + } catch (IOException e) { + + e.printStackTrace(); + throw new RuntimeException(); + } catch (RuntimeException e) { + System.out.println("Could not parse JSON response"); + throw e; + } + System.out.println(); + System.out.println("********** Response Received **********"); + for (Map.Entry entry : oauthLoginResponse.entrySet()) { + System.out.println( + String.format(" %s = %s", entry.getKey(), entry.getValue())); + } + return oauthLoginResponse; + } + + public static Map handleURLEncodedResponse(HttpResponse response) { + Map map = Charset.availableCharsets(); + Map oauthResponse = new HashMap(); + Set> set = map.entrySet(); + HttpEntity entity = response.getEntity(); + + System.out.println(); + System.out.println("********** Response Received **********"); + + for (Map.Entry entry : set) { + System.out.println( + String.format(" %s = %s", entry.getKey(), entry.getValue())); + if (entry.getKey().equalsIgnoreCase("UTF-8")) { + // charset = entry.getValue(); + } + } + + try { + List list = URLEncodedUtils.parse(EntityUtils.toString(entity), + Charset.forName("UTF-8")); + for (NameValuePair pair : list) { + System.out.println( + String.format(" %s = %s", pair.getName(), pair.getValue())); + oauthResponse.put(pair.getName(), pair.getValue()); + } + + } catch (IOException e) { + + e.printStackTrace(); + throw new RuntimeException("Could not parse URLEncoded Response"); + } + + return oauthResponse; + } + + public static Map handleXMLResponse(HttpResponse response) { + Map oauthResponse = new HashMap(); + try { + + String xmlString = EntityUtils.toString(response.getEntity()); + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + DocumentBuilder db = factory.newDocumentBuilder(); + InputSource inStream = new InputSource(); + inStream.setCharacterStream(new StringReader(xmlString)); + Document doc = db.parse(inStream); + + System.out.println("********** Response Receieved **********"); + parseXMLDoc(null, doc, oauthResponse); + } catch (Exception e) { + e.printStackTrace(); + throw new RuntimeException("Exception occurred while parsing XML response"); + } + return oauthResponse; + } + + public static void parseXMLDoc(Element element, Document doc, + Map oauthResponse) { + NodeList child = null; + if (element == null) { + child = doc.getChildNodes(); + + } else { + child = element.getChildNodes(); + } + for (int j = 0; j < child.getLength(); j++) { + if (child.item(j).getNodeType() == org.w3c.dom.Node.ELEMENT_NODE) { + org.w3c.dom.Element childElement = (org.w3c.dom.Element) child.item(j); + if (childElement.hasChildNodes()) { + System.out.println(childElement.getTagName() + " : " + + childElement.getTextContent()); + oauthResponse.put(childElement.getTagName(), + childElement.getTextContent()); + parseXMLDoc(childElement, null, oauthResponse); + } + + } + } + } + + public static String getAuthorizationHeaderForAccessToken(String accessToken) { + return OAuthConstants.BEARER + " " + accessToken; + } + + public static String getBasicAuthorizationHeader(String username, String password) { + return OAuthConstants.BASIC + " " + encodeCredentials(username, password); + } + + public static String encodeCredentials(String username, String password) { + String cred = username + ":" + password; + String encodedValue = null; + byte[] encodedBytes = Base64.encodeBase64(cred.getBytes()); + encodedValue = new String(encodedBytes); + System.out.println("encodedBytes " + new String(encodedBytes)); + + byte[] decodedBytes = Base64.decodeBase64(encodedBytes); + System.out.println("decodedBytes " + new String(decodedBytes)); + + return encodedValue; + + } + + public static boolean isValidInput(OAuth2Details input) { + + if (input == null) { + return false; + } + + String grantType = input.getGrantType(); + + if (!isValid(grantType)) { + System.out.println("Please provide valid value for grant_type"); + return false; + } + + if (!isValid(input.getAuthenticationServerUrl())) { + System.out + .println("Please provide valid value for authentication server url"); + return false; + } + + if (grantType.equals(OAuthConstants.GRANT_TYPE_PASSWORD)) { + if (!isValid(input.getUsername()) || !isValid(input.getPassword())) { + System.out.println( + "Please provide valid username and password for password grant_type"); + return false; + } + } + + if (grantType.equals(OAuthConstants.GRANT_TYPE_CLIENT_CREDENTIALS)) { + if (!isValid(input.getClientId()) || !isValid(input.getClientSecret())) { + System.out.println( + "Please provide valid client_id and client_secret for client_credentials grant_type"); + return false; + } + } + + System.out.println("Validated Input"); + return true; + + } + + public static boolean isValid(String str) { + return (str != null && str.trim().length() > 0); + } + +} diff --git a/qaf-support-ws/src/main/java/com/qmetry/qaf/automation/ws/client/BasicAuthWsClient.java b/qaf-support-ws/src/main/java/com/qmetry/qaf/automation/ws/client/BasicAuthWsClient.java new file mode 100644 index 00000000..923a24e0 --- /dev/null +++ b/qaf-support-ws/src/main/java/com/qmetry/qaf/automation/ws/client/BasicAuthWsClient.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright (c) 2019 Infostretch Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + ******************************************************************************/ +package com.qmetry.qaf.automation.ws.client; + +import com.qmetry.qaf.automation.core.ConfigurationManager; +import com.qmetry.qaf.automation.ws.rest.DefaultRestClient; +import com.sun.jersey.api.client.Client; +import com.sun.jersey.api.client.filter.HTTPBasicAuthFilter; + +public class BasicAuthWsClient extends DefaultRestClient { + + public static final String REST_CLIENT_BASIC_AUTH_USER = + "rest.client.basic.auth.username"; + public static final String REST_CLIENT_BASIC_AUTH_PASSWORD = + "rest.client.basic.auth.password"; + + @Override + protected Client createClient() { + + Client client = super.createClient(); + client.getProperties().put("jersey.config.client.followRedirects", true); + client.addFilter(new HTTPBasicAuthFilter( + ConfigurationManager.getBundle().getString(REST_CLIENT_BASIC_AUTH_USER, + ""), + ConfigurationManager.getBundle() + .getString(REST_CLIENT_BASIC_AUTH_PASSWORD, ""))); + return client; + } +} diff --git a/qaf-support-ws/src/main/java/com/qmetry/qaf/automation/ws/client/DigestAuthWsClient.java b/qaf-support-ws/src/main/java/com/qmetry/qaf/automation/ws/client/DigestAuthWsClient.java new file mode 100644 index 00000000..bd08028f --- /dev/null +++ b/qaf-support-ws/src/main/java/com/qmetry/qaf/automation/ws/client/DigestAuthWsClient.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright (c) 2019 Infostretch Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + ******************************************************************************/ +package com.qmetry.qaf.automation.ws.client; + +import com.qmetry.qaf.automation.core.ConfigurationManager; +import com.qmetry.qaf.automation.ws.rest.DefaultRestClient; +import com.sun.jersey.api.client.Client; +import com.sun.jersey.api.client.filter.HTTPDigestAuthFilter; + +public class DigestAuthWsClient extends DefaultRestClient { + + public static final String REST_CLIENT_DIGEST_AUTH_USER = "rest.client.digest.auth.username"; + public static final String REST_CLIENT_DIGEST_AUTH_PASSWORD = "rest.client.digest.auth.password"; + + @Override + protected Client createClient() { + Client client = super.createClient(); + client.addFilter( + new HTTPDigestAuthFilter(ConfigurationManager.getBundle().getString(REST_CLIENT_DIGEST_AUTH_USER, ""), + ConfigurationManager.getBundle().getString(REST_CLIENT_DIGEST_AUTH_PASSWORD, ""))); + return client; + } +} diff --git a/qaf-support-ws/src/main/java/com/qmetry/qaf/automation/ws/client/HawkAuthWsClient.java b/qaf-support-ws/src/main/java/com/qmetry/qaf/automation/ws/client/HawkAuthWsClient.java new file mode 100644 index 00000000..02fb07ed --- /dev/null +++ b/qaf-support-ws/src/main/java/com/qmetry/qaf/automation/ws/client/HawkAuthWsClient.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * Copyright (c) 2019 Infostretch Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + ******************************************************************************/ +package com.qmetry.qaf.automation.ws.client; + +import com.qmetry.qaf.automation.ws.rest.DefaultRestClient; +import com.sun.jersey.api.client.Client; +import com.wealdtech.hawk.HawkClient; +import com.wealdtech.hawk.HawkCredentials; +import com.wealdtech.hawk.jersey.HawkAuthorizationFilter; + +public class HawkAuthWsClient extends DefaultRestClient { + + public static final String REST_CLIENT_HAWK_KEY_ID = "rest.client.hawk.auth.keyId"; + public static final String REST_CLIENT_HAWK_KEY = "rest.client.hawk.auth.key"; + + @Override + protected Client createClient() { + + HawkCredentials hawkCredentials = new HawkCredentials.Builder() + .keyId(REST_CLIENT_HAWK_KEY_ID).key(REST_CLIENT_HAWK_KEY) + .algorithm(HawkCredentials.Algorithm.SHA256).build(); + + HawkClient hawkClient = + new HawkClient.Builder().credentials(hawkCredentials).build(); + + Client client = super.createClient(); + client.addFilter(new HawkAuthorizationFilter(hawkClient)); + return client; + } +} diff --git a/qaf-support-ws/src/main/java/com/qmetry/qaf/automation/ws/client/NTLMAuthClient.java b/qaf-support-ws/src/main/java/com/qmetry/qaf/automation/ws/client/NTLMAuthClient.java new file mode 100644 index 00000000..66528992 --- /dev/null +++ b/qaf-support-ws/src/main/java/com/qmetry/qaf/automation/ws/client/NTLMAuthClient.java @@ -0,0 +1,88 @@ +/******************************************************************************* + * Copyright (c) 2019 Infostretch Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + ******************************************************************************/ +package com.qmetry.qaf.automation.ws.client; + +import java.util.Arrays; + +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.NTCredentials; +import org.apache.http.client.CredentialsProvider; +import org.apache.http.client.config.AuthSchemes; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.impl.client.BasicCookieStore; +import org.apache.http.impl.client.BasicCredentialsProvider; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; + +import com.qmetry.qaf.automation.ws.rest.RestClientFactory; +import com.sun.jersey.api.client.Client; +import com.sun.jersey.client.apache4.ApacheHttpClient4Handler; +import static com.qmetry.qaf.automation.core.ConfigurationManager.getBundle; + +/** + * Jersey client to support NTLM authentication. This class uses following properties: + *
    + *
  • ntlm.user - The user name. This should not include the domain to authenticate with. For example: "user" is correct whereas "DOMAIN\\user" is not. + *
  • ntlm.password - The password + *
  • ntlm.workstation - workstation (default is blank) The workstation the authentication request is originating from. Essentially, the computer name for this machine. + *
  • ntlm.domain- domain The domain to authenticate within (default is blank). + *
+ * + * For NTLM authentication, register this class using rest.client.impl property as below: + *

+ * rest.client.impl=com.qmetry.qaf.automation.ws.client.NTLMAuthClient + * + * @author Chirag Jayswal + * @since 2.1.12 + */ +public class NTLMAuthClient extends RestClientFactory { + + private static final String USERNAME = getBundle().getString("ntlm.user"); + private static final String PASSWORD = getBundle().getString("ntlm.password"); + private static final String WORKSTATION = getBundle().getString("ntlm.workstation",""); + private static final String DOMAIN = getBundle().getString("ntlm.domain",""); + + @Override + protected Client createClient() { + PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(); + + RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(30000) + .setConnectionRequestTimeout(30000) + .setTargetPreferredAuthSchemes(Arrays.asList(AuthSchemes.NTLM)) + .setProxyPreferredAuthSchemes(Arrays.asList(AuthSchemes.BASIC)) + .build(); + + CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); + credentialsProvider.setCredentials(AuthScope.ANY, new NTCredentials(USERNAME, PASSWORD, WORKSTATION, DOMAIN)); + + CloseableHttpClient closeableHttpClient = HttpClients.custom().setConnectionManager(cm) + .setDefaultCredentialsProvider(credentialsProvider) + .setDefaultRequestConfig(requestConfig) + .build(); + + ApacheHttpClient4Handler root = new ApacheHttpClient4Handler(closeableHttpClient, new BasicCookieStore(), false); + Client client = new Client(root); + return client; + } + +} diff --git a/qaf-support-ws/src/main/java/com/qmetry/qaf/automation/ws/client/OAuthWsClient.java b/qaf-support-ws/src/main/java/com/qmetry/qaf/automation/ws/client/OAuthWsClient.java new file mode 100644 index 00000000..527bbe22 --- /dev/null +++ b/qaf-support-ws/src/main/java/com/qmetry/qaf/automation/ws/client/OAuthWsClient.java @@ -0,0 +1,85 @@ +/******************************************************************************* + * Copyright (c) 2019 Infostretch Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + ******************************************************************************/ +package com.qmetry.qaf.automation.ws.client; + +import com.qmetry.qaf.automation.core.ConfigurationManager; +import com.qmetry.qaf.automation.util.StringUtil; +import com.qmetry.qaf.automation.ws.auth.oauth.OAuth2Details; +import com.qmetry.qaf.automation.ws.auth.oauth.OAuthConstants; +import com.qmetry.qaf.automation.ws.auth.oauth.OAuthUtils; +import com.qmetry.qaf.automation.ws.rest.DefaultRestClient; +import com.sun.jersey.api.client.Client; +import com.sun.jersey.api.client.ClientHandlerException; +import com.sun.jersey.api.client.ClientRequest; +import com.sun.jersey.api.client.ClientResponse; +import com.sun.jersey.api.client.filter.ClientFilter; + +public class OAuthWsClient extends DefaultRestClient { + + @Override + protected Client createClient() { + Client client = super.createClient(); + client.addFilter(new ClientFilter() { + + public ClientResponse handle(ClientRequest cr) throws ClientHandlerException { + cr.getHeaders().add(OAuthConstants.AUTHORIZATION, OAuthUtils + .getAuthorizationHeaderForAccessToken(getAccessToken())); + return getNext().handle(cr); + } + + private String getAccessToken() { + String accessToken = ConfigurationManager.getBundle() + .getString(OAuthConstants.ACCESS_TOKEN); + if (StringUtil.isEmpty(accessToken)) { + // Generate the OAuthDetails bean from the config properties + // file + OAuth2Details oauthDetails = OAuthUtils + .createOAuthDetails(ConfigurationManager.getBundle()); + + System.out.println(oauthDetails); + // Validate Input + if (!OAuthUtils.isValidInput(oauthDetails)) { + System.out.println( + "Please provide valid config properties to continue."); + System.exit(0); + } + + // Generate new Access token + accessToken = OAuthUtils.getAccessToken(oauthDetails); + + if (OAuthUtils.isValid(accessToken)) { + ConfigurationManager.getBundle() + .setProperty(OAuthConstants.ACCESS_TOKEN, accessToken); + System.out.println( + "Successfully generated Access token for client_credentials grant_type: " + + accessToken); + } else { + System.out.println( + "Could not generate Access token for client_credentials grant_type"); + } + } + return accessToken; + } + }); + return client; + } +} diff --git a/qaf-support-ws/src/test/java/com/qmetry/qaf/automation/ws/tests/WSRTestSuite.java b/qaf-support-ws/src/test/java/com/qmetry/qaf/automation/ws/tests/WSRTestSuite.java new file mode 100644 index 00000000..48ce9dc5 --- /dev/null +++ b/qaf-support-ws/src/test/java/com/qmetry/qaf/automation/ws/tests/WSRTestSuite.java @@ -0,0 +1,38 @@ +package com.qmetry.qaf.automation.ws.tests; +import static com.qmetry.qaf.automation.core.ConfigurationManager.getBundle; + +import org.hamcrest.Matchers; +import org.testng.annotations.Test; + +import com.qmetry.qaf.automation.core.ConfigurationManager; +import com.qmetry.qaf.automation.data.MetaData; +import com.qmetry.qaf.automation.util.Validator; +import com.qmetry.qaf.automation.ws.WsRequestBean; +/** + * @author chirag.jayswal + * + */ +public class WSRTestSuite { + + @Test + public void test1(){ + WsRequestBean bean = new WsRequestBean(); + bean.fillData("sample"); + bean.resolveParameters(null); + Validator.verifyThat(bean.getBaseUrl(), Matchers.equalTo(getBundle().getString("reference.baseUrl"))); + Validator.verifyThat(bean.getEndPoint(), Matchers.equalTo(getBundle().getString("sample.endpoint"))); + System.out.println(bean); + } + + @MetaData("{'bug':'#11'}") + @Test + public void test2(){ + WsRequestBean bean = new WsRequestBean(); + bean.fillData("overrideheaders"); + bean.resolveParameters(null); + Validator.verifyThat(bean.getBaseUrl(), Matchers.equalTo(getBundle().getString("reference.baseUrl"))); + Validator.verifyThat(bean.getHeaders().get("Content-type").toString(), Matchers.equalTo("application/xml")); + System.out.println(bean); + } + +} diff --git a/qaf-support/pom.xml b/qaf-support/pom.xml new file mode 100644 index 00000000..28a44a6e --- /dev/null +++ b/qaf-support/pom.xml @@ -0,0 +1,21 @@ + + 4.0.0 + + com.qmetry + qaf-parent + ${revision} + + qaf-support + + support + + + + com.qmetry + qaf-selenium + ${qaf.version} + + + \ No newline at end of file diff --git a/qaf-support/src/main/java/com/qmetry/qaf/automation/step/CommonStep.java b/qaf-support/src/main/java/com/qmetry/qaf/automation/step/CommonStep.java new file mode 100644 index 00000000..431a6b79 --- /dev/null +++ b/qaf-support/src/main/java/com/qmetry/qaf/automation/step/CommonStep.java @@ -0,0 +1,2389 @@ +/******************************************************************************* + * Copyright (c) 2019 Infostretch Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + ******************************************************************************/ +package com.qmetry.qaf.automation.step; + +import static com.qmetry.qaf.automation.core.ConfigurationManager.getBundle; +import static com.qmetry.qaf.automation.ui.webdriver.ElementFactory.$; + +import java.util.Arrays; +import java.util.Iterator; +import java.util.Set; + +import org.openqa.selenium.Cookie; +import org.openqa.selenium.interactions.Actions; + +import com.qmetry.qaf.automation.core.TestBaseProvider; +import com.qmetry.qaf.automation.data.MetaData; +import com.qmetry.qaf.automation.ui.JsToolkit; +import com.qmetry.qaf.automation.ui.WebDriverTestBase; +import com.qmetry.qaf.automation.ui.webdriver.QAFExtendedWebElement; +import com.qmetry.qaf.automation.ui.webdriver.QAFWebElement; +import com.qmetry.qaf.automation.util.StringMatcher; +import com.qmetry.qaf.automation.util.StringUtil; + +/** + * com.qmetry.qaf.automation.step.CommonStep.java + * + * @author chirag + */ +public final class CommonStep { + + @QAFTestStep(description = "COMMENT: {value}") + public static void comment(Object value) { + System.out.printf("COMMENT: %s \n", value); + } + + /** + * Store last step result with the given name. In bdd if step returns value + * and you want to store the return value with name for further use you can + * call this step. + *

+ * Example:
+ * + * get text of 'my.ele.loc'
+ * AND store into 'myeletext'
+ * COMMENT: '${myeletext}'
+ *
+ * + * @param var + * : {0} : the name of variable you in which want to store last + * step result + */ + @QAFTestStep(description = "store into {var}") + public static void storeLastStepResultInto(String var) { + Object val = getBundle().getProperty("last.step.result"); + getBundle().addProperty(var, val); + } + + /** + * Store a value in variable to use later on. Stored The variable can be + * passed as argument to the other steps as ${varname} + *

+ * Example:
+ * + * store 5 into 'price'
+ * COMMENT: '${myeletext}'
+ *
+ * + * @param val + * : {0} : value to be stored in variable + * @param var + * : {1} : variable name + */ + @QAFTestStep(description = "store {val} into {var}") + public static void store(Object val, String var) { + getBundle().addProperty(var, val); + } + + /** + * Insert text in the given locator + *

+ * Example:
+ * + * sendKeys 'infostretch' into 'my.ele.loc'
+ *
+ *
+ * + * @param text + * : {0} : String to be insert + * @param loc + * : {1} : an element locator, can be direct locator value or a + * locator key stored in locator repository + */ + @QAFTestStep(description = "sendKeys {text} into {loc}") + public static void sendKeys(String text, String loc) { + $(loc).sendKeys(text); + } + + /** + * Verify that the specified element is somewhere on the page + *

+ * Example: + *

+ * BDD + *

+ * + * assert 'my.ele.loc' is present
+ *
+ *

+ * KWD + *

+ * + * @param loc + * : {0} : an element locator, can be direct locator value or a + * locator key stored in locator repository + */ + @QAFTestStep(description = "assert {loc} is present") + public static void assertPresent(String loc) { + $(loc).assertPresent(); + } + + /** + * Verify that the specified link text is somewhere on the page + *

+ * Example: + *

+ * BDD + *

+ * + * assert link with text 'infostretch' is present"
+ *
+ *

+ * KWD + *

+ * + * @param linkText + * : {0} : link text to be verified in browser page. + */ + @QAFTestStep(description = "assert link with text {linkText} is present") + public static void assertLinkWithTextPresent(String linkText) { + $("link=" + linkText).assertPresent(); + } + + /** + * Verify that the specified partial link is somewhere on the page + *

+ * Example: + *

+ * BDD + *

+ * + * assert link with partial text 'infostretch' is present"
+ *
+ *

+ * KWD + *

+ * + * @param linkText + * : {0} : partial link text to be verified in browser page. + */ + @QAFTestStep(description = "assert link with partial text {linkText} is present") + public static void assertLinkWithPartialTextPresent(String linkText) { + $("partialLink=" + linkText).assertPresent(); + } + + /** + * Asserts that the specified element is somewhere on the page. + *

+ * Example: + *

+ * BDD + *

+ * + * verify 'my.ele.loc' is present
+ * KWD + *
+ * + * @param loc + * : {0} : an element locator, can be direct locator value or a + * locator key stored in locator repository + */ + @QAFTestStep(description = "verify {loc} is present") + public static boolean verifyPresent(String loc) { + return $(loc).verifyPresent(); + } + + /** + * Asserts that the specified link with given text is somewhere on the page + *

+ * Example: + *

+ * BDD + *

+ * + * verify link with text 'About Us' is present
+ *
+ *

+ * KWD + *

+ * + * @param linkText + * : {0} : link text to be verified in browser page. + */ + @QAFTestStep(description = "verify link with text {linkText} is present") + public static boolean verifyLinkWithTextPresent(String linkText) { + return $("link=" + linkText).verifyPresent(); + } + + /** + * Asserts that the specified link with given partial text is somewhere on + * the page + *

+ * Example: + *

+ * BDD + *

+ * + * verify link with partial text 'infostretch' is present
+ *
+ *

+ * KWD + *

+ * + * @param linkText + * : {0} : partial link text to be verified in browser page. + */ + @QAFTestStep(description = "verify link with partial text {linkText} is present") + public static boolean verifyLinkWithPartialTextPresent(String linkText) { + return $("partialLink=" + linkText).verifyPresent(); + } + + /** + * @param loc + * : {0} : an element locator, can be direct locator value or a + * locator key stored in locator repository + */ + @QAFTestStep(description = "assert {loc} is visible") + public static void assertVisible(String loc) { + $(loc).assertVisible(); + } + + /** + * Verify that the specified element is visible somewhere on the page + *

+ * Example: + *

+ * BDD + *

+ * + * verify 'my.ele.loc' is visible
+ *
+ *

+ * KWD + *

+ * + * @param loc + * : {0} : an element locator, can be direct locator value or a + * locator key stored in locator repository + */ + @QAFTestStep(description = "verify {loc} is visible") + public static boolean verifyVisible(String loc) { + return $(loc).verifyVisible(); + } + + /** + * Opens an URL in the browser. This accepts both relative and absolute + * URLs. The "get" command waits for the page to load before proceeding, * + *

+ * Example:
+ * + * get 'http://www.infostretch.com'
+ * get '/'
+ * get '/Resources/case-studies.php'
+ *
+ * + * @param url + * : {0} : the URL to open; may be relative or absolute + */ + @QAFTestStep(description = "get {url}") + public static void get(String url) { + new WebDriverTestBase().getDriver().get(url); + } + + /** + * Switch from one driver to another and visa-versa during the test. + *

+ * This will create a driver session if given driver is not available in + * current thread. Note that it will not tear-down the current driver + * session. + *

+ * It is useful for some use cases involving browser and device - There are + * some use cases involving more than 2 devices/browsers (ex.: video + * conference) + *

+ * For single driver in entire test case you don't required to use this + * method. + * + * @since 2.1.11 + * @param driverName + * : driver name to create driver object. Refer QAF documentation + * to understand what can be the driver name + */ + @QAFTestStep(description = "switch to {driverName}") + public static void switchDriver(String driverName) { + TestBaseProvider.instance().get().setDriver(driverName); + } + + /** + * This step will tear down driver. It will quite and end current browser + * session. + */ + @QAFTestStep(description = "tear down driver") + public static void tearDownDriver() { + TestBaseProvider.instance().get().tearDown(); + } + + /** + * Switch the context to the driver to new window Example:
+ * + * switchToWindow '2'
+ * switchToWindow 'Forgot Password Popup'
+ *
+ * + * @param windowNameOrIndex + * : title or index of the window + */ + @QAFTestStep(description = "switch to {nameOrIndex} window") + public static void switchToWindow(String nameOrIndex) { + if (StringUtil.isNumeric(nameOrIndex)) { + int index = Integer.parseInt(nameOrIndex); + Set windows = new WebDriverTestBase().getDriver().getWindowHandles(); + Iterator itr = windows.iterator(); + for (int i = 0; i < windows.size() && i <= index; i++) { + nameOrIndex = itr.next(); + } + new WebDriverTestBase().getDriver().switchTo().window(nameOrIndex); + } else { + new WebDriverTestBase().getDriver().switchTo().window(nameOrIndex); + } + } + + /** + * clear the specified element value from the field + *

+ * Example: + *

+ * BDD + *

+ * + * clear 'my.ele.loc'
+ *
+ *

+ * KWD + *

+ * + * @param loc + * : {0} : an element locator, can be direct locator value or a + * locator key stored in locator repository + */ + @QAFTestStep(description = "clear {loc}") + public static void clear(String loc) { + $(loc).clear(); + } + + /** + * Retrieve the value for specified element. + *

+ * Example: + *

+ * BDD + *

+ * + * get text of 'my.ele.loc'
+ *
+ *

+ * KWD + *

+ * + * @param loc + * : {0} : an element locator, can be direct locator value or a + * locator key stored in locator repository + * @return The text contains by the specified locator + */ + @QAFTestStep(description = "get text of {loc}") + public static String getText(String loc) { + return $(loc).getText(); + } + + /** + * Submit the specified page. This is particularly useful for page without + * submit buttons, e.g. single-input "Search" page. + *

+ * Example: + *

+ * BDD + *

+ * + * submit 'my.ele.loc'
+ *
+ *

+ * KWD + *

+ * + * @param loc + * : {0} : an element locator, can be direct locator value or a + * locator key stored in locator repository + */ + + @QAFTestStep(description = "submit {loc}") + public static void submit(String loc) { + $(loc).submit(); + + } + + /** + * Clicks on a link, button, checkbox or radio button. If the click action + * causes a new page to load (like a link usually does), call + * waitForPageToLoad. + *

+ * Example: + *

+ * BDD + *

+ * + * click on 'my.ele.loc'
+ *
+ *

+ * KWD + *

+ * + * @param loc + * : {0} : an element locator, can be direct locator value or a + * locator key stored in locator repository + */ + @QAFTestStep(description = "click on {loc}") + public static void click(String loc) { + $(loc).click(); + } + + /** + * A convenience step for drag and drop that performs click-and-hold at the + * location of the source element, moves to the location of the target + * element, then releases the mouse. + * + *

+ * Example: + *

+ * BDD + *

+ * + * drag 'source.ele.loc' and drop on 'target.ele.loc'
+ *
+ *

+ * KWD + *

+ * + * dragAndDrop|['source.ele.loc','target.ele.loc']| + * + * + * @param source + * : {0} : source element locator to emulate button down at. + * @param target + * : {1} : target element locator to move to and release the + * mouse at. + */ + @QAFTestStep(description = "drag {source} and drop on {target}") + public static void dragAndDrop(String source, String target) { + QAFExtendedWebElement src = (QAFExtendedWebElement) $(source); + Actions actions = new Actions(src.getWrappedDriver()); + actions.dragAndDrop(src, $(target)); + } + + /** + * Wait for the specified element is visible Determines if the specified + * element is visible. An element can be rendered invisible by setting the + * CSS "visibility" property to "hidden", or the "display" property to + * "none", either for the element itself or one if its ancestors. This + * method will wait till its presence if the element is not present. + *

+ * Example: + *

+ * BDD + *

+ * + * wait until 'my.ele.loc' to be visible
+ *
+ *

+ * KWD + *

+ * + * @param loc + * : {0} : an element locator, can be direct locator value or a + * locator key stored in locator repository + */ + @QAFTestStep(description = "wait until {loc} to be visible") + public static void waitForVisible(String loc) { + $(loc).waitForVisible(); + } + + // @QAFTestStep(stepName = "waitForVisibleWithTimeout", description = + // "wait {1}sec for {0} to be visible") + public static void waitForVisible(String loc, long sec) { + $(loc).waitForVisible(sec * 1000); + } + + /** + * Determines if the specified element is not visible. This method will wait + * till its invisibility, if the element is visible. + *

+ * Example: + *

+ * BDD + *

+ * + * wait until 'my.ele.loc' not to be visible
+ *
+ *

+ * KWD + *

+ * + * @param loc + * : {0} : an element locator, can be direct locator value or a + * locator key stored in locator repository + */ + @QAFTestStep(description = "wait until {loc} not to be visible") + public static void waitForNotVisible(String loc) { + $(loc).waitForNotVisible(); + } + + // @QAFTestStep(stepName = "waitForNotVisibleWithTimeout", description = + // "wait {1}sec for {0} not to be visible") + public static void waitForNotVisible(String loc, long sec) { + $(loc).waitForNotVisible(sec * 1000); + } + + /** + * Determines if the specified element is disable. This method will wait for + * the element to be disable, if the element is enable. + *

+ * Example: + *

+ * BDD + *

+ * + * wait until 'my.ele.loc' to be disable
+ *
+ *

+ * KWD + *

+ * + * @param loc + * : {0} : an element locator, can be direct locator value or a + * locator key stored in locator repository + */ + @QAFTestStep(description = "wait until {loc} to be disable") + public static void waitForDisabled(String loc) { + $(loc).waitForDisabled(); + } + + // @QAFTestStep(stepName = "waitForDisableWithTimeout", description = + // "wait {1}sec for {0} to be Disable") + public static void waitForDisabled(String loc, long sec) { + $(loc).waitForDisabled(sec * 1000); + + } + + /** + * Determines if the specified element is enable. This method will wait for + * the element to be enable, if the element is disable. + *

+ * Example: + *

+ * BDD + *

+ * + * wait until 'my.ele.loc' to be enable
+ *
+ *

+ * KWD + *

+ * + * @param loc + * : {0} : an element locator, can be direct locator value or a + * locator key stored in locator repository + */ + @QAFTestStep(description = "wait until {loc} to be enable") + public static void waitForEnabled(String loc) { + $(loc).waitForEnabled(); + + } + + // @QAFTestStep(stepName = "waitForEnableWithTimeout", description = + // "wait {1}sec for {0} to be Enable") + public static void waitForEnabled(String loc, long sec) { + $(loc).waitForEnabled(sec * 1000); + + } + + /** + * Determines if the specified element is present. This method will wait for + * the element to be present, if the element is not present. + *

+ * Example: + *

+ * BDD + *

+ * + * wait until 'my.ele.loc' to be present
+ *
+ *

+ * KWD + *

+ * + * @param loc + * : {0} : an element locator, can be direct locator value or a + * locator key stored in locator repository + */ + @QAFTestStep(description = "wait until {loc} to be present") + public static void waitForPresent(String loc) { + $(loc).waitForPresent(); + ; + + } + + // @QAFTestStep(stepName = "waitForPresentWithTimeout", description = + // "wait {1}sec for {0} to be Present") + public static void waitForPresent(String loc, long sec) { + $(loc).waitForPresent(sec * 1000); + + } + + /** + * Determines if the specified element is not present. This method will wait + * for the element not to be present, if the element is present. + *

+ * Example: + *

+ * BDD + *

+ * + * wait until 'my.ele.loc' is not present
+ *
+ *

+ * KWD + *

+ * + * @param loc + * : {0} : an element locator, can be direct locator value or a + * locator key stored in locator repository + */ + @QAFTestStep(description = "wait until {loc} is not present") + public static void waitForNotPresent(String loc) { + $(loc).waitForNotPresent(); + + } + + // @QAFTestStep(stepName = "waitForNotPresentWithTimeout", description = + // "wait {1}sec for {0} is not Present") + public static void waitForNotPresent(String loc, long sec) { + $(loc).waitForNotPresent(sec * 1000); + + } + + /** + * Gets the text of an element. This works for any element that contains + * text. This command uses either the textContent or the innerText of the + * element, which is the rendered text shown to the user. + *

+ * Example: + *

+ * BDD + *

+ * + * wait until 'my.ele.loc' text 'infostretch'
+ *
+ *

+ * KWD + *

+ * + * @param loc + * : {0} : an element locator, can be direct locator value or a + * locator key stored in locator repository + * @param text + * : {1} : The text of element locator + */ + @QAFTestStep(description = "wait until {loc} text {text}") + public static void waitForText(String loc, String text) { + $(loc).waitForText(text); + + } + + // @QAFTestStep(stepName = "waitForTextWithTimeout", description = + // "wait {2}sec for {0} text is {1}") + public static void waitForText(String loc, String text, long sec) { + $(loc).waitForText(text, sec * 1000); + + } + + /** + * Gets the text of an element. This works for any element that contains + * text. This command uses either the textContent or the innerText of the + * element, which is the rendered text shown to the user. + *

+ * Example: + *

+ * BDD + *

+ * + * wait until 'my.ele.loc' text is not 'infostretch'
+ *
+ *

+ * KWD + *

+ * + * @param loc + * : {0} : an element locator, can be direct locator value or a + * locator key stored in locator repository + * @param text + * : {1} : The text of element locator + */ + @QAFTestStep(description = "wait until {loc} text is not {text}") + public static void waitForNotText(String loc, String text) { + $(loc).waitForNotText(text); + + } + + // @QAFTestStep(stepName = "waitForNotTextWithTimeout", description = + // "wait {2}sec for {0} text is not {1}") + public static void waitForNotText(String loc, String text, long sec) { + $(loc).waitForNotText(text, sec * 1000); + } + + /** + * Gets the (whitespace-trimmed) value of an input field (or anything else + * with a value parameter). + *

+ * Example: + *

+ * BDD + *

+ * + * wait until 'my.ele.loc' value is 'infostretch'
+ *
+ *

+ * KWD + *

+ * + * @param loc + * : {0} : an element locator, can be direct locator value or a + * locator key stored in locator repository + * @param value + * : {1} : The object of value for element locator + */ + @QAFTestStep(description = "wait until {loc} value is {value}") + public static void waitForValue(String loc, Object value) { + $(loc).waitForValue(value); + } + + // @QAFTestStep(stepName = "waitForValueWithTimeout", description = + // "wait {2}sec for {0} value is {1}") + public static void waitForValue(String loc, Object value, long sec) { + $(loc).waitForValue(value, sec * 1000); + } + + /** + * Gets the (whitespace-trimmed) value of an input field (or anything else + * with a value parameter). + *

+ * Example: + *

+ * BDD + *

+ * + * wait until 'my.ele.loc' value is not 'infostretch'
+ *
+ *

+ * KWD + *

+ * + * @param loc + * : {0} : an element locator, can be direct locator value or a + * locator key stored in locator repository + * @param value + * : {1} : The object of value for element locator + */ + @QAFTestStep(description = "wait until {loc} value is not {value}") + public static void waitForNotValue(String loc, Object value) { + $(loc).waitForNotValue(value); + + } + + // @QAFTestStep(stepName = "waitForNotValueWithTimeout", description = + // "wait {2}sec for {0} value is not {1}") + public static void waitForNotValue(String loc, Object value, long sec) { + $(loc).waitForNotValue(value, sec * 1000); + } + + /** + * This method wait until the locator in the specified page will be + * selected. + *

+ * Example: + *

+ * BDD + *

+ * + * wait until 'my.ele.loc' to be selected
+ *
+ *

+ * KWD + *

+ * + * @param loc + * : {0} : an element locator, can be direct locator value or a + * locator key stored in locator repository + */ + @QAFTestStep(description = "wait until {loc} to be selected") + public static void waitForSelected(String loc) { + $(loc).waitForSelected(); + } + + // @QAFTestStep(stepName = "waitForSelectedWithTimeout", description = + // "wait {1}sec for {0} to be selected") + public static void waitForSelected(String loc, long sec) { + $(loc).waitForSelected(sec * 1000); + + } + + /** + * This method wait until the locator in the specified page will not be + * selected. + *

+ * Example: + *

+ * BDD + *

+ * + * wait until 'my.ele.loc' is not selected
+ *
+ *

+ * KWD + *

+ * + * @param loc + * : {0} : an element locator, can be direct locator value or a + * locator key stored in locator repository + */ + @QAFTestStep(description = "wait until {loc} is not selected") + public static void waitForNotSelected(String loc) { + $(loc).waitForNotSelected(); + + } + + // @QAFTestStep(stepName = "waitForNotSelectedWithTimeout", description = + // "wait {1}sec for {0} is not selected") + public static void waitForNotSelected(String loc, long sec) { + $(loc).waitForNotSelected(sec * 1000); + + } + + /** + * This method wait until it gets the value of an element attribute for + * specified element locator. + *

+ * Example: + *

+ * BDD + *

+ * + * wait until 'my.ele.loc' for attribute 'type' value is 'send'
+ *
+ *

+ * KWD + *

+ * + * @param loc + * : {0} : an element locator, can be direct locator value or a + * locator key stored in locator repository + * @param attr + * : {1} : attribute name which value to be verified + * @param value + * : {2} : value of attribute + */ + @QAFTestStep(description = "wait until {loc} for attribute {attr} value is {value}") + public static void waitForAttribute(String loc, String attr, String value) { + $(loc).waitForAttribute(attr, value); + + } + + // @QAFTestStep(stepName = "waitForAttributeWithTimeout", description = + // "wait {3}sec for {0} attribute {1} value is {2}") + public static void waitForAttribute(String loc, String attr, String value, long sec) { + $(loc).waitForAttribute(attr, value, sec * 1000); + + } + + /** + * This method wait until it can not gets the value of an element attribute + * for specified element locator. + *

+ * Example: + *

+ * BDD + *

+ * + * wait until 'my.ele.loc' for attribute 'type' value is not 'send'
+ *
+ *

+ * KWD + *

+ * + * @param loc + * : {0} : an element locator, can be direct locator value or a + * locator key stored in locator repository + * @param attr + * : {1} : attribute name which value to be verified + * @param value + * : {2} : value of attribute + */ + @QAFTestStep(description = "wait until {loc} attribute {attr} value is not {value}") + public static void waitForNotAttribute(String loc, String attr, String value) { + $(loc).waitForNotAttribute(attr, value); + } + + // @QAFTestStep(stepName = "waitForNotAttributeWithTimeout", description = + // "wait {3}sec for {0} attribute {1} value is not {2}") + public static void waitForNotAttribute(String loc, String attr, String value, long sec) { + $(loc).waitForAttribute(attr, value, sec * 1000); + } + + /** + * This method wait until it gets the CSS class name for specified element + * locator + *

+ * Example: + *

+ * BDD + *

+ * + * wait until 'my.ele.loc' css class name is 'ClassName'
+ *
+ *

+ * KWD + *

+ * + * @param loc + * : {0} : an element locator, can be direct locator value or a + * locator key stored in locator repository + * @param className + * : {1} : CSS class name to be verified + */ + @QAFTestStep(description = "wait until {loc} css class name is {className}") + public static void waitForCssClass(String loc, String className) { + $(loc).waitForCssClass(className); + } + + // @QAFTestStep(stepName = "waitForCssClassWithTimeout", description = + // "wait {2}sec for {0} css class name is {1}") + public static void waitForCssClass(String loc, String className, long sec) { + $(loc).waitForCssClass(className, sec * 1000); + } + + /** + * This method wait until it can not gets the CSS class name for specified + * element locator + *

+ * Example: + *

+ * BDD + *

+ * + * wait until 'my.ele.loc' css class name is not 'ClassName'
+ *
+ *

+ * KWD + *

+ * + * @param loc + * : {0} : an element locator, can be direct locator value or a + * locator key stored in locator repository + * @param className + * : {1} : CSS class name to be verified + */ + @QAFTestStep(description = "wait until {loc} css class name is not {className}") + public static void waitForNotCssClass(String loc, String className) { + $(loc).waitForNotCssClass(className); + } + + // @QAFTestStep(stepName = "waitForNotCssClassWithTimeout", description = + // "wait {2}sec for {0} css class name is not {1} ") + public static void waitForNotCssClass(String loc, String className, long sec) { + $(loc).waitForCssClass(className, sec * 1000); + + } + + /** + * This method wait until it gets the property value for specified element + * locator + *

+ * Example: + *

+ * BDD + *

+ * + * wait until 'my.ele.loc' property 'propertyStyle' value is 'value'
+ *
+ *

+ * KWD + *

+ * + * @param loc + * : {0} : an element locator, can be direct locator value or a + * locator key stored in locator repository + * @param prop + * : {1} : property (css style) to be verified + * @param value + * : {2} : value of property (ie. css style property value) + */ + @QAFTestStep(description = "wait until {loc} property {prop} value is {value}") + public static void waitForCssStyle(String loc, String prop, String value) { + $(loc).waitForCssStyle(prop, value); + + } + + // @QAFTestStep(stepName = "waitForCssStyleWithTimeout", description = + // "wait {3}sec for {0} property {1} value is {2} ") + public static void waitForCssStyle(String loc, String prop, String value, long sec) { + $(loc).waitForCssStyle(prop, value, sec * 1000); + + } + + /** + * This method wait until it can not gets the property value for specified + * element locator + *

+ * Example: + *

+ * BDD + *

+ * + * wait until 'my.ele.loc' property 'propertyStyle' value is not 'value'
+ *
+ *

+ * KWD + *

+ * + * @param loc + * : {0} : an element locator, can be direct locator value or a + * locator key stored in locator repository + * @param prop + * : {1} : property (css style) to be verified + * @param value + * : {2} : value of property (ie. css style property value) + */ + @QAFTestStep(description = "wait until {loc} property {prop} value is not {value}") + public static void waitForNotCssStyle(String loc, String prop, String value) { + $(loc).waitForNotCssStyle(prop, value); + + } + + /** + * This method wait until it gets the css color property value for specified element + * locator + *

+ * Example: + *

+ * BDD + *

+ * + * wait until 'my.ele.loc' color 'propertyStyle' value is 'value'
+ *
+ *

+ * KWD + *

+ * + * @param loc + * : {0} : an element locator, can be direct locator value or a + * locator key stored in locator repository + * @param prop + * : {1} : color property (css style) to be verified + * @param value + * : {2} : value of color in hex or rgb or rgba + */ + @QAFTestStep(description = "wait until {loc} color {prop} value is {value}") + public static void waitForCssStyleColor(String loc, String prop, String value) { + $(loc).waitForCssStyleColor(prop, value); + } + + /** + * This method wait until not the css color property value of element + * locator + *

+ * Example: + *

+ * BDD + *

+ * + * wait until 'my.ele.loc' color 'propertyStyle' value is not 'value'
+ *
+ *

+ * KWD + *

+ * + * @param loc + * : {0} : an element locator, can be direct locator value or a + * locator key stored in locator repository + * @param prop + * : {1} : color property (css style) to be verified + * @param value + * : {2} : value of color in hex or rgb or rgba + */ + @QAFTestStep(description = "wait until {loc} color {prop} value is not {value}") + public static void waitForNotCssStyleColor(String loc, String prop, String value) { + $(loc).waitForNotCssStyleColor(prop, value); + } + + // @QAFTestStep(stepName = "waitForNotCssStyleWithTimeout", description = + // "wait {3}sec for {0} css property {1} vaule is {2} ") + public static void waitForNotCssStyle(String loc, String prop, String value, long sec) { + $(loc).waitForNotCssStyle(prop, value, sec * 1000); + + } + + /** + * Assert that the specified element is not somewhere on the page + *

+ * Example: + *

+ * BDD + *

+ * + * verify 'my.ele.loc' not present
+ *
+ *

+ * KWD + *

+ * + * @param loc + * : {0} : an element locator, can be direct locator value or a + * locator key stored in locator repository + * @return true if the element locator is present, false + * otherwise + */ + @QAFTestStep(description = "verify {loc} not present") + public static boolean verifyNotPresent(String loc) { + + return $(loc).verifyNotPresent(); + } + + /** + * Will check and wait until in-progress AJAX call get completed from any of + * the {@link JsToolkit}. If you know the toolkit used in your AUT use + * {@link #waitForAjaxToComplete(String)} + */ + @QAFTestStep(description = "wait until ajax call complete") + public static void waitForAjaxToComplete() { + new WebDriverTestBase().getDriver().waitForAjax(); + } + + /** + * Will check and wait until in-progress AJAX call get completed from + * provide toolkit. Following are supported toolkit: + *
    + *
  • DOJO + *
  • EXTJS + *
  • JQUERY + *
  • YUI + *
  • PHPJS + *
  • PROTOTYPE + * + * @param jstoolkit + * must be one of the {@link JsToolkit} + */ + @QAFTestStep(description = "wait until {jstoolkit} ajax call complete") + public static void waitForAjaxToComplete(String jstoolkit) { + new WebDriverTestBase().getDriver().waitForAjax(JsToolkit.valueOf(jstoolkit)); + } + + /** + * + * @param elementloc + */ + @QAFTestStep(description = "wait until any of {loc} to be present") + public static void waitForAnyElementPresent(String... elementloc) { + QAFWebElement[] elements= + Arrays.stream(elementloc).map(loc-> $(loc)).toArray(QAFWebElement[]::new); + new WebDriverTestBase().getDriver().waitForAnyElementPresent(elements); + } + + /** + * + * @param elementloc + */ + @QAFTestStep(description = "wait until all of {loc} to be present") + public static void waitForAllElementPresent(String... elementloc) { + QAFWebElement[] elements= + Arrays.stream(elementloc).map(loc-> $(loc)).toArray(QAFWebElement[]::new); + new WebDriverTestBase().getDriver().waitForAllElementPresent(elements); + } + + /** + * + * @param elementloc + */ + @QAFTestStep(description = "wait until any of {loc} to be visible") + public static void waitForAnyElementVisible(String... elementloc) { + QAFWebElement[] elements= + Arrays.stream(elementloc).map(loc-> $(loc)).toArray(QAFWebElement[]::new); + new WebDriverTestBase().getDriver().waitForAnyElementVisible(elements); + } + + /** + * + * @param elementloc + */ + @QAFTestStep(description = "wait until all of {loc} to be visible") + public static void waitForAllElementVisible(String... elementloc) { + QAFWebElement[] elements= + Arrays.stream(elementloc).map(loc-> $(loc)).toArray(QAFWebElement[]::new); + new WebDriverTestBase().getDriver().waitForAllElementVisible(elements); + } + + /** + * + * @param title + */ + @QAFTestStep(description = "wait until window title {title}") + public static void waitForWindowTitle(String title) { + new WebDriverTestBase().getDriver().waitForWindowTitle(StringMatcher.expected(title)); + } + + /** + * + * @param title + */ + @QAFTestStep(description = "verify window title {title}") + public static void verifyWindowTitle(String title) { + new WebDriverTestBase().getDriver().verifyTitle(StringMatcher.expected(title)); + } + + /** + * Assert window title + * + * @param title + */ + @QAFTestStep(description = "assert window title {title}") + public static void assertWindowTitle(String title) { + new WebDriverTestBase().getDriver().assertTitle(StringMatcher.expected(title)); + } + + /** + * + * @param url + */ + @QAFTestStep(description = "wait until window url {url}") + public static void waitForWindowUrl(String url) { + new WebDriverTestBase().getDriver().waitForCurrentUrl(StringMatcher.expected(url)); + } + + /** + * + * @param url + */ + @QAFTestStep(description = "verify window url {url}") + public static void verifyWindowUrl(String url) { + new WebDriverTestBase().getDriver().verifyCurrentUrl(StringMatcher.expected(url)); + } + + /** + * + * @param url + */ + @QAFTestStep(description = "assert window url {url}") + public static void assertWindowUrl(String url) { + new WebDriverTestBase().getDriver().assertCurrentUrl(StringMatcher.expected(url)); + } + + /** + * + * @param count + */ + @QAFTestStep(description = "wait until no of windows to be {count}") + public static void waitForNoOfWindows(int count) { + new WebDriverTestBase().getDriver().waitForNoOfWindows(count); + } + + /** + * + * @param count + */ + @QAFTestStep(description = "verify no of windows is {count}") + public static void verifyNoOfWindows(int count) { + new WebDriverTestBase().getDriver().verifyNoOfWindows(count); + } + /** + * + * @param count + */ + @QAFTestStep(description = "assert no of windows is {count}") + public static void assertNoOfWindows(int count) { + new WebDriverTestBase().getDriver().assertNoOfWindows(count); + } + + /** + * Assert that the specified element is not visible somewhere on the page + *

    + * Example: + *

    + * BDD + *

    + * + * verify 'my.ele.loc' not visible
    + *
    + *

    + * KWD + *

    + * + * @param loc + * : an element locator, can be direct locator value or a locator + * key stored in locator repository + * @return true if the element locator is visible, false + * otherwise + */ + @QAFTestStep(description = "verify {loc} not visible") + public static boolean verifyNotVisible(String loc) { + return $(loc).verifyNotVisible(); + } + + /** + * Assert that the specified element is not enable somewhere on the page + *

    + * Example: + *

    + * BDD + *

    + * + * verify 'my.ele.loc' not enabled
    + *
    + *

    + * KWD + *

    + * + * @param loc + * : an element locator, can be direct locator value or a locator + * key stored in locator repository + * @return true if the element locator is enable, false + * otherwise + */ + @QAFTestStep(description = "verify {loc} enabled") + public static boolean verifyEnabled(String loc) { + return $(loc).verifyEnabled(); + } + + /** + * Assert that the specified element is disabled somewhere on the page + *

    + * Example: + *

    + * BDD + *

    + * + * verify 'my.ele.loc' disabled
    + *
    + *

    + * KWD + *

    + * + * @param loc + * : an element locator, can be direct locator value or a locator + * key stored in locator repository + * @return true if the element locator is disabled, false + * otherwise + */ + @QAFTestStep(description = "verify {loc} disabled") + public static boolean verifyDisabled(String loc) { + return $(loc).verifyDisabled(); + } + + /** + * Asserts the text of an element. This works for any element that contains + * text. This command uses either the textContent or the innerText of the + * element, which is the rendered text shown to the user. + *

    + * Example: + *

    + * BDD + *

    + * + * verify 'my.ele.loc' text is 'infostretch'
    + *
    + *

    + * KWD + *

    + * + * @param loc + * : {0} : an element locator, can be direct locator value or a + * locator key stored in locator repository + * @param text + * : {1} : The text of element locator + * @return true if the element locator text is verified, false + * otherwise + */ + + @QAFTestStep(description = "verify {loc} text is {text}") + public static boolean verifyText(String loc, String text) { + return $(loc).verifyText(text); + } + + /** + * Asserts the text of an element. This works for any element that contains + * text. This command uses either the textContent or the innerText of the + * element, which is the rendered text shown to the user. + *

    + * Example: + *

    + * BDD + *

    + * + * verify 'my.ele.loc' text is not 'infostretch'
    + *
    + *

    + * KWD + *

    + * + * @param loc + * : {0} : an element locator, can be direct locator value or a + * locator key stored in locator repository + * @param text + * : {1} : The text of element locator + * @return true if the element locator text is not verified, + * false otherwise + */ + @QAFTestStep(description = "verify {loc} text is not {text}") + public static boolean verifyNotText(String loc, String text) { + return $(loc).verifyNotText(text); + } + + /** + * Asserts the value of an element. + *

    + * Example: + *

    + * BDD + *

    + * + * verify 'my.ele.loc' value is 'Type Value'
    + *
    + *

    + * KWD + *

    + * + * @param loc + * : {0} : an element locator, can be direct locator value or a + * locator key stored in locator repository + * @param text + * : {1} : The type value of element locator + * @return true if the element locator type value is verified, + * false otherwise + */ + @QAFTestStep(description = "verify {loc} value is {value}") + public static boolean verifyValue(String loc, T value) { + return $(loc).verifyValue(value); + } + + /** + * Asserts not the value of an element. + *

    + * Example: + *

    + * BDD + *

    + * + * verify 'my.ele.loc' value is not 'Type Value'
    + *
    + *

    + * KWD + *

    + * + * @param loc + * : {0} : an element locator, can be direct locator value or a + * locator key stored in locator repository + * @param text + * : {1} : The type value of element locator + * @return true if the element locator type value is not verified, + * false otherwise + */ + @QAFTestStep(description = "verify {loc} value is not {value}") + public static boolean verifyNotValue(String loc, T value) { + return $(loc).verifyNotValue(value); + } + + /** + * Assert that the specified element is selected somewhere on the page + *

    + * Example: + *

    + * BDD + *

    + * + * verify 'my.ele.loc' is selected
    + *
    + *

    + * KWD + *

    + * + * @param loc + * : {0} : an element locator, can be direct locator value or a + * locator key stored in locator repository + * @return true if the element locator is selected, false + * otherwise + */ + @QAFTestStep(description = "verify {loc} is selected") + public static boolean verifySelected(String loc) { + + return $(loc).verifySelected(); + } + + /** + * Assert that the specified element is not selected somewhere on the page + *

    + * Example: + *

    + * BDD + *

    + * + * verify 'my.ele.loc' is not selected
    + *
    + *

    + * KWD + *

    + * + * @param loc + * : {0} : an element locator, can be direct locator value or a + * locator key stored in locator repository + * @return true if the element locator is not selected, false + * otherwise + */ + @QAFTestStep(description = "verify {loc} is not selected") + public static boolean verifyNotSelected(String loc) { + return $(loc).verifyNotSelected(loc); + } + + /** + * Assert attribute value for specific locator somewhere in the page. + *

    + * Example: + *

    + * BDD + *

    + * + * verify 'my.ele.loc' attribute 'type' value is 'send'
    + *
    + *

    + * KWD + *

    + * + * @param loc + * : {0} : an element locator, can be direct locator value or a + * locator key stored in locator repository + * @param attr + * : {1} : attribute name which value to be verified + * @param value + * : {2} : value of attribute + * @return true if the element locator attribute value is verified, + * false otherwise + */ + @QAFTestStep(description = "verify {loc} attribute {attr} value is {value}") + public static boolean verifyAttribute(String loc, String attr, String value) { + return $(loc).verifyAttribute(attr, value); + } + + /** + * Assert not attribute value for specific locator somewhere in the page. + *

    + * Example: + *

    + * BDD + *

    + * + * verify 'my.ele.loc' attribute 'type' value is not 'send'
    + *
    + *

    + * KWD + *

    + * + * @param loc + * : {0} : an element locator, can be direct locator value or a + * locator key stored in locator repository + * @param attr + * : {1} : attribute name which value to be verified + * @param value + * : {2} : value of attribute + * @return true if the element locator attribute value is not + * verified, false otherwise + */ + @QAFTestStep(description = "verify {loc} attribute {attr} value is not {value}") + public static boolean verifyNotAttribute(String loc, String attr, String value) { + return $(loc).verifyNotAttribute(attr, value); + } + + /* + * @QAFTestStep(description = + * "verify {0} not attribute {1} value {3} to be match {2}") public boolean + * verifyNotAttribute(String loc, String attr, StringMatcher matcher, + * String... label) { return new + * QAFExtendedWebElement(loc).verifyNotAttribute(attr, matcher, label); } + */ + /** + * Assert css class name for specific locator somewhere in the page. + *

    + * Example: + *

    + * BDD + *

    + * + * verify 'my.ele.loc' css class name is 'class name'
    + *
    + *

    + * KWD + *

    + * + * @param loc + * : {0} : an element locator, can be direct locator value or a + * locator key stored in locator repository + * @param className + * : {1} : css class name not to be verified + * @return true if the element locator css class name is verified, + * false otherwise + */ + @QAFTestStep(description = "verify {loc} css class name is {className}") + public static boolean verifyCssClass(String loc, String className) { + return $(loc).verifyCssClass(className); + } + + /** + * Assert not css class name for specific locator somewhere in the page. + *

    + * Example: + *

    + * BDD + *

    + * + * verify 'my.ele.loc' css class name is not 'class name'
    + *
    + *

    + * KWD + *

    + * + * @param loc + * : {0} : an element locator, can be direct locator value or a + * locator key stored in locator repository + * @param className + * : {1} : css class name not to be verified + * @return true if the element locator css class name is not + * verified, false otherwise + */ + @QAFTestStep(description = "verify {loc} css class name is not {className}") + public static boolean verifyNotCssClass(String loc, String className) { + return $(loc).verifyNotCssClass(className); + } + + /** + * Assert css property value for specific locator somewhere in the page. + *

    + * Example: + *

    + * BDD + *

    + * + * verify 'my.ele.loc' property 'Style' value is 'value'
    + *
    + *

    + * KWD + *

    + * + * @param loc + * : {0} : an element locator, can be direct locator value or a + * locator key stored in locator repository + * @param prop + * : {1} : property (css style) to be verified + * @param value + * : {2} : value of property (i.e css style property value) + * @return true if the element locator color property value is verified, + * false otherwise + */ + @QAFTestStep(description = "verify {loc} property {prop} value is {value}") + public static boolean verifyCssStyle(String loc, String prop, String value) { + return $(loc).verifyCssStyle(prop, value); + } + + /** + * Assert not css property value for specific locator somewhere in the page. + *

    + * Example: + *

    + * BDD + *

    + * + * verify 'my.ele.loc' property 'Style' value is not 'value'
    + *
    + *

    + * KWD + *

    + * + * @param loc + * : {0} : an element locator, can be direct locator value or a + * locator key stored in locator repository + * @param prop + * : {1} : property (css style) to be verified + * @param value + * : {2} : value of property (i.e css style property value) + * @return true if the element locator color property value is not + * verified, false otherwise + */ + @QAFTestStep(description = "verify {loc} property {prop} value is not {value}") + public static boolean verifyNotCssStyle(String loc, String prop, String value) { + return $(loc).verifyNotCssStyle(prop, value); + } + + /** + * This method verify the css color property value of is equal to value provide for element + * locator + *

    + * Example: + *

    + * BDD + *

    + * + * verify 'my.ele.loc' color 'propertyStyle' value is 'value'
    + *
    + *

    + * KWD + *

    + * + * @param loc + * : {0} : an element locator, can be direct locator value or a + * locator key stored in locator repository + * @param prop + * : {1} : color property (css style) to be verified + * @param value + * : {2} : value of color in hex or rgb or rgba + */ + @QAFTestStep(description = "verify {loc} color {prop} value is {value}") + public static void verifyCssStyleColor(String loc, String prop, String value) { + $(loc).verifyCssStyleColor(prop, value); + } + /** + * This method verify the css color property value of is not equal to value provide for element + * locator + *

    + * Example: + *

    + * BDD + *

    + * + * verify 'my.ele.loc' color 'propertyStyle' value is not 'value'
    + *
    + *

    + * KWD + *

    + * + * @param loc + * : {0} : an element locator, can be direct locator value or a + * locator key stored in locator repository + * @param prop + * : {1} : color property (css style) to be verified + * @param value + * : {2} : value of color in hex or rgb or rgba + */ + @QAFTestStep(description = "verify {loc} color {prop} value is not {value}") + public static void verifyNotCssStyleColor(String loc, String prop, String value) { + $(loc).verifyNotCssStyleColor(prop, value); + } + /** + * Verify that the specified element is not present somewhere on the page + *

    + * Example: + *

    + * BDD + *

    + * + * assert 'my.ele.loc' is not present
    + *
    + *

    + * KWD + *

    + * + * @param loc + * : {0} : an element locator, can be direct locator value or a + * locator key stored in locator repository + */ + @QAFTestStep(description = "assert {loc} is not present") + public static void assertNotPresent(String loc) { + $(loc).assertNotPresent(); + } + + /** + * Verify that the specified element is not visible somewhere on the page + *

    + * Example: + *

    + * BDD + *

    + * + * assert 'my.ele.loc' is not visible
    + *
    + *

    + * KWD + *

    + * + * @param loc + * : {0} : an element locator, can be direct locator value or a + * locator key stored in locator repository + */ + @QAFTestStep(description = "assert {loc} is not visible") + public static void assertNotVisible(String loc) { + $(loc).assertNotVisible(); + } + + /** + * Verify that the specified element is enable somewhere on the page + *

    + * Example: + *

    + * BDD + *

    + * + * assert 'my.ele.loc' is enable
    + *
    + *

    + * KWD + *

    + * + * @param loc + * : {0} : an element locator, can be direct locator value or a + * locator key stored in locator repository + */ + @QAFTestStep(description = "assert {loc} is enable") + public static void assertEnabled(String loc) { + $(loc).assertEnabled(); + } + + /** + * Verify that the specified element is disable somewhere on the page + *

    + * Example: + *

    + * BDD + *

    + * + * assert 'my.ele.loc' is disable
    + *
    + *

    + * KWD + *

    + * + * @param loc + * : {0} : an element locator, can be direct locator value or a + * locator key stored in locator repository + */ + @QAFTestStep(description = "assert {loc} is disable") + public static void assertDisabled(String loc) { + $(loc).assertDisabled(); + } + + /** + * Verify the text of an element. This works for any element that contains + * text. This command uses either the textContent or the innerText of the + * element, which is the rendered text shown to the user. + *

    + * Example: + *

    + * BDD + *

    + * + * assert 'my.ele.loc' text is 'infostretch'
    + *
    + *

    + * KWD + *

    + * + * @param loc + * : {0} : an element locator, can be direct locator value or a + * locator key stored in locator repository + * @param text + * : {1} : The text of element locator + */ + @QAFTestStep(description = "assert {loc} text is {text}") + public static void assertText(String loc, String text) { + $(loc).assertText(text); + } + + /** + * Verify an element is not contain the text. This works for any element + * that contains text. This command uses either the textContent or the + * innerText of the element, which is the rendered text shown to the user. + *

    + * Example: + *

    + * BDD + *

    + * + * assert 'my.ele.loc' text is not 'infostretch'
    + *
    + *

    + * KWD + *

    + * + * @param loc + * : {0} : an element locator, can be direct locator value or a + * locator key stored in locator repository + * @param text + * : {1} : The text of element locator + */ + @QAFTestStep(description = "assert {loc} text is not {text}") + public static void assertNotText(String loc, String text) { + $(loc).assertNotText(text); + } + + /** + * Verify the (whitespace-trimmed) value of an input field (or anything else + * with a value parameter). + *

    + * Example: + *

    + * BDD + *

    + * + * assert 'my.ele.loc' value is 'value'
    + *
    + *

    + * KWD + *

    + * + * @param loc + * : {0} : an element locator, can be direct locator value or a + * locator key stored in locator repository + * @param value + * : {1} : The value for element locator + */ + @QAFTestStep(description = "assert {loc} value is {value}") + public static void assertValue(String loc, String value) { + $(loc).assertValue(value); + } + + /** + * Not verify the (whitespace-trimmed) value of an input field (or anything + * else with a value parameter). + *

    + * Example: + *

    + * BDD + *

    + * + * assert 'my.ele.loc' value is not 'value'
    + *
    + *

    + * KWD + *

    + * + * @param loc + * : {0} : an element locator, can be direct locator value or a + * locator key stored in locator repository + * @param value + * : {1} : The object of value for element locator + */ + @QAFTestStep(description = "assert {loc} value is not {value}") + public static void assertNotValue(String loc, T value) { + $(loc).assertNotValue(value); + } + + /** + * Verify that the specified element is selected somewhere on the page + *

    + * Example: + *

    + * BDD + *

    + * + * assert 'my.ele.loc' is selected
    + *
    + *

    + * KWD + *

    + * + * @param loc + * : {0} : an element locator, can be direct locator value or a + * locator key stored in locator repository + */ + @QAFTestStep(description = "assert {loc} is selected") + public static void assertSelected(String loc) { + $(loc).assertSelected(); + } + + /** + * Verify that the specified element is not selected somewhere on the page + *

    + * Example: + *

    + * BDD + *

    + * + * assert 'my.ele.loc' is not selected
    + *
    + *

    + * KWD + *

    + * + * @param loc + * : {0} : an element locator, can be direct locator value or a + * locator key stored in locator repository + */ + @QAFTestStep(description = "assert {loc} is not selected") + public static void assertNotSelected(String loc) { + $(loc).assertNotSelected(); + } + + /** + * Verify attribute value for specific locator somewhere in the page. + *

    + * Example: + *

    + * BDD + *

    + * + * assert 'my.ele.loc' attribute 'type' value is 'send'
    + *
    + *

    + * KWD + *

    + * + * @param loc + * : {0} : an element locator, can be direct locator value or a + * locator key stored in locator repository + * @param attr + * : {1} : attribute name which value to be asserted + * @param value + * : {2} : value of attribute + */ + @QAFTestStep(description = "assert {loc} attribute {attr} value is {value}") + public static void assertAttribute(String loc, String attr, String value) { + $(loc).assertAttribute(attr, value); + } + + /** + * Verify not attribute value for specific locator somewhere in the page. + *

    + * Example: + *

    + * BDD + *

    + * + * assert 'my.ele.loc' attribute 'type' value is not 'send'
    + *
    + *

    + * KWD + *

    + * + * @param loc + * : {0} : an element locator, can be direct locator value or a + * locator key stored in locator repository + * @param attr + * : {1} : attribute name which value not to be asserted + * @param value + * : {2} : value of attribute + */ + @QAFTestStep(description = "assert {loc} attribute {attr} value is not {value}") + public static void assertNotAttribute(String loc, String attr, String value) { + $(loc).assertNotAttribute(attr, value); + } + + /** + * verify css class name for specific locator somewhere in the page. + *

    + * Example: + *

    + * BDD + *

    + * + * assert 'my.ele.loc' css class name is 'class name'
    + *
    + *

    + * KWD + *

    + * + * @param loc + * : {0} : an element locator, can be direct locator value or a + * locator key stored in locator repository + * @param className + * : {1} : css class name to be asserted + */ + @QAFTestStep(description = "assert {loc} css class name is {className}") + public static void assertCssClass(String loc, String className) { + $(loc).assertCssClass(className); + } + + /** + * verify not css class name for specific locator somewhere in the page. + *

    + * Example: + *

    + * BDD + *

    + * + * assert 'my.ele.loc' css class name is not 'class name'
    + *
    + *

    + * KWD + *

    + * + * @param loc + * : {0} : an element locator, can be direct locator value or a + * locator key stored in locator repository + * @param className + * : {1} : css class name not to be asserted + */ + @QAFTestStep(description = "assert {loc} css class name is not {className}") + public static void assertNotCssClass(String loc, String className) { + $(loc).assertNotCssClass(className); + } + + /** + * Verify css property value for specific locator somewhere in the page. + *

    + * Example: + *

    + * BDD + *

    + * + * assert 'my.ele.loc' property 'Style' value is 'value'
    + *
    + *

    + * KWD + *

    + * + * @param loc + * : {0} : an element locator, can be direct locator value or a + * locator key stored in locator repository + * @param prop + * : {1} : property (css style) to be asserted + * @param value + * : {2} : value of property (i.e css style property value) + */ + @QAFTestStep(description = "assert {loc} property {prop} value is {value}") + public static void assertCssStyle(String loc, String prop, String value) { + $(loc).assertCssStyle(prop, value); + } + + /** + * Verify not css property value for specific locator somewhere in the page. + *

    + * Example: + *

    + * BDD + *

    + * + * assert 'my.ele.loc' property 'Style' value is not 'value'
    + *
    + *

    + * KWD + *

    + * + * @param loc + * : {0} : an element locator, can be direct locator value or a + * locator key stored in locator repository + * @param prop + * : {1} : property (css style) to be asserted + * @param value + * : {2} : value of property (i.e css style property value) + */ + @QAFTestStep(description = "assert {loc} property {prop} value is not {value}") + public static void assertNotCssStyle(String loc, String prop, String value) { + $(loc).assertNotCssStyle(prop, value); + } + + /** + * This method verify the css color property value of is equal to value provide for element + * locator + *

    + * Example: + *

    + * BDD + *

    + * + * assert 'my.ele.loc' color 'propertyStyle' value is 'value'
    + *
    + *

    + * KWD + *

    + * + * @param loc + * : {0} : an element locator, can be direct locator value or a + * locator key stored in locator repository + * @param prop + * : {1} : color property (css style) to be verified + * @param value + * : {2} : value of color in hex or rgb or rgba + */ + @QAFTestStep(description = "assert {loc} color {prop} value is {value}") + public static void assertCssStyleColor(String loc, String prop, String value) { + $(loc).assertCssStyleColor(prop, value); + } + + /** + * This method verify the css color property value of is not equal to value provide for element + * locator + *

    + * Example: + *

    + * BDD + *

    + * + * assert 'my.ele.loc' color 'propertyStyle' value is not 'value'
    + *
    + *

    + * KWD + *

    + * + * @param loc + * : {0} : an element locator, can be direct locator value or a + * locator key stored in locator repository + * @param prop + * : {1} : color property (css style) to be verified + * @param value + * : {2} : value of color in hex or rgb or rgba + */ + @QAFTestStep(description = "assert {loc} color {prop} value is not {value}") + public static void assertNotCssStyleColor(String loc, String prop, String value) { + $(loc).assertNotCssStyleColor(prop, value); + } + /** + * set the attribute value for specific locator somewhere in the page. + *

    + * Example: + *

    + * BDD + *

    + * + * set 'my.ele.loc' attribute 'type' value is 'value'
    + *
    + *

    + * KWD + *

    + * + * @param loc + * : {0} : an element locator, can be direct locator value or a + * locator key stored in locator repository + * @param attr + * : {1} : attribute name which value not to be asserted + * @param value + * : {2} : value of attribute + */ + @QAFTestStep(description = "set {loc} attribute {attr} value is {value}") + public static void setAttribute(String loc, String attr, String value) { + $(loc).setAttribute(attr, value); + } + + /** + * add cookie, This will valid for the entire domain + * + * @param name + * : {0} name of the cookie + * @param value + * : {1} value of the cookie + */ + @QAFTestStep(description = "add cookie {name} with value {value}") + public static void addCookie(String name, String value) { + Cookie cookie = new Cookie(name, value); + new WebDriverTestBase().getDriver().manage().addCookie(cookie); + } + + /** + * Delete the named cookie from the current domain. This is equivalent to + * setting the named cookie's expiry date to some time in the past. + * + * @param name + * : {0} name of the cookie to be deleted + */ + @QAFTestStep(description = "delete cookie with name {name}") + public static void deleteCookie(String name) { + new WebDriverTestBase().getDriver().manage().deleteCookieNamed(name); + } + + /** + * Delete all the cookies for the current domain. + */ + @QAFTestStep(description = "delete all cookies") + public static void deleteAllCookies() { + new WebDriverTestBase().getDriver().manage().deleteAllCookies(); + } + + /** + * Get a cookie with a given name + * + * @param name + * : {0} name of the cookie + */ + @QAFTestStep(description = "get a cookie with a name {name}") + public static void getCookieValue(String name) { + new WebDriverTestBase().getDriver().manage().getCookieNamed(name).getValue(); + } + + @QAFTestStep(description = "mouse move on {loc}") + public static void mouseOver(String loc) { + new WebDriverTestBase().getDriver().getMouse().mouseMove(((QAFExtendedWebElement) $(loc)).getCoordinates()); + } + + /** + * Start time tracking which can be stopped by subsequent call to + * {@link #stopTransaction()}. It will group all steps and track time with + * given threshold comparison. + * + * @param name + * @param threshold + */ + @MetaData("{'qafstep-transaction':true}") + @QAFTestStep(stepName = "startTransactionWithThreshold", description = "start (step|transaction|time-tracker) (for|:) {task-name} with {second}s threshold") + public static void startTransaction(String name, int threshold) { + + } + + /** + * Start time tracking which can be stopped by subsequent call to + * {@link #stopTransaction()}. It will group all steps and track time. + * + * @param name + */ + @MetaData("{'qafstep-transaction':true}") + @QAFTestStep(description = "start (step|transaction|time-tracker) (for|:) {task-name}") + public static void startTransaction(String name) { + + } + + @MetaData("{'qafstep-transaction':true}") + @QAFTestStep(description = "(stop|end) (step|transaction|time-tracker)") + public static void stopTransaction() { + + } + + /** + * @param locator + * - locator of frame + * @return + */ + @QAFTestStep(stepName = "switchToFrame", description = "switch to frame {0}") + public static Object switchToFrame(String locator) { + return new WebDriverTestBase().getDriver().switchTo().frame(new QAFExtendedWebElement(locator)); + } + + /** + * switches the webdriver context to the parent frame + * + * @return + */ + @QAFTestStep(stepName = "switchToParentFrame", description = "switch to parent frame") + public static Object switchToParentFrame() { + return new WebDriverTestBase().getDriver().switchTo().parentFrame(); + } + + /** + * switched to the defult window. Generally used to come out of any frame + * context + * + * @return + */ + @QAFTestStep(stepName = "switchToDefaultWindow", description = "switch to default window") + public static Object switchToDefaultWindow() { + return new WebDriverTestBase().getDriver().switchTo().defaultContent(); + } + +} diff --git a/qaf-support/src/main/java/com/qmetry/qaf/automation/step/aop.xml b/qaf-support/src/main/java/com/qmetry/qaf/automation/step/aop.xml new file mode 100644 index 00000000..1f582204 --- /dev/null +++ b/qaf-support/src/main/java/com/qmetry/qaf/automation/step/aop.xml @@ -0,0 +1,30 @@ + + + + + + \ No newline at end of file diff --git a/qaf-testng/pom.xml b/qaf-testng/pom.xml index 93935f42..44959a77 100644 --- a/qaf-testng/pom.xml +++ b/qaf-testng/pom.xml @@ -1,4 +1,6 @@ - + 4.0.0 com.qmetry @@ -14,35 +16,34 @@ com.qmetry qaf-core - ${project.version} + ${qaf.version} com.qmetry qaf-selenium - ${project.version} + ${qaf.version} true com.qmetry qaf-ws - ${project.version} + ${qaf.version} true - + org.testng testng @@ -50,16 +51,28 @@ compile - org.beanshell - bsh - 2.0b5 - true - + org.beanshell + bsh + 2.0b5 + true + + + info.cukes + cucumber-java + 1.2.4 + test + - info.cukes - cucumber-java - 1.2.4 - test + org.seleniumhq.selenium + selenium-leg-rc + ${selenium.version} + true + + + * + * + + \ No newline at end of file diff --git a/qaf-testng/src/main/java/com/qmetry/qaf/automation/testng/pro/QAFTestNGListener.java b/qaf-testng/src/main/java/com/qmetry/qaf/automation/testng/pro/QAFTestNGListener.java index a38a7825..b608a085 100644 --- a/qaf-testng/src/main/java/com/qmetry/qaf/automation/testng/pro/QAFTestNGListener.java +++ b/qaf-testng/src/main/java/com/qmetry/qaf/automation/testng/pro/QAFTestNGListener.java @@ -47,6 +47,7 @@ import org.testng.ITestContext; import org.testng.ITestNGMethod; import org.testng.ITestResult; +import org.testng.SkipException; import org.testng.annotations.IConfigurationAnnotation; import org.testng.annotations.IDataProviderAnnotation; import org.testng.annotations.IFactoryAnnotation; @@ -61,6 +62,7 @@ import com.qmetry.qaf.automation.core.ConfigurationManager; import com.qmetry.qaf.automation.core.HtmlCheckpointResultFormatter; import com.qmetry.qaf.automation.core.QAFTestBase; +import com.qmetry.qaf.automation.core.SkipTestException; import com.qmetry.qaf.automation.core.TestBaseProvider; import com.qmetry.qaf.automation.keys.ApplicationProperties; import com.qmetry.qaf.automation.step.client.Scenario; @@ -233,6 +235,11 @@ protected void processResult(ITestResult tr, ITestContext context) { tr.setThrowable(new AssertionError(varificationFailures + " verification failed.")); } } + if(tr.getThrowable() != null && tr.getThrowable() instanceof SkipTestException) { + SkipTestException ste = (SkipTestException)tr.getThrowable(); + tr.setThrowable(new SkipException(ste.getMessage(), ste.getSelfOrCause())); + setSkip(tr, context); + } if (tr.getStatus() == ITestResult.FAILURE) { ReportUtils.setScreenshot(tr.getThrowable()); diff --git a/qaf-testng/src/main/resources/META-INF/MANIFEST.MF b/qaf-testng/src/main/resources/META-INF/MANIFEST.MF index d32161cd..a239c86e 100644 --- a/qaf-testng/src/main/resources/META-INF/MANIFEST.MF +++ b/qaf-testng/src/main/resources/META-INF/MANIFEST.MF @@ -1,4 +1,3 @@ -Vendor: Infostretch Corp. Built-By: ${user.name} Build-Java: ${java.version} Build-OS: ${os.name} diff --git a/qaf-tools/pom.xml b/qaf-tools/pom.xml index 2bb2a522..8f19ad79 100644 --- a/qaf-tools/pom.xml +++ b/qaf-tools/pom.xml @@ -15,17 +15,17 @@ com.qmetry qaf-core - ${project.version} + ${revision} com.qmetry qaf-ws - ${project.version} + ${revision} com.qmetry qaf-selenium - ${project.version} + ${revision} \ No newline at end of file diff --git a/qaf-tools/src/main/java/com/qmetry/qaf/automation/tools/MultiPropertiesEditorHelper.java b/qaf-tools/src/main/java/com/qmetry/qaf/automation/tools/MultiPropertiesEditorHelper.java index bc878dc5..bff7c6bd 100644 --- a/qaf-tools/src/main/java/com/qmetry/qaf/automation/tools/MultiPropertiesEditorHelper.java +++ b/qaf-tools/src/main/java/com/qmetry/qaf/automation/tools/MultiPropertiesEditorHelper.java @@ -5,7 +5,11 @@ import static com.qmetry.qaf.automation.util.FileUtil.isLocale; import java.io.File; +import java.io.FileWriter; import java.io.IOException; +import java.io.StringWriter; +import java.io.Writer; +import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.Collection; import java.util.HashMap; @@ -14,8 +18,10 @@ import org.apache.commons.configuration.ConfigurationException; import org.apache.commons.configuration.PropertiesConfiguration; +import org.apache.commons.lang.StringEscapeUtils; import com.google.common.io.Files; +import com.qmetry.qaf.automation.keys.ApplicationProperties; import com.qmetry.qaf.automation.util.StringUtil; public class MultiPropertiesEditorHelper { @@ -43,20 +49,29 @@ public static Collection> getContent(String filePath) { for(File file: files) { try { PropertiesConfiguration p = new PropertiesConfiguration(); - p.setEncoding(StandardCharsets.UTF_8.name()); + p.setEncoding( + ApplicationProperties.LOCALE_CHAR_ENCODING.getStringVal(StandardCharsets.UTF_8.toString())); p.load(file); String colName = getExtention(file.getName()); p.getKeys().forEachRemaining((k)->{ Map entry = entries.get(k); if(null == entry) { - entry = new HashMap(); + entry = new LinkedHashMap(); entry.put("key", (String)k); entries.put((String)k, entry); } - entry.put(colName, p.getString((String)k)); + String val = StringEscapeUtils.escapeHtml(p.getString((String)k)); + entry.put(colName, val); }); - + //add blank row + Map entry = entries.get(""); + if(null == entry) { + entry = new LinkedHashMap(); + entry.put("key", ""); + entries.put("", entry); + } + entry.put(colName, ""); } catch (Exception e) { System.err.println("Unable to read " + file + e.getMessage()); } @@ -67,14 +82,13 @@ public static Collection> getContent(String filePath) { public static void saveContent(Collection> data, String path) { File file = new File(path); - String name = file.getName(); + String name = Files.getNameWithoutExtension(file.getName()); String parent = file.getParent(); saveContent(data, name, parent); } - public static void saveContent(Collection> data, String name, String parent) { - Map properties = new HashMap(); - + private static void saveContent(Collection> data, String name, String parent) { + Map properties = new HashMap(); data.iterator().forEachRemaining(entry -> { String key = (String) entry.remove("key"); if (StringUtil.isNotBlank(key)) { @@ -87,7 +101,8 @@ public static void saveContent(Collection> data, String name File target = new File(parent, String.join(".", name, colName)); target.createNewFile(); p = new PropertiesConfiguration(); - p.setEncoding(StandardCharsets.UTF_8.toString()); + p.setEncoding( + ApplicationProperties.LOCALE_CHAR_ENCODING.getStringVal(StandardCharsets.UTF_8.toString())); p.load(target); p.setFile(target); properties.put(colName, p); @@ -103,9 +118,21 @@ public static void saveContent(Collection> data, String name properties.values().forEach(p->{ try { - p.save(); - //p.save - } catch (ConfigurationException e2) { + String encoding = ApplicationProperties.LOCALE_CHAR_ENCODING.getStringVal(); + if(StringUtil.isNotBlank(encoding)) { + StringWriter sw = new StringWriter(); + p.save(sw); + try(Writer out = new FileWriter(p.getFile(), Charset.forName(encoding))){ + String tranStr = StringEscapeUtils.unescapeJava( sw.toString()); + //StringEscapeUtils.unescapeJava(out , sw.toString()); + out.write(tranStr); + out.flush(); + } + }else { + //save unicode; + p.save(); + } + } catch (ConfigurationException | IOException e2) { throw new RuntimeException(e2); } }); @@ -116,17 +143,12 @@ public static File[] getFiles(String name, boolean locale) { if(!locale || !isLocale(name) ) return new File[] {}; File f = new File(name); - f.getParentFile().listFiles((dir,fname)->{ + return f.getParentFile().listFiles((dir,fname)->{ return (!locale || isLocale(fname)) && Files.getNameWithoutExtension(fname).equalsIgnoreCase(Files.getNameWithoutExtension(name)); }); - return null; } public static File[] getFiles(String name) { return getFiles(name, isLocale(name)); } - - - - } diff --git a/qaf-tools/src/main/java/com/qmetry/qaf/automation/tools/RepoEditor.java b/qaf-tools/src/main/java/com/qmetry/qaf/automation/tools/RepoEditor.java index 661cd501..b6de4c76 100644 --- a/qaf-tools/src/main/java/com/qmetry/qaf/automation/tools/RepoEditor.java +++ b/qaf-tools/src/main/java/com/qmetry/qaf/automation/tools/RepoEditor.java @@ -152,7 +152,7 @@ private static HttpServer createServer(int port) { break; case "get_content": res.setEntity(new StringEntity( - JSONUtil.toString(getContent(queryParams.get("path"),Boolean.getBoolean(queryParams.getOrDefault("multi","false")))), + JSONUtil.toString(getContent(queryParams.get("path"),Boolean.valueOf(queryParams.getOrDefault("multi","false")))), ContentType.APPLICATION_JSON)); break; case "save_wsc": @@ -164,7 +164,7 @@ private static HttpServer createServer(int port) { break; case "save_loc": String data = IOUtils.toString(req.getEntity().getContent(), StandardCharsets.UTF_8); - saveContent(JSONUtil.toObject(data, List.class), queryParams.get("path"), Boolean.getBoolean(queryParams.getOrDefault("multi","false"))); + saveContent(JSONUtil.toObject(data, List.class), queryParams.get("path"), Boolean.valueOf(queryParams.getOrDefault("multi","false"))); break; case "load_resource": @@ -575,7 +575,13 @@ private static Object[] getNodes(String id) { rootNode.put("id", "resources"); rootNode.put("type", "folder"); rootNode.put("children", getNodes("resources")); - return new Object[] { rootNode }; + String bddLoc = ApplicationProperties.SCENARIO_FILE_LOC.getStringVal("scenarios"); + Map bddNode = new HashMap(); + bddNode.put("text", bddLoc); + bddNode.put("id", bddLoc); + bddNode.put("type", "folder"); + bddNode.put("children", getNodes(bddLoc)); + return new Object[] { rootNode, bddNode }; } File parent = new File(id); if (isWSC(parent.getName())) { @@ -616,6 +622,9 @@ private static Object[] getNodes(String id) { if (p.toFile().isDirectory()) { node.put("children", true); node.put("type", "folder"); + }else if (FileUtil.isLocale(p.toString())) { + node.put("children", false); + node.put("type", "file-locale"); } else { String type = FileUtil.getExtention(p.toString()); node.put("type", "file-"+type); @@ -701,8 +710,8 @@ private static Map getWSCFile(String file){ private static void saveContent(Collection> data, String file, boolean isMulti) throws IOException { if(isMulti) { - File f = new File(file); - MultiPropertiesEditorHelper.saveContent(data, f.getName(), f.getParent()); + MultiPropertiesEditorHelper.saveContent(data, file); + return; } Gson gson = new GsonBuilder().disableHtmlEscaping().serializeNulls().create(); String fileContent = null; diff --git a/qaf-ws/pom.xml b/qaf-ws/pom.xml index 2114810f..84a29f76 100644 --- a/qaf-ws/pom.xml +++ b/qaf-ws/pom.xml @@ -1,4 +1,6 @@ - + 4.0.0 com.qmetry @@ -15,7 +17,56 @@ com.qmetry qaf-core - ${project.version} + ${qaf.version} + + + com.sun.jersey.contribs + jersey-apache-client4 + 1.19.4 + compile + + + org.apache.httpcomponents + * + + + + + com.sun.jersey + jersey-client + 1.19 + compile + + + com.sun.jersey + jersey-core + 1.19 + compile + + + com.sun.jersey.contribs + jersey-multipart + 1.19 + compile + + + com.sun.jersey.contribs + jersey-apache-client + 1.17.1 + compile + + + + org.apache.httpcomponents + httpclient + 4.5.14 + compile + + + junit + * + + \ No newline at end of file diff --git a/qaf/pom.xml b/qaf/pom.xml index 5fd03653..dbffb37c 100644 --- a/qaf/pom.xml +++ b/qaf/pom.xml @@ -14,27 +14,27 @@ com.qmetry qaf-core - ${project.version} + ${revision} com.qmetry qaf-ws - ${project.version} + ${revision} com.qmetry qaf-testng - ${project.version} + ${revision} com.qmetry qaf-selenium - ${project.version} + ${revision} com.qmetry qaf-tools - ${project.version} + ${revision} \ No newline at end of file