package base; import com.codeborne.selenide.Configuration; import com.google.common.collect.ImmutableMap; import net.ihe.gazelle.test.data_structure.LoginProfile; import net.ihe.gazelle.test.enums.Languages; import net.ihe.gazelle.test.page.MainPage; import net.ihe.gazelle.test.tool.ErrorChecker; import net.ihe.gazelle.test.tool.Loader; import net.ihe.gazelle.test.tool.Tool; import org.apache.commons.io.FileUtils; import org.openqa.selenium.*; import org.openqa.selenium.chrome.ChromeDriver; import org.openqa.selenium.chrome.ChromeDriverService; import org.openqa.selenium.firefox.FirefoxBinary; import org.openqa.selenium.firefox.FirefoxDriver; import org.openqa.selenium.firefox.FirefoxProfile; import org.openqa.selenium.ie.InternetExplorerDriver; import org.openqa.selenium.opera.OperaDriver; import org.openqa.selenium.opera.OperaDriverService; import org.openqa.selenium.remote.DesiredCapabilities; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.testng.Assert; import java.io.File; import java.io.IOException; import java.util.concurrent.*; import java.util.concurrent.TimeoutException; import java.util.logging.Level; import java.util.regex.Matcher; import java.util.regex.Pattern; import static com.codeborne.selenide.WebDriverRunner.closeWebDriver; /** *

* Base class for every test. Contains the WebDriver and the data set. Contains the method used to restart the database and perform the test *

*

*

* There are two important methods : run() and testScenario(). *

*

* run() is the {@literal @}Test method for every scenario class and is overriden in every child class : dataSet initializations are made there. Then super.run() is called. In the super.run() are called several all-time * initializations : webDriver and database. After those initializations, super.run() will call try{ testScenario() } several times, until it returns successfully. *

*

* BaseTest.testScenario() is "abstract" and is destined to be overriden in every child class. In every child class, testScenario() contains all scenario's instructions and * assertions. *

*
*

* This allows concentrate initializations and error filtering in the same place (BaseTest) and to have all specific code in each specific class. *

* * @author sbs */ public class BaseTest { private Object[][] dataSets; // Get the child class name of the test's class (without the whole path) private String testCaseName = ""; private static Logger log = LoggerFactory.getLogger(BaseTest.class); public BaseTest withDataSets(Object[][] ds) { dataSets = ds; return this; } /** * Logout inside a try */ public void safetyLogout() { try { new MainPage(new LoginProfile( Loader.instance().config("Account.Admin.Login"), Loader.instance().config("Account.Admin.Password"), Languages.ENGLISH)).logout(); } catch (Exception e) { System.out.println("couldn't logout"); e.printStackTrace(); } } /** * Sleeps for a given time in milliseconds * * @param millis */ public void pause(int millis) { try { Thread.sleep(millis); } catch (InterruptedException e) { } } /** * Performs universal initializations like database restart and webDriver creation. * Calls testScenario() until it succeeds or until the max amount of trials has been reached */ public void run() { WebDriverException lastException = null; boolean properlyFinished = false; int trials = 1; final int MAX_TRIALS = Integer.parseInt(Loader.instance().config("test.max.trials")); java.util.logging.Logger.getLogger("com.codeborne.selenide.webdriver").setLevel(Level.WARNING); java.util.logging.Logger.getLogger("com.codeborne.selenide.impl").setLevel(Level.WARNING); try { Matcher m = Pattern.compile("\\.([^.]+)$").matcher(Thread.currentThread().getStackTrace()[2].getClassName()); if (m.find()) testCaseName = m.group(1); } catch (Exception e) { testCaseName = "No-name"; } while (trials - 1 < MAX_TRIALS && !properlyFinished) { try { // EXECUTION log.info("Executing the test : " + testCaseName); for (Object[] ds : dataSets) { testScenario(ds); } properlyFinished = true; } catch (WebDriverException e) { if (Loader.instance().config("Debug").equals("true")) e.printStackTrace(); lastException = e; log.warn("There were non-managed WebDriverException during the execution." + " Trying again to run this test (" + trials+1 + "/" + MAX_TRIALS + ")"); trials++; } catch (AssertionError e) { log.warn("Test failed :" + e + " Trying to re-run it (" + trials + "/" + MAX_TRIALS + ")"); trials++; } finally { // TEAR DOWN closeWebDriver(); } } if (!properlyFinished) { if (lastException != null) { lastException.printStackTrace(); Assert.fail("The test run didn't finish without exception"); } } } /** * Destined to be overriden in every child test class. testScenario() is called by run(). It contains all the scenario code. * * @param ds TODO */ public void testScenario(Object[] ds) { } private static void executeCommand(String command, long timeoutInSeconds) throws Exception { ExecutorService service = Executors.newSingleThreadExecutor(); Process process = Runtime.getRuntime().exec(command); try { Callable call = new CallableProcess(process); Future future = service.submit(call); int exitValue = future.get(timeoutInSeconds, TimeUnit.SECONDS); if (exitValue != 0) { throw new Exception("Process did not exit correctly"); } } catch (ExecutionException e) { throw new Exception("Process failed to execute", e); } catch (TimeoutException e) { process.destroy(); throw new Exception("Process timed out", e); } finally { service.shutdown(); } } private static class CallableProcess implements Callable { private Process p; public CallableProcess(Process process) { p = process; } public Integer call() throws Exception { return p.waitFor(); } } /** * Checks for an error and throws a new WebDriverException if one is found. * Errors are defined in the class ErrorPages. * An error is, for example, error.seam. * This method is used to tell the run() method that a test didn't run as expected but should be tried again. * * @return * @throws WebDriverException */ public static boolean checkForError() throws WebDriverException { return ErrorChecker.checkForError(); } }