/** * Copyright (C) 2015 Orion Health (Orchestral Development Ltd) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package xbdd.report; import java.io.IOException; import java.io.InputStream; import java.util.Arrays; import java.util.List; import java.util.Map; import javax.ws.rs.client.Client; import javax.ws.rs.client.Entity; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import org.codehaus.jackson.map.JsonMappingException; import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.ui.ExpectedConditions; import org.openqa.selenium.support.ui.WebDriverWait; import xbdd.XbddDriver; import xbdd.utils.JerseyClientFactory; import xbdd.utils.XBDDInstance; import com.google.common.base.Function; import com.google.common.collect.Lists; import com.mongodb.DBObject; public class ReportManager { public static String FEATURE_LIST_ID = "featureIndex"; public static final Function<WebElement, FeatureSummary> WEB_ELEMENT_TO_FEATURE_SUMMARY = new Function<WebElement, FeatureSummary>() { @Override public FeatureSummary apply(final WebElement featureElement) { final FeatureSummary summary = new FeatureSummary(); summary.setTitle(featureElement.findElement(By.cssSelector(".feature-name")).getText()); final String result = featureElement.getAttribute("data-status"); summary.setResult((result) != null ? result : "undefined"); final List<WebElement> tagElements = featureElement.findElements(By.cssSelector(".feature-tag")); summary.setTags(Lists.transform(tagElements, new Function<WebElement, String>() { @Override public String apply(final WebElement tagElement) { return tagElement.getText(); } })); if (!featureElement.findElements(By.cssSelector(".feature-description")).isEmpty()) { summary.setDescription(featureElement.findElement(By.cssSelector(".feature-description")).getText()); } summary.setScenarios(Lists.transform(featureElement.findElements(By.cssSelector(".scenario")), WEB_ELEMENT_SCENARIO_SUMMARY)); return summary; } }; public static final Function<WebElement, ScenarioSummary> WEB_ELEMENT_SCENARIO_SUMMARY = new Function<WebElement, ScenarioSummary>() { @Override public ScenarioSummary apply(final WebElement element) { final ScenarioSummary scenarioSummary = new ScenarioSummary(); scenarioSummary.setName(element.findElement(By.cssSelector(".scenario-name")).getText()); scenarioSummary.setDescription(element.findElement(By.cssSelector(".scenario-description")).getText()); scenarioSummary.setResult(element.getAttribute("data-status")); final List<WebElement> tagElements = element.findElements(By.cssSelector(".scenario-tag")); scenarioSummary.setTags(Lists.transform(tagElements, new Function<WebElement, String>() { @Override public String apply(final WebElement tagElement) { return tagElement.getText(); } })); final List<WebElement> stepElements = element.findElements(By.cssSelector(".step")); scenarioSummary.setSteps(Lists.transform(stepElements, new Function<WebElement, StepSummary>() { @Override public StepSummary apply(final WebElement stepElement) { return new StepSummary(stepElement.getText(), stepElement.getAttribute("data-status")); } })); scenarioSummary.setTestingTips(element.findElement(By.cssSelector(".testing-tips")).getAttribute("value")); scenarioSummary.setEnvironment(element.findElement(By.cssSelector(".environment-notes")).getAttribute("value")); scenarioSummary.setExecutionNotes(element.findElement(By.cssSelector(".execution-notes")).getAttribute("value")); return scenarioSummary; } }; public static final Function<WebElement, StepSummary> WEB_ELEMENT_TO_STEP_SUMMARY = new Function<WebElement, StepSummary>() { @Override public StepSummary apply(final WebElement element) { final StepSummary step = new StepSummary(); step.setStep(element.getText()); step.setStatus(element.getAttribute("data-status")); return step; } }; private final Client client; private final WebDriver webDriver; private final XBDDInstance xbddInstance; /** * Create a new XBDDFileHelper REST service helper which provides methods for managing report */ public ReportManager(final XbddDriver webDriver, final XBDDInstance xbddInstance) { this.xbddInstance = xbddInstance; this.client = JerseyClientFactory.getInstance().createAuthenticatingClient(); this.webDriver = webDriver; } /** * Load a test results JSON file to xbdd and check that the response was ok * * @param resource The path to the resource file relative to this class' classloader * @param rootURL The root url for the restful service call * @param reportContext The context of the report * @throws IllegalArgumentException IOException */ public void loadReport(final String resource, final String rootURL, final ReportContext reportContext) throws IllegalArgumentException, IOException { try (final InputStream is = this.getClass().getClassLoader().getResourceAsStream(resource)) { final Response response = this.client .target(rootURL + "/rest/reports/" + reportContext.getProduct() + "/" + reportContext.getMajorVersion() + "." + reportContext.getMinorVersion() + "." + reportContext.getServicePackVersion() + "/" + reportContext.getBuild()) .request() .put(Entity.entity(is, MediaType.APPLICATION_JSON)); if (response.getStatus() != 200) { throw new IllegalStateException("Unexpected response code loading test result file: " + response); } } } /** * Retrieve a feature DBObject file to xbdd * * @param rootURL The root url for the restful service call * @param reportContext The context of the report * @param featureId The id of the feature * * @return the feature information */ public DBObject getFeature(final String rootURL, final ReportContext reportContext, final String featureId) { final DBObject feature = this.client .target(rootURL + "/rest/feature/" + reportContext.getProduct() + "/" + reportContext.getMajorVersion() + "." + reportContext.getMinorVersion() + "." + reportContext.getServicePackVersion() + "/" + reportContext.getBuild() + "/" + featureId) .request() .get(DBObject.class); return feature; } /** * Update the old feature results with the new feature results, and check that the response was ok * * @param feature The feature * @param rootURL The root url for the restful service call * @param reportContext The context of the report * @throws IOException * @throws JsonMappingException * @throws IllegalArgumentException IOException */ public void updateFeature(final DBObject feature, final String rootURL, final ReportContext reportContext, final String featureId) { final Response response = this.client .target(rootURL + "/rest/feature/" + reportContext.getProduct() + "/" + reportContext.getMajorVersion() + "." + reportContext.getMinorVersion() + "." + reportContext.getServicePackVersion() + "/" + reportContext.getBuild() + "/" + featureId) .request() .put(Entity.entity(feature, MediaType.APPLICATION_JSON)); if (response.getStatus() != 200) { throw new IllegalStateException("Unexpected response code loading test result file: " + response); } } /** * Open a report by navigating to its page * * @param reportContext The context of the report */ public void openReport(final ReportContext reportContext) { this.webDriver.navigate().to( this.xbddInstance.getBaseURL() + "/reports/" + reportContext.getProduct() + "/" + reportContext.getMajorVersion() + "." + reportContext.getMinorVersion() + "." + reportContext.getServicePackVersion() + "/" + reportContext.getBuild()); } /** * Open a report by navigating to its page and put the feature in context * * @param reportContext The context of the report * @param feature the name of the feature */ public void openFeature(final ReportContext reportContext, final String feature) { this.webDriver.navigate().to( this.xbddInstance.getBaseURL() + "/reports/" + reportContext.getProduct() + "/" + reportContext.getMajorVersion() + "." + reportContext.getMinorVersion() + "." + reportContext.getServicePackVersion() + "/" + reportContext.getBuild() + "/" + feature); } /** * Open a openScenario from a report * * @param reportContext The context of the report * @param feature The name of the feature * @param scenarioPathParam The part of scenario id * @param scenarioName The name of the scenario * * @return the summary of the scenario */ public ScenarioSummary openScenario(final ReportContext reportContext, final String feature, final String scenarioPathParam) { openFeature(reportContext, feature); final String id = feature + "\\;" + scenarioPathParam; new WebDriverWait(this.webDriver, 20).until(ExpectedConditions.elementToBeClickable(By.cssSelector("#" + id + " .scenario-name"))) .click(); return new WebDriverWait(this.webDriver, 20).until(new Function<WebDriver, ScenarioSummary>() { @Override public ScenarioSummary apply(final WebDriver driver) { return WEB_ELEMENT_SCENARIO_SUMMARY.apply(driver.findElement(By.cssSelector("#" + id))); } }); } /** * Return the list of features from a report. * * @return a list of {@link FeatureSummary}s. Will not be empty. * @throws {@link TimeoutException} if no features are found within 20 seconds. * */ public List<FeatureSummary> getFeatures() { return new WebDriverWait(this.webDriver, 20) .until(new Function<WebDriver, List<FeatureSummary>>() { @Override public List<FeatureSummary> apply(final WebDriver driver) { final List<WebElement> featureElements = driver.findElement(By.id(FEATURE_LIST_ID)).findElements( By.cssSelector(".feature-index-entry")); // when the test runs really fast, it sometimes gets the element but returns an empty array if (featureElements.isEmpty()) { return null; } return Lists.transform(featureElements, WEB_ELEMENT_TO_FEATURE_SUMMARY); } }); } public FeatureSummary getFeature() { return new WebDriverWait(this.webDriver, 20) .until(new Function<WebDriver, FeatureSummary>() { @Override public FeatureSummary apply(final WebDriver driver) { return WEB_ELEMENT_TO_FEATURE_SUMMARY.apply(driver.findElement(By.cssSelector(".feature"))); } }); } public FeatureSummary getFeatureSummary(final String summaryId) { return new WebDriverWait(this.webDriver, 20).until(new Function<WebDriver, FeatureSummary>() { @Override public FeatureSummary apply(final WebDriver driver) { return WEB_ELEMENT_TO_FEATURE_SUMMARY.apply(driver.findElement(By.id(summaryId))); } }); } /** * update a feature DBObject * * @param feature The jaon object form of the feature * @param updateMap The map includes the fields needed to be updated with the new values for the feature json object * * @return The feature DBObject */ @SuppressWarnings("unchecked") public DBObject updateFeatureJSONObject(final DBObject feature, final Map<String, String> updateMap) { final String[] namesInElements = { "testing-tips", "environment-notes", "execution-notes" }; for (final String key : updateMap.keySet()) { if (Arrays.asList(namesInElements).contains(key)) { final List<DBObject> elements = (List<DBObject>) feature.get("elements"); for (final DBObject scenario : elements) { scenario.put(key, updateMap.get(key)); } } } return feature; } }