package org.jboss.windup.testutil.html;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Path;
import java.util.List;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.jboss.windup.util.exception.WindupException;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.htmlunit.HtmlUnitDriver;
/**
* Contains methods for testing the Java Application Overview report.
*
* @author <a href="mailto:jesse.sightler@gmail.com">Jesse Sightler</a>
*/
public class TestJavaApplicationOverviewUtil extends TestReportUtil
{
/**
* Loads the given page w/ the {@link WebDriver}
*/
@Override
public void loadPage(Path filePath)
{
try
{
Path modifiedPath = filePath.getParent().resolve(filePath.getFileName().toString() + "_modified.html");
String contents = FileUtils.readFileToString(filePath.toFile());
// remove some libraries that htmlunit has issues with... we don't really test these through htmlunit anyway
contents = contents.replace("$.plot", "");
contents = contents.replace("<script src=\"resources/libraries/flot/jquery.flot.min.js\"></script>",
"<script>$.plot = function(){}</script>");
contents = contents.replace("<script src=\"resources/libraries/flot/jquery.flot.pie.min.js\"></script>", "");
// RenderApplicationPieChartDirective
contents = contents.replace("<script src=\"resources/js/jquery.color-2.1.2.min.js\"></script>",
"<script>jQuery.Color = function(){ return { toHexString: function(){ return \"#aa0000\"; } } }</script>");
try (FileWriter writer = new FileWriter(modifiedPath.toFile()))
{
writer.append(contents);
}
getDriver().get(modifiedPath.toUri().toString());
}
catch (IOException e)
{
throw new RuntimeException(e);
}
}
public void checkApplicationMessage(String message)
{
// application-message
List<WebElement> applicationMessageElements = getDriver()
.findElements(By.className("application-message"));
for (WebElement applicationMessageElement : applicationMessageElements)
{
if (message.equals(applicationMessageElement.getText()))
return;
}
throw new CheckFailedException("Could not find an application message with text: " + message);
}
public void checkMainEffort(int expectedEffort)
{
WebElement effortElement = getDriver()
.findElement(By.xpath(
".//div[contains(@class, 'container') and contains(@class, 'mainGraphContainer')]//div[@class = 'points']/div[@class = 'number']"));
String effortString = effortElement.getText().trim();
effortString = effortString.replace(",", "");
int effort;
try
{
effort = Integer.parseInt(effortString);
}
catch (Exception e)
{
throw new CheckFailedException("Effort: " + effortString + " could not be parsed as numeric!");
}
if (effort != expectedEffort)
throw new CheckFailedException("Effort was " + effort + " but was expected to be " + expectedEffort);
}
public void checkAppSectionEffort(String appSection, int expectedEffort)
{
WebElement appSectionEl = getAppSectionElement(appSection);
if (appSectionEl == null)
{
throw new CheckFailedException("Unable to find app section with name: " + appSection);
}
String xpath = getElementXPath(getDriver(), appSectionEl) + "/"
+ "../..//div[@class = \\'points\\']/div[text() = \\'Story Points\\']/../div[@class = \\'number\\']";
String effortString = getStringValueForXpathElement(getDriver(), xpath).trim();
effortString = effortString.replace(",", "");
try
{
int effort = Integer.parseInt(effortString);
if (effort != expectedEffort)
throw new CheckFailedException("Effort was " + effort + " but was expected to be " + expectedEffort);
}
catch (Exception e)
{
throw new CheckFailedException("Effort: " + effortString + " could not be parsed as numeric!");
}
}
/**
* Checks if the given App section, filepath, and effort level can be seen in the report.
* <p>
* For example checkFilePathEffort("src_example", "src/main/resources/test.properties", 13) will ensure that an application called "src_example"
* is in the report, with a line referencing "src/main/resources/test.properties" and that this line contains the effort level 13).
*/
public void checkFilePathEffort(String appSection, String filePath, int effort)
{
WebElement appSectionEl = getAppSectionElement(appSection);
if (appSectionEl == null)
{
throw new CheckFailedException("Unable to find app section with name: " + appSection);
}
WebElement fileRowElement = getFileRowElement(appSection, filePath);
if (fileRowElement == null)
{
throw new CheckFailedException("Unable to find row for filePath: " + filePath);
}
List<WebElement> elements = fileRowElement.findElements(By.xpath("./td[position() = 4]"));
for (WebElement element : elements)
{
if (element.getText() != null)
{
try
{
int number = Integer.parseInt(getTextForElement(element));
if (number == effort)
{
return;
}
else
{
throw new CheckFailedException("Found row with appSection: " + appSection + " and filePath: "
+ filePath
+ ", but effort was: " + number + " (expected value: " + effort + ")");
}
}
catch (NumberFormatException e)
{
// ignore
}
}
}
throw new CheckFailedException("Unable to find app: " + appSection + " file: " + filePath + " with effort: "
+ effort);
}
/**
* Checks if the given App section, filepath, and tag can be found in the report.
* <p>
* For example calling checkFilePathAndIssues("src_example", "src/main/resources/test.properties", "Web Servlet again") will ensure that an
* application called "src_example" is in the report, with a line referencing "src/main/resources/test.properties" and that this line contains
* text in the issues section saying "Web Servlet again").
*/
public void checkFilePathAndIssues(String appSection, String filePath, String text)
{
WebElement appSectionEl = getAppSectionElement(appSection);
if (appSectionEl == null)
{
throw new CheckFailedException("Unable to find app section with name: " + appSection);
}
WebElement fileRowElement = getFileRowElement(appSection, filePath);
if (fileRowElement == null)
{
throw new CheckFailedException("Unable to find row for filePath: " + filePath);
}
List<WebElement> elements = fileRowElement.findElements(By.xpath("./td[position() = 3]"));
for (WebElement element : elements)
{
String elementText = getTextForElement(element);
if (elementText != null && elementText.contains(text))
{
return;
}
}
throw new CheckFailedException("Unable to find app: " + appSection + " file: " + filePath + " with issue: "
+ text);
}
/**
* Checks if the given App section, filepath, and tag can be found in the report.
* <p>
* For example calling checkFilePathAndTag("src_example", "src/main/resources/test.properties", "Properties") will ensure that an application
* called "src_example" is in the report, with a line referencing "src/main/resources/test.properties" and that this file is tagged "Properties"
*/
public void checkFilePathAndTag(String appSection, String filePath, String tag)
{
WebElement appSectionEl = getAppSectionElement(appSection);
if (appSectionEl == null)
{
throw new CheckFailedException("Unable to find app section with name: " + appSection);
}
WebElement fileRowElement = getFileRowElement(appSection, filePath);
if (fileRowElement == null)
{
throw new CheckFailedException("Unable to find row for filePath: " + filePath);
}
List<WebElement> elements = fileRowElement.findElements(By.xpath("./td[position() = 2]/span"));
for (WebElement element : elements)
{
String spanValue = getTextForElement(element);
if (spanValue.equals(tag))
{
return;
}
}
throw new CheckFailedException("Unable to find app: " + appSection + " file: " + filePath + " with tag: "
+ tag);
}
/**
* In case the element's css is display:none, selenium does not see it using getText(). Therefore this methods uses javascript to query the value
*
* @param element
* @return
*/
private String getTextForElement(WebElement element)
{
HtmlUnitDriver driver = (HtmlUnitDriver) getDriver();
String xpath = getElementXPath(driver, element);
String result = getStringValueForXpathElement(driver, xpath);
return result.trim();
}
/**
* Returns the xpath full path of the given element. E.g something like /html/body/div[2]/p
*
* @param driver
* @param element
* @return
*/
private String getElementXPath(WebDriver driver, WebElement element)
{
String xpath = (String) ((JavascriptExecutor) driver).executeScript(
"gPt=function(c){if(c.id!==''){return'id(\"'+c.id+'\")'}if(c===document.body){return c.tagName}var a=0;var e=c.parentNode.childNodes;for(var b=0;b<e.length;b++){var d=e[b];if(d===c){return gPt(c.parentNode)+'/'+c.tagName+'['+(a+1)+']'}if(d.nodeType===1&&d.tagName===c.tagName){a++}}};return gPt(arguments[0]).toLowerCase();",
element);
if (!StringUtils.startsWith(xpath, "id(\""))
xpath = "/html/" + xpath;
return xpath;
}
private String getStringValueForXpathElement(WebDriver driver, String xpathToElement)
{
return (String) ((JavascriptExecutor) driver).executeScript("var foundDocument=document.evaluate( '" + xpathToElement
+ "', document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null ).singleNodeValue; if(foundDocument !=null) {return foundDocument.textContent;} else {return null} ");
}
/**
* Checks if the given App section, filepath, and tag can be found in the report.
* <p>
* For example calling checkFilePathAndTag("src_example", "src/main/resources/test.properties") will ensure that an application called
* "src_example" is in the report, with a line referencing "src/main/resources/test.properties"
*/
public void checkFilePath(String appSection, String filePath)
{
WebElement appSectionEl = getAppSectionElement(appSection);
if (appSectionEl == null)
{
throw new CheckFailedException("Unable to find app section with name: " + appSection);
}
WebElement fileRowElement = getFileRowElement(appSection, filePath);
if (fileRowElement == null)
{
throw new CheckFailedException("Unable to find row for filePath: " + filePath);
}
return;
}
private WebElement getFileRowElement(String appSection, String filePath)
{
WebElement fileTable = getAppSectionElement(appSection).findElement(By.xpath("../../div[contains(@class,'panel-body')]/table"));
WebElement fileRow = fileTable.findElement(By
.xpath("./tbody/tr/td/a[normalize-space(text()) = '" + filePath + "']/../.."));
return fileRow;
}
private WebElement getAppSectionElement(String appSection)
{
List<WebElement> titleElements = getDriver().findElements(By.className("panel-title"));
for (WebElement el : titleElements)
{
String panelTitleText = el.getText();
if (panelTitleText != null)
{
panelTitleText = parseOutAppTitle(panelTitleText);
if (appSection.equals(panelTitleText.trim()))
{
return el;
}
}
}
return null;
}
private String parseOutAppTitle(String input)
{
// remove story points information
return input.replaceAll("\\(.*\\)", "");
}
}