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