package base; 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.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.regex.Matcher; import java.util.regex.Pattern; /** *

* 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 static WebDriver driver; public static Logger log = LoggerFactory.getLogger(BaseTest.class); private Object[][] dataSets; // Get the child class name of the test's class (without the whole path) private String testCaseName = ""; public static WebDriver getDriver() { return driver; } 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(); } } /** * 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(getDriver()); } public BaseTest withDataSets(Object[][] ds) { dataSets = ds; return this; } /** * Logout inside a try */ public void safetyLogout() { try { new MainPage(driver, 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")); final String BROWSER = String.valueOf(Loader.instance().config("browser.name")); 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 { // SETUP initWebDriver(BROWSER); // EXECUTION log.info("Executing the test : " + testCaseName + " on Thread " + Thread.currentThread().getId()); for (Object[] ds : dataSets) { testScenario(ds); } properlyFinished = true; } catch (WebDriverException e) { takeDebugScreenshot(); if (Loader.instance().config("Debug").equals("true")) e.printStackTrace(); lastException = e; trials++; log.warn("There were non-managed WebDriverException during the execution." + " Trying again to run this test (" + trials + "/" + MAX_TRIALS + ")"); } catch (AssertionError e) { takeDebugScreenshot(); log.warn("Test failed :" + e); throw e; } finally { // TEAR DOWN try { closeWebDriver(); } catch (Exception ex) { log.warn("couldn't close the driver"); } } } if (!properlyFinished) { if (lastException != null) { lastException.printStackTrace(); Assert.fail("The test run didn't finish without exception"); } } } /** * Calls for database restore and jboss restart. * Calls for Command.Database.Restore, it it takes more than 500s, calls for Command.Jboss.Restart * Commands are configurable in config.properties * Returns when command returned or when timed out (500 for the database restore + 200 for the jboss restart) */ /* public void initDatabase() { if (Loader.instance().config("Auto.DataBase.Restore").equals("true")) { log.info("Restoring database..."); try { executeCommand(Loader.instance().config("Command.Database.Restore"), 500); log.info("Database restored"); } catch (Exception e) { log.error("Error during the call of the restoration command, restarting jboss"); try { executeCommand(Loader.instance().config("Command.Jboss.Restart"), 200); log.info("Jboss restarted"); } catch (Exception ex) { log.error("Couldn't restart jboss"); } e.printStackTrace(); } } }*/ public void takeDebugScreenshot() { File scrFile = ((TakesScreenshot) getDriver()).getScreenshotAs(OutputType.FILE); String dirName = "./" + testCaseName; try { boolean existingDir = new File(dirName).exists(); if (!existingDir) { new File(dirName).mkdirs(); } //Copy Driver screenshot to current jenkin's job workspace, add current datetime in file name. FileUtils.copyFile(scrFile, new File(dirName + "/" + getDriver().getTitle() + "-screen-" + Tool.getDate() + ".png")); } catch (IOException e) { e.printStackTrace(); } } /** * 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) { } /** * Prepare a new instance of webdriver * * @param browser the current browser to setup **/ public void initWebDriver(String browser) { //Web driver path sets in pom.xml String CHROME_DRIVER = String.valueOf(Loader.instance().config("webdriver.chrome.binary.location")); String IE_DRIVER = String.valueOf(Loader.instance().config("webdriver.ie.binary.location")); //X Server port configuration on xvfb environment String xPort = System.getProperty("Importal.xvfb.id", ":1"); log.info("Setting up browser : " + browser.toUpperCase()); if (browser.contains("firefox")) { driver = setupFirefoxWebDriver(xPort); } else if (browser.contains("chrome")) { driver = setupChromeWebDriver(xPort, CHROME_DRIVER); } else if (browser.contains("ie")) { driver = setupInternetExplorerDriver(IE_DRIVER); } else { log.info("Browser " + browser.toUpperCase() + " not recognized. Using FIREFOX instead."); driver = setupFirefoxWebDriver(xPort); } } private WebDriver setupInternetExplorerDriver(String binary) { System.setProperty("webdriver.ie.driver", binary); DesiredCapabilities capabilities = DesiredCapabilities.internetExplorer(); capabilities.setCapability(InternetExplorerDriver.INTRODUCE_FLAKINESS_BY_IGNORING_SECURITY_DOMAINS, true); WebDriver webDriver = new InternetExplorerDriver(capabilities); webDriver.manage().window().maximize(); webDriver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS); return webDriver; } private WebDriver setupChromeWebDriver(String xPort, String binary) { System.setProperty("webdriver.chrome.driver", binary); DesiredCapabilities capabilities = DesiredCapabilities.chrome(); capabilities.setPlatform(Platform.LINUX); WebDriver webDriver; if (Loader.instance().config("headless").equals("true")) { ChromeDriverService service = new ChromeDriverService.Builder() .usingAnyFreePort() .withEnvironment(ImmutableMap.of("DISPLAY", xPort)).withSilent(true).build(); webDriver = new ChromeDriver(service, capabilities); } else { webDriver = new ChromeDriver(capabilities); } webDriver.manage().window().maximize(); webDriver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS); return webDriver; } private WebDriver setupFirefoxWebDriver(String xPort) { FirefoxProfile firefoxProfile = new FirefoxProfile(); firefoxProfile.setPreference("browser.download.folderList", 2); firefoxProfile.setPreference("browser.download.manager.showWhenStarting", false); // The download directory firefoxProfile.setPreference("browser.download.dir", Loader.instance().config("firefox.download.directory")); // The list of MIME types firefox will automatically download without showing a prompt window firefoxProfile.setPreference("browser.helperApps.neverAsk.saveToDisk", "text/csv" + ",application/vnd.ms-excel" + ",application/pdf" + ",application/xml" + ",application/zip" + ",text/plain" + ",application/vnd.oasis.opendocument.text" + ",application/vnd.oasis.opendocument.spreadsheet" + ",application/vnd.oasis.opendocument.presentation" + ",application/vnd.oasis.opendocument.graphics" + ",application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" + ",application/vnd.ms-powerpoint" + ",application/msword" + ",application/vnd.openxmlformats-officedocument.wordprocessingml.document"); WebDriver webDriver; if (Loader.instance().config("headless").equals("true")) { FirefoxBinary firefoxBinary = new FirefoxBinary(); firefoxBinary.setEnvironmentProperty("DISPLAY", xPort); webDriver = new FirefoxDriver(firefoxBinary, firefoxProfile); } else { webDriver = new FirefoxDriver(firefoxProfile); } webDriver.manage().window().maximize(); webDriver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS); return webDriver; } public void closeWebDriver() { driver.quit(); driver = null; } private static class CallableProcess implements Callable { private Process p; public CallableProcess(Process process) { p = process; } public Integer call() throws Exception { return p.waitFor(); } } }