package com.jazzautomation;
import com.google.common.base.Optional;
import static com.jazzautomation.WebUIManager.SYSTEM_BROWSERS_SETTING;
import com.jazzautomation.action.ComponentAction;
import com.jazzautomation.action.HtmlAction;
import com.jazzautomation.cucumber.And;
import com.jazzautomation.cucumber.Background;
import com.jazzautomation.cucumber.Feature;
import com.jazzautomation.cucumber.Scenario;
import com.jazzautomation.cucumber.Then;
import com.jazzautomation.page.DomElementExpectation;
import com.jazzautomation.page.Page;
import com.jazzautomation.report.ActionResult;
import com.jazzautomation.report.ExpectationResult;
import com.jazzautomation.report.FeatureResult;
import com.jazzautomation.report.ScenarioResult;
import com.jazzautomation.report.SuiteResult;
import com.jazzautomation.ui.Browsers;
import static com.jazzautomation.ui.Browsers.Chrome;
import static com.jazzautomation.ui.Browsers.IE;
import static com.jazzautomation.ui.Browsers.NOT_SPECIFIED;
import static com.jazzautomation.ui.Browsers.Safari;
import com.jazzautomation.ui.Settings;
import static com.jazzautomation.util.Constants.IMG_FOLDER_NAME;
import com.jazzautomation.util.WebActionException;
import org.apache.commons.io.FileUtils;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.remote.Augmenter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.threeten.bp.LocalDate;
import org.threeten.bp.format.DateTimeFormatter;
import java.io.File;
import java.net.MalformedURLException;
import java.util.List;
import java.util.Map;
import java.util.Set;
/** Suite processor class that will process test suites and run all features. */
public class SuiteProcessor
{
private static final Logger LOG = LoggerFactory.getLogger(SuiteProcessor.class);
private static final int SCREEN_CAPTURE_WAIT = 3000;
private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("MM_dd_yyyy");
private SuiteProcessor() {}
/**
* Processes the provided suite.
*
* @param suite the suite to be executed
* @param driver the web driver; optional
*/
public static void process(Suite suite, WebDriver driver)
{
SuiteResult result = runSuite(suite.getFeatures(), driver);
suite.setResult(result);
}
private static SuiteResult runSuite(List<Feature> features, WebDriver driver)
{
LOG.info("** Begin Suite **");
SuiteResult suiteResult = new SuiteResult();
long suiteTimeStarted = System.currentTimeMillis();
for (Feature feature : features)
{
runFeature(feature, suiteResult, driver);
}
long suiteTimeEnded = System.currentTimeMillis();
suiteResult.calculateSuccessRate();
suiteResult.setDuration((suiteTimeEnded - suiteTimeStarted) / 1000.0);
LOG.info("\nSuiteResult = \n" + suiteResult);
LOG.info("** End Suite **");
return suiteResult;
}
private static void runFeature(Feature feature, SuiteResult suiteResult, WebDriver driver)
{
long featureTimeStarted = System.currentTimeMillis();
FeatureResult featureResult = new FeatureResult();
featureResult.setFeature(feature);
suiteResult.addFeatureResult(featureResult);
Background background = feature.getBackground();
Map<String, String> backgroundSettings = background.getGiven().getSettings();
LOG.info("Background settings = [" + backgroundSettings + ']');
if (!backgroundSettings.isEmpty())
{
resetSettings(backgroundSettings, false);
}
// setting driver
if (driver == null)
{
try
{
driver = setWebDriver(WebUIManager.getInstance().getBrowser());
}
catch (MalformedURLException e)
{
featureResult.setMessage("Error: remoteWebDriver Url is incorrect (STOPPED): " + WebUIManager.getRemoteWebDriverUrl()
+ " Please check your settings.properties ");
featureResult.setSuccess(false);
resetSettings(null, true);
}
}
// go to the set
String startingSiteUrl = backgroundSettings.get("url").trim();
LOG.info("Navigating to site: " + startingSiteUrl);
assert driver != null;
driver.get(startingSiteUrl);
LOG.info("Go to feature [" + feature.getDescription() + "] with total [" + feature.getScenarios().size() + "] scenarios");
boolean isFirstPage = true;
JavascriptExecutor jsDriver = null;
for (Scenario scenario : feature.getScenarios())
{
if (isFirstPage)
{
jsDriver = WebUIManager.getInstance().getJQueryDriver(driver);
isFirstPage = false;
}
runScenario(scenario, featureResult, driver, jsDriver);
}
long featureTimeEnded = System.currentTimeMillis();
featureResult.setDuration((featureTimeEnded - featureTimeStarted) / 1000);
featureResult.calculateSuccessRate();
driver.quit();
}
private static void runScenario(Scenario scenario, FeatureResult featureResult, WebDriver driver, JavascriptExecutor jsDriver)
{
long scenarioTimeStarted = System.currentTimeMillis();
ScenarioResult scenarioResult = new ScenarioResult();
featureResult.addScenarioResult(scenarioResult);
scenarioResult.setScenario(scenario);
LOG.info("start working on scenario [" + scenario.getText() + ']');
Page page = scenario.getGiven().getPage();
pageSetup(driver, jsDriver, page);
// loading page
if (loadPage(scenario, driver, scenarioTimeStarted, scenarioResult, page))
{
return;
}
// take actions
takeActions(scenario, scenarioResult, page);
// verify expectations
verifyExpectations(scenario, driver, jsDriver, scenarioResult, page);
scenarioResult.calculateSuccessRate();
long scenarioTimeEnded = System.currentTimeMillis();
scenarioResult.setDuration((scenarioTimeEnded - scenarioTimeStarted) / 1000.0);
}
private static boolean loadPage(Scenario scenario, WebDriver driver, long scenarioTimeStarted, ScenarioResult scenarioResult, Page page)
{
if (!loadPage(scenario, scenarioResult, page))
{
scenarioResult.calculateSuccessRate();
long scenarioTimeEnded = System.currentTimeMillis();
scenarioResult.setDuration((scenarioTimeEnded - scenarioTimeStarted) / 1000);
if (scenario.isOptional())
{
LOG.info("Not able to load page [" + page.getPageName() + "] for scenario [" + scenario.getText() + ']');
scenarioResult.setScreenShotPath(captureScreen(driver));
}
else
{
scenarioResult.setSuccess(false);
LOG.info("Optional: Not able to load page [" + page.getPageName() + "] for scenario [" + scenario.getText() + ']');
scenarioResult.setScreenShotPath(captureScreen(driver));
}
return true;
}
return false;
}
private static void verifyExpectations(Scenario scenario, WebDriver driver, JavascriptExecutor jsDriver, ScenarioResult scenarioResult, Page page)
{
Then then = scenario.getThen();
if (then != null)
{
if (then.getPageExpected() != null)
{
pageSetup(driver, jsDriver, then.getPageExpected());
verifyPageExpectation(scenarioResult, then);
}
else
{
for (DomElementExpectation expect : then.getExpects())
{
verifyComponentExpectation(scenarioResult, page, expect);
}
}
}
}
private static void takeActions(Scenario scenario, ScenarioResult scenarioResult, Page page)
{
for (And and : scenario.getAnds())
{
LOG.info("Working on 'and' [" + and.getText() + ']');
for (ComponentAction componentAction : and.getActions())
{
executeAction(scenarioResult, page, and, componentAction);
}
}
}
/**
* What does return true mean? False? //CODEREVIEW - need docs
*
* @param scenario
* @param scenarioResult
* @param page
*
* @return
*/
private static boolean loadPage(Scenario scenario, ScenarioResult scenarioResult, Page page)
{
try
{
page.setup();
return true;
}
catch (Exception exception)
{
if (scenario.isOptional())
{
scenarioResult.setMessage("Skipped page for :" + page.getPageName() + " [" + exception.getMessage() + "].");
LOG.info("Skipped page for :" + page.getPageName() + " - optional.");
}
else
{
scenarioResult.setSuccess(false);
scenarioResult.setSuccessRate(0.0);
scenarioResult.setMessage("Failed to load page: " + page.getPageName() + " [" + exception.getMessage() + "].");
LOG.info("Failed to load page for :" + page.getPageName() + " for " + scenario.getText() + " Please check your feature settings");
}
return false;
}
}
private static void pageSetup(WebDriver driver, JavascriptExecutor jsDriver, Page page)
{
page.setWebDriver(driver);
page.setJsDriver(jsDriver);
WebUIManager webUiManager = WebUIManager.getInstance();
WebUIManager.loadJQuery(jsDriver);
LOG.info("Navigating to page " + page.getPageName());
page.setPageLoadTimeout(WebUIManager.getPageLoadTimeout());
page.setActionPace(WebUIManager.getActionPace());
page.setBrowser(webUiManager.getBrowser());
}
private static void verifyPageExpectation(ScenarioResult scenarioResult, Then then)
{
ExpectationResult expectResult = new ExpectationResult();
scenarioResult.addExpectResults(expectResult);
try
{
then.getPageExpected().setup();
expectResult.setSuccess(true);
}
catch (WebActionException e)
{
expectResult.setSuccess(false);
expectResult.setMessage("Expected to see page:" + then.getPageExpected().getPageName() + " Failed - " + e.getMessage());
scenarioResult.setScreenShotPath(captureScreen(then.getPageExpected().getWebDriver()));
}
}
private static void verifyComponentExpectation(ScenarioResult scenarioResult, Page page, DomElementExpectation expect)
{
ExpectationResult expectResult = new ExpectationResult();
scenarioResult.addExpectResults(expectResult);
expectResult.setComponentExpect(expect);
if (page.checkExpectation(expect))
{
expectResult.setSuccess(true);
}
else
{
expectResult.setSuccess(false);
expectResult.setMessage(expect.getMessage());
LOG.info("Failed to meet expect - capture screen ");
scenarioResult.setScreenShotPath(captureScreen(page.getWebDriver()));
}
}
private static void executeAction(ScenarioResult scenarioResult, Page page, And and, ComponentAction componentAction)
{
ActionResult actionResult = new ActionResult();
actionResult.setAnd(and);
actionResult.setAction(componentAction);
scenarioResult.addActionResult(actionResult);
try
{
if (componentAction.getAction() == HtmlAction.WAIT)
{
page.executeWebAction(null, componentAction.getAction(), componentAction.getActionValue());
}
else
{
page.executeWebAction(page.getDomElement(componentAction.getComponentName()), componentAction.getAction(), componentAction.getActionValue());
}
actionResult.setSuccess(true);
}
catch (WebActionException wae)
{
if (componentAction.isOptional())
{
actionResult.setSuccess(true);
actionResult.setMessage("Skipped action :" + componentAction.getAction() + ' ' + componentAction.getComponentName() + " - optional");
LOG.info("Skipped action :" + componentAction.getAction() + ' ' + componentAction.getComponentName() + " - optional");
}
else
{
actionResult.setMessage("Failed to take action :" + componentAction.getAction() + ' ' + componentAction.getComponentName() + " - "
+ wae.getMessage());
actionResult.setSuccess(false);
scenarioResult.setScreenShotPath(captureScreen(page.getWebDriver()));
LOG.info("Failed to take action :" + componentAction.getAction() + ' ' + componentAction.getComponentName());
}
}
}
private static void resetSettings(Map<String, String> backgroundSettings, boolean resetToNull)
{
WebUIManager uiManager = WebUIManager.getInstance();
if (resetToNull)
{
uiManager.setPlatform(null);
String browserProperty = Settings.getNotNullSystemProperty(SYSTEM_BROWSERS_SETTING);
// noinspection UnnecessarilyQualifiedStaticallyImportedElement
Optional<Browsers> possible = Browsers.findValueOf(browserProperty);
Browsers browser = possible.isPresent() ? possible.get()
: NOT_SPECIFIED;
uiManager.setBrowser(browser, true);
uiManager.setBrowserVersion(null);
}
else
{
Set<String> keys = backgroundSettings.keySet();
for (String key : keys)
{
if (key.toLowerCase().equals("platform"))
{
uiManager.setPlatform(backgroundSettings.get(key));
}
else if (key.toLowerCase().equals("browser"))
{
LOG.info("browser is " + backgroundSettings.get(key));
Optional<Browsers> possible = Browsers.findValueOf(backgroundSettings.get(key));
uiManager.setBrowser(possible.get(), false);
}
else if (key.toLowerCase().equals("browserVersion"))
{
uiManager.setBrowserVersion(backgroundSettings.get(key));
}
}
}
}
private static WebDriver setWebDriver(Browsers browser) throws MalformedURLException
{
WebUIManager webUIManager = WebUIManager.getInstance();
if (LOG.isDebugEnabled())
{
LOG.debug("browser name = '" + browser.getLowercaseName() + '\'');
}
WebDriver driver;
if (browser == Chrome)
{
driver = webUIManager.getChromeDriver(); // todo why isn't this a property of the browser enum?
}
else if (browser == IE)
{
driver = webUIManager.getIEDriver();
}
else if (browser == Safari)
{
driver = webUIManager.getSafariDriver();
}
else
{
driver = webUIManager.getFirefoxDriver();
}
return driver;
}
private static String captureScreen(WebDriver driver)
{
String fileUrl;
try
{
Thread.sleep(3500);
WebDriver augmentedDriver = driver;
if (WebUIManager.getInstance().isUseRemoteWebDriver())
{
augmentedDriver = new Augmenter().augment(driver);
}
//
File source = ((TakesScreenshot) augmentedDriver).getScreenshotAs(OutputType.FILE);
String fileName = source.getName();
String dirName = IMG_FOLDER_NAME + '_' + DATE_TIME_FORMATTER.format(LocalDate.now());
File dirFile = new File(WebUIManager.getInstance().getLogsPath() + File.separator + dirName);
if (!dirFile.exists())
{
dirFile.mkdir();
}
fileUrl = dirName + '/' + source.getName();
String path = WebUIManager.getInstance().getLogsPath() + File.separator + dirName + File.separator + fileName;
FileUtils.copyFile(source, new File(path));
Thread.sleep(SCREEN_CAPTURE_WAIT);
}
catch (Exception e)
{
fileUrl = "Failed to capture screen shot: " + e.getMessage();
}
return fileUrl;
}
}