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(); }