From 073fe865b78934f76681e6518aee41cfe1a980e4 Mon Sep 17 00:00:00 2001 From: msiwiec Date: Wed, 1 Oct 2014 12:52:45 -0600 Subject: [PATCH 1/3] first go at element validation port and test handling of verifications list --- .../com/prototest/jgolem/core/Validation.java | 8 ++ .../prototest/jgolem/core/Verifications.java | 108 ++++++++++++++++++ .../jgolem/core/VerificationsListener.java | 18 +++ .../com/prototest/jgolem/web/Element.java | 14 +-- .../ElementValidation.java} | 59 ++++++---- .../jgolem/web/WebBrowserTestBase.java | 3 + .../prototest/jgolem/GoogleResultsPage.java | 4 +- 7 files changed, 182 insertions(+), 32 deletions(-) create mode 100644 jgolem/jgolem-core/src/main/java/com/prototest/jgolem/core/Validation.java create mode 100644 jgolem/jgolem-core/src/main/java/com/prototest/jgolem/core/Verifications.java create mode 100644 jgolem/jgolem-core/src/main/java/com/prototest/jgolem/core/VerificationsListener.java rename jgolem/jgolem-core/src/main/java/com/prototest/jgolem/{core/Verification.java => web/ElementValidation.java} (56%) diff --git a/jgolem/jgolem-core/src/main/java/com/prototest/jgolem/core/Validation.java b/jgolem/jgolem-core/src/main/java/com/prototest/jgolem/core/Validation.java new file mode 100644 index 0000000..558b5a3 --- /dev/null +++ b/jgolem/jgolem-core/src/main/java/com/prototest/jgolem/core/Validation.java @@ -0,0 +1,8 @@ +package com.prototest.jgolem.core; + +public interface Validation { + public Validation not(); + public Validation containsText(String text); + public Validation isVisible(); + public Validation isPresent(); +} diff --git a/jgolem/jgolem-core/src/main/java/com/prototest/jgolem/core/Verifications.java b/jgolem/jgolem-core/src/main/java/com/prototest/jgolem/core/Verifications.java new file mode 100644 index 0000000..26bbc15 --- /dev/null +++ b/jgolem/jgolem-core/src/main/java/com/prototest/jgolem/core/Verifications.java @@ -0,0 +1,108 @@ +package com.prototest.jgolem.core; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.testng.Assert; + +import java.util.LinkedList; +import java.util.List; + +/** + * Verifications are like non-terminating assertions. This allows us to validate part of the test without stopping the test if the validations fail. + * A list of all validations is kept, and at the end of the test the VerificationsListener will inject it into the test and validate all validations passed. + */ +public class Verifications { + + private static Logger logger = LogManager.getLogger(Verification.class.getName()); + + // The list of verifications kept during the test. After the test is finished this list will be checked to validate all verifications passed. + private static List verifications = new LinkedList<>(); + public static List getVerifications() { + return verifications; + } + + public static void clearVerifications() { + verifications.clear(); + } + + /** + * Checks the list of verifications and fails the test if any of them did not pass. Use this to fail a test for failed verificaitons. + */ + public static boolean assertVerifications() { + String failed = getFailures(); + if (failed.length() > 0) { + //Reporter.getCurrentTestResult().setStatus(ITestResult.FAILURE); + //Reporter.getCurrentTestResult().setThrowable(new AssertionFailedError(String.format("The test failed due to %s verification errors",numFailed))); + Assert.fail(String.format("The test failed due to verification errors:\n%s", failed)); + return false; + } + + return true; + } + + /** + * Add a verification to the list, using a specified message, and whether or not it passed. + */ + public static void addVerification(String message, boolean passed) { + String msg = String.format("Verification %s : %s", (passed ? "Passed" : "Failed"), message); + + if (passed) { + logger.debug(msg); + verifications.add(new Verification(msg, true)); + } else { + logger.error(msg); + // TODO: screenshot - logger.screenshot(); + verifications.add(new Verification(message, "", false)); + } + } + + /** + * Add a verification to the list, using a specified message, a path to a screenshot, and whether or not it passed. + */ + public static void addVerification(String message, String filePath, boolean passed) { + if (passed) { + logger.debug(String.format("Verification Passed : %S", message)); + } else { + logger.error(String.format("Verification Failed : %S", message)); + // TODO: implement image save in logger -- logger.image(new File(filePath)); + } + verifications.add(new Verification(message, filePath, false)); + + } + + /** + * Get the list of failed verifications in a string. + */ + public static String getFailures() { + StringBuilder errors = new StringBuilder(); + for (Verification verification : verifications) { + if (!verification.passed) { + errors.append("\t" + verification.errorMessage); + } + + } + return errors.toString(); + } + + static class Verification { + + public String errorMessage; + public String imagePath; + public boolean passed; + + // Create a verification with a specific message, a specific image, and whether or not the verification passed. + Verification(String errorMessage, String imagePath, boolean passed) { + this.errorMessage = errorMessage; + this.imagePath = imagePath; + this.passed = passed; + } + + // Create a verification with a specific message, and whether or not the verification passed. + Verification(String errorMessage, boolean passed) { + this.errorMessage = errorMessage; + this.imagePath = ""; + this.passed = passed; + } + } +} + diff --git a/jgolem/jgolem-core/src/main/java/com/prototest/jgolem/core/VerificationsListener.java b/jgolem/jgolem-core/src/main/java/com/prototest/jgolem/core/VerificationsListener.java new file mode 100644 index 0000000..cc434cf --- /dev/null +++ b/jgolem/jgolem-core/src/main/java/com/prototest/jgolem/core/VerificationsListener.java @@ -0,0 +1,18 @@ +package com.prototest.jgolem.core; + +import org.testng.IHookCallBack; +import org.testng.IHookable; +import org.testng.ITestResult; + +/** + */ +public class VerificationsListener implements IHookable { + @Override + public void run(IHookCallBack callBack, ITestResult testResult) { + callBack.runTestMethod(testResult); + + Verifications.assertVerifications(); + Verifications.clearVerifications(); + + } +} diff --git a/jgolem/jgolem-core/src/main/java/com/prototest/jgolem/web/Element.java b/jgolem/jgolem-core/src/main/java/com/prototest/jgolem/web/Element.java index 94754de..caee1de 100644 --- a/jgolem/jgolem-core/src/main/java/com/prototest/jgolem/web/Element.java +++ b/jgolem/jgolem-core/src/main/java/com/prototest/jgolem/web/Element.java @@ -1,9 +1,5 @@ package com.prototest.jgolem.web; -import com.google.inject.Inject; -import com.google.inject.Injector; -import com.prototest.jgolem.core.AutoInjection; -import com.prototest.jgolem.core.Verification; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.openqa.selenium.*; @@ -14,13 +10,11 @@ //Element class can be instantiated any time but only looks for the element on the page when a function is called public class Element extends WebAutoInjection implements WebElement { - private By by; private String name; private WebElement element; private Logger logger = LogManager.getLogger(getClass()); - //public Verification Verify; public Element(String name, By by) { this.name = name; @@ -29,12 +23,12 @@ public Element(String name, By by) { //this.driver = TestBase.getDriver(); } - public Verification verify() { + public ElementValidation verify() { return verify(10); } - public Verification verify(int timeoutSec) { - return new Verification(this, timeoutSec); + public ElementValidation verify(int timeoutSec) { + return new ElementValidation(this, timeoutSec); } public By getBy() { @@ -61,6 +55,8 @@ public String getText() { return getElement().getText(); } + public String getValue() {return getElement().getAttribute("value");} + public String getAttribute(String attribute) { try { return getElement().getAttribute(attribute); diff --git a/jgolem/jgolem-core/src/main/java/com/prototest/jgolem/core/Verification.java b/jgolem/jgolem-core/src/main/java/com/prototest/jgolem/web/ElementValidation.java similarity index 56% rename from jgolem/jgolem-core/src/main/java/com/prototest/jgolem/core/Verification.java rename to jgolem/jgolem-core/src/main/java/com/prototest/jgolem/web/ElementValidation.java index b58c317..07e59fe 100644 --- a/jgolem/jgolem-core/src/main/java/com/prototest/jgolem/core/Verification.java +++ b/jgolem/jgolem-core/src/main/java/com/prototest/jgolem/web/ElementValidation.java @@ -1,10 +1,13 @@ -package com.prototest.jgolem.core; +package com.prototest.jgolem.web; -import com.prototest.jgolem.web.Element; +import com.prototest.jgolem.core.Validation; +import com.prototest.jgolem.core.Verifications; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import java.util.function.Function; -public class Verification { +public class ElementValidation implements Validation { protected Element element; protected boolean isTrue; protected boolean condition; @@ -12,26 +15,26 @@ public class Verification { protected String conditional; protected int timeout; + private Logger logger = LogManager.getLogger(getClass()); private Function validation = (result -> result); - protected Verification() { - - } - - public Verification(Element element, int timeout) { + public ElementValidation(Element element, int timeout) { this.element = element; this.conditional = " not"; this.timeout = timeout; } - protected void ValidateCondition() { + protected void validateCondition() { + boolean passed = true; + if (!validation.apply(condition)) { - System.out.println("Verification Failed : " + this.message); + passed = false; } + Verifications.addVerification(this.message, passed); } - protected boolean WaitForElement() { + protected boolean waitForElement() { for (int i = 0; i < this.timeout; i++) { if (element.isPresent()) return true; @@ -46,35 +49,49 @@ protected boolean WaitForElement() { return false; } - public Verification ContainsText(String text) { - if (WaitForElement()) { + public ElementValidation containsValue(String text) { + if (waitForElement()) { + this.condition = this.element.getValue().contains(text); + this.message = String.format("Element (%s) does%s contain value %s", element.getBy().toString(), conditional, text); + } + + validateCondition(); + return this; + } + + @Override + public Validation containsText(String text) { + if (waitForElement()) { this.condition = this.element.getText().contains(text); this.message = String.format("Element (%s) does%s contain text %s", element.getBy().toString(), conditional, text); } - ValidateCondition(); + validateCondition(); return this; } - public Verification IsVisible() { - if (WaitForElement()) { + @Override + public Validation isVisible() { + if (waitForElement()) { this.condition = this.element.isDisplayed(); this.message = String.format("Element (%s) is%s visible ", element.getBy().toString(), conditional); } - ValidateCondition(); + validateCondition(); return this; } - public Verification IsPresent() { - if (WaitForElement()) { + @Override + public Validation isPresent() { + if (waitForElement()) { this.condition = this.element.isPresent(); this.message = String.format("Element (%s) is%s present", element.getBy().toString(), conditional); } - ValidateCondition(); + validateCondition(); return this; } - public Verification Not() { + @Override + public Validation not() { this.conditional = ""; // Invert the result this.validation = (result -> !result); diff --git a/jgolem/jgolem-core/src/main/java/com/prototest/jgolem/web/WebBrowserTestBase.java b/jgolem/jgolem-core/src/main/java/com/prototest/jgolem/web/WebBrowserTestBase.java index 28468cf..9c9eb75 100644 --- a/jgolem/jgolem-core/src/main/java/com/prototest/jgolem/web/WebBrowserTestBase.java +++ b/jgolem/jgolem-core/src/main/java/com/prototest/jgolem/web/WebBrowserTestBase.java @@ -2,9 +2,12 @@ import com.google.inject.Inject; import com.prototest.jgolem.core.TestBase; +import com.prototest.jgolem.core.VerificationsListener; import org.openqa.selenium.WebDriver; import org.testng.annotations.Guice; +import org.testng.annotations.Listeners; +@Listeners({VerificationsListener.class}) @Guice(modules = WebTestsModule.class) public class WebBrowserTestBase extends TestBase { @Inject diff --git a/jgolem_test/pageobjects-google/src/main/java/com/prototest/jgolem/GoogleResultsPage.java b/jgolem_test/pageobjects-google/src/main/java/com/prototest/jgolem/GoogleResultsPage.java index d36f1cb..6a07630 100644 --- a/jgolem_test/pageobjects-google/src/main/java/com/prototest/jgolem/GoogleResultsPage.java +++ b/jgolem_test/pageobjects-google/src/main/java/com/prototest/jgolem/GoogleResultsPage.java @@ -28,13 +28,13 @@ public GoogleResultsPage SearchFor(String text) public GoogleResultsPage VerifyResult(String text) { - searchResult(text).verify(10).IsVisible(); + searchResult(text).verify(10).isVisible(); return new GoogleResultsPage(); } public GoogleResultsPage VerifyResultNotVisible(String text) { - searchResult(text).verify(10).Not().IsVisible(); + searchResult(text).verify(10).not().isVisible(); return new GoogleResultsPage(); } From 9be2ead8572db1acbbff32411c8297863ee21ad2 Mon Sep 17 00:00:00 2001 From: msiwiec Date: Wed, 1 Oct 2014 21:42:42 -0600 Subject: [PATCH 2/3] create abstract element verification class implementation --- .../core/AbstractElementValidationImpl.java | 64 +++++++++++++++++++ .../jgolem/web/ElementValidation.java | 34 +--------- 2 files changed, 67 insertions(+), 31 deletions(-) create mode 100644 jgolem/jgolem-core/src/main/java/com/prototest/jgolem/core/AbstractElementValidationImpl.java diff --git a/jgolem/jgolem-core/src/main/java/com/prototest/jgolem/core/AbstractElementValidationImpl.java b/jgolem/jgolem-core/src/main/java/com/prototest/jgolem/core/AbstractElementValidationImpl.java new file mode 100644 index 0000000..d7cb385 --- /dev/null +++ b/jgolem/jgolem-core/src/main/java/com/prototest/jgolem/core/AbstractElementValidationImpl.java @@ -0,0 +1,64 @@ +package com.prototest.jgolem.core; + +import com.prototest.jgolem.web.Element; // TODO, make Element interface + +import java.util.function.Function; + +public abstract class AbstractElementValidationImpl implements Validation { + protected Element element; + protected boolean isTrue; + protected boolean condition; + protected String message; + protected String conditional; + protected int timeout; + + private Function validation = (result -> result); + + public AbstractElementValidationImpl(Element element, int timeout) { + this.element = element; + this.conditional = " not"; + this.timeout = timeout; + } + + protected void validateCondition() { + boolean passed = true; + + if (!validation.apply(condition)) { + passed = false; + } + + Verifications.addVerification(this.message, passed); + } + + protected boolean waitForElement() { + for (int i = 0; i < this.timeout; i++) { + if (element.isPresent()) + return true; + else + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + } + } + this.condition = false; + this.message = String.format("Element (%s) is%s present", element.getBy().toString(), conditional); + return false; + } + + @Override + public abstract Validation containsText(String text); + + @Override + public abstract Validation isVisible(); + + @Override + public abstract Validation isPresent(); + + @Override + public Validation not() { + this.conditional = ""; + // Invert the result + this.validation = (result -> !result); + return this; + } +} diff --git a/jgolem/jgolem-core/src/main/java/com/prototest/jgolem/web/ElementValidation.java b/jgolem/jgolem-core/src/main/java/com/prototest/jgolem/web/ElementValidation.java index 07e59fe..253dfe5 100644 --- a/jgolem/jgolem-core/src/main/java/com/prototest/jgolem/web/ElementValidation.java +++ b/jgolem/jgolem-core/src/main/java/com/prototest/jgolem/web/ElementValidation.java @@ -1,37 +1,17 @@ package com.prototest.jgolem.web; +import com.prototest.jgolem.core.AbstractElementValidationImpl; import com.prototest.jgolem.core.Validation; -import com.prototest.jgolem.core.Verifications; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import java.util.function.Function; -public class ElementValidation implements Validation { - protected Element element; - protected boolean isTrue; - protected boolean condition; - protected String message; - protected String conditional; - protected int timeout; +public class ElementValidation extends AbstractElementValidationImpl { private Logger logger = LogManager.getLogger(getClass()); - private Function validation = (result -> result); public ElementValidation(Element element, int timeout) { - this.element = element; - this.conditional = " not"; - this.timeout = timeout; - } - - protected void validateCondition() { - boolean passed = true; - - if (!validation.apply(condition)) { - passed = false; - } - - Verifications.addVerification(this.message, passed); + super(element,timeout); } protected boolean waitForElement() { @@ -89,12 +69,4 @@ public Validation isPresent() { validateCondition(); return this; } - - @Override - public Validation not() { - this.conditional = ""; - // Invert the result - this.validation = (result -> !result); - return this; - } } From 511298ae18d1dbf6d13c0a9470b0d741c92eb8d5 Mon Sep 17 00:00:00 2001 From: msiwiec Date: Thu, 2 Oct 2014 21:13:18 -0600 Subject: [PATCH 3/3] Revert "create abstract element verification class implementation" This reverts commit 9be2ead8572db1acbbff32411c8297863ee21ad2. --- .../core/AbstractElementValidationImpl.java | 64 ------------------- .../jgolem/web/ElementValidation.java | 34 +++++++++- 2 files changed, 31 insertions(+), 67 deletions(-) delete mode 100644 jgolem/jgolem-core/src/main/java/com/prototest/jgolem/core/AbstractElementValidationImpl.java diff --git a/jgolem/jgolem-core/src/main/java/com/prototest/jgolem/core/AbstractElementValidationImpl.java b/jgolem/jgolem-core/src/main/java/com/prototest/jgolem/core/AbstractElementValidationImpl.java deleted file mode 100644 index d7cb385..0000000 --- a/jgolem/jgolem-core/src/main/java/com/prototest/jgolem/core/AbstractElementValidationImpl.java +++ /dev/null @@ -1,64 +0,0 @@ -package com.prototest.jgolem.core; - -import com.prototest.jgolem.web.Element; // TODO, make Element interface - -import java.util.function.Function; - -public abstract class AbstractElementValidationImpl implements Validation { - protected Element element; - protected boolean isTrue; - protected boolean condition; - protected String message; - protected String conditional; - protected int timeout; - - private Function validation = (result -> result); - - public AbstractElementValidationImpl(Element element, int timeout) { - this.element = element; - this.conditional = " not"; - this.timeout = timeout; - } - - protected void validateCondition() { - boolean passed = true; - - if (!validation.apply(condition)) { - passed = false; - } - - Verifications.addVerification(this.message, passed); - } - - protected boolean waitForElement() { - for (int i = 0; i < this.timeout; i++) { - if (element.isPresent()) - return true; - else - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - } - } - this.condition = false; - this.message = String.format("Element (%s) is%s present", element.getBy().toString(), conditional); - return false; - } - - @Override - public abstract Validation containsText(String text); - - @Override - public abstract Validation isVisible(); - - @Override - public abstract Validation isPresent(); - - @Override - public Validation not() { - this.conditional = ""; - // Invert the result - this.validation = (result -> !result); - return this; - } -} diff --git a/jgolem/jgolem-core/src/main/java/com/prototest/jgolem/web/ElementValidation.java b/jgolem/jgolem-core/src/main/java/com/prototest/jgolem/web/ElementValidation.java index 253dfe5..07e59fe 100644 --- a/jgolem/jgolem-core/src/main/java/com/prototest/jgolem/web/ElementValidation.java +++ b/jgolem/jgolem-core/src/main/java/com/prototest/jgolem/web/ElementValidation.java @@ -1,17 +1,37 @@ package com.prototest.jgolem.web; -import com.prototest.jgolem.core.AbstractElementValidationImpl; import com.prototest.jgolem.core.Validation; +import com.prototest.jgolem.core.Verifications; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import java.util.function.Function; -public class ElementValidation extends AbstractElementValidationImpl { +public class ElementValidation implements Validation { + protected Element element; + protected boolean isTrue; + protected boolean condition; + protected String message; + protected String conditional; + protected int timeout; private Logger logger = LogManager.getLogger(getClass()); + private Function validation = (result -> result); public ElementValidation(Element element, int timeout) { - super(element,timeout); + this.element = element; + this.conditional = " not"; + this.timeout = timeout; + } + + protected void validateCondition() { + boolean passed = true; + + if (!validation.apply(condition)) { + passed = false; + } + + Verifications.addVerification(this.message, passed); } protected boolean waitForElement() { @@ -69,4 +89,12 @@ public Validation isPresent() { validateCondition(); return this; } + + @Override + public Validation not() { + this.conditional = ""; + // Invert the result + this.validation = (result -> !result); + return this; + } }