/*******************************************************************************
* Copyright 2017 Ivan Shubin http://galenframework.com
*
* 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 com.galenframework.validation.specs;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import com.galenframework.browser.Browser;
import com.galenframework.speclang2.pagespec.PageSpecReader;
import com.galenframework.specs.SpecComponent;
import com.galenframework.validation.*;
import com.galenframework.page.Page;
import com.galenframework.page.PageElement;
import com.galenframework.specs.page.Locator;
import com.galenframework.specs.page.PageSpec;
import com.galenframework.speclang2.pagespec.SectionFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static java.util.Arrays.asList;
public class SpecValidationComponent extends SpecValidation<SpecComponent> {
private final static Logger LOG = LoggerFactory.getLogger(SpecValidationComponent.class);
private static final Map<String, Locator> NO_OBJECTS = Collections.emptyMap();
@Override
public ValidationResult check(PageValidation pageValidation, String objectName, SpecComponent spec) throws ValidationErrorException {
PageElement mainObject = pageValidation.findPageElement(objectName);
checkAvailability(mainObject, objectName);
tellListenerSubLayout(pageValidation, objectName);
List<ValidationResult> results;
if (spec.isFrame()) {
results = checkInsideFrame(mainObject, pageValidation, spec);
}
else {
results = checkInsideNormalWebElement(pageValidation, objectName, spec);
}
tellListenerAfterSubLayout(pageValidation, objectName);
List<ValidationObject> objects = asList(new ValidationObject(mainObject.getArea(), objectName));
List<ValidationResult> errorResults = results.stream().filter(byOnlyError()).collect(Collectors.toList());
if (!errorResults.isEmpty()) {
throw new ValidationErrorException("Child component spec contains " + errorResults.size() + " errors")
.withValidationObjects(objects)
.withChildValidationResults(errorResults);
} else {
List<ValidationResult> warningResults = results.stream().filter(byOnlyWarn()).collect(Collectors.toList());
if (!warningResults.isEmpty()) {
return new ValidationResult(spec, objects).withError(
new ValidationError(asList("Child component spec contains " + warningResults.size() + " warnings"))
.withOnlyWarn(true)
).withChildValidationResults(warningResults);
}
}
return new ValidationResult(spec, objects);
}
private void tellListenerAfterSubLayout(PageValidation pageValidation, String objectName) {
if (pageValidation.getValidationListener() != null) {
try {
pageValidation.getValidationListener().onAfterSubLayout(pageValidation, objectName);
}
catch (Exception ex) {
LOG.trace("Unknown error during validation after object", ex);
}
}
}
private void tellListenerSubLayout(PageValidation pageValidation, String objectName) {
if (pageValidation.getValidationListener() != null) {
try {
pageValidation.getValidationListener().onSubLayout(pageValidation, objectName);
}
catch (Exception ex) {
LOG.trace("Unknown error during validation after object", ex);
}
}
}
private List<ValidationResult> checkInsideFrame(PageElement mainObject, PageValidation pageValidation, SpecComponent spec) {
Page page = pageValidation.getPage();
Page framePage = page.createFrameContext(mainObject);
List<ValidationResult> results = checkInsidePage(pageValidation.getBrowser(), framePage, spec,
pageValidation.getSectionFilter(), pageValidation.getValidationListener());
if (spec.isFrame()) {
page.switchToParentFrame();
}
return results;
}
private List<ValidationResult> checkInsidePage(Browser browser, Page page, SpecComponent spec,
SectionFilter sectionFilter, ValidationListener validationListener) {
PageSpecReader pageSpecReader = new PageSpecReader();
PageSpec componentPageSpec;
try {
componentPageSpec = pageSpecReader.read(spec.getSpecPath(),
page, sectionFilter, spec.getProperties(),
wrapJsVariables(spec.getJsVariables(), spec.getArguments()),
NO_OBJECTS
);
} catch (IOException e) {
throw new RuntimeException("Could not read spec " + spec.getSpecPath(), e);
}
SectionValidation sectionValidation = new SectionValidation(componentPageSpec.getSections(),
new PageValidation(browser, page, componentPageSpec, validationListener, sectionFilter),
validationListener);
return sectionValidation.check();
}
private Map<String, Object> wrapJsVariables(Map<String, Object> jsVariables, Map<String, Object> arguments) {
Map<String, Object> newJsVariables = new HashMap<>();
if (jsVariables != null) {
newJsVariables.putAll(jsVariables);
}
if (arguments != null) {
newJsVariables.putAll(arguments);
}
return newJsVariables;
}
private List<ValidationResult> checkInsideNormalWebElement(PageValidation pageValidation, String objectName, SpecComponent spec) {
Locator mainObjectLocator = pageValidation.getPageSpec().getObjectLocator(objectName);
Page objectContextPage = pageValidation.getPage().createObjectContextPage(mainObjectLocator);
return checkInsidePage(pageValidation.getBrowser(), objectContextPage, spec,
pageValidation.getSectionFilter(), pageValidation.getValidationListener());
}
private Predicate<ValidationResult> byOnlyWarn() {
return r -> r.getError() != null && r.getError().isOnlyWarn();
}
private Predicate<ValidationResult> byOnlyError() {
return r -> r.getError() != null && !r.getError().isOnlyWarn();
}
}