diff --git a/galen-core/pom.xml b/galen-core/pom.xml
index c5f35aca..f2b52747 100644
--- a/galen-core/pom.xml
+++ b/galen-core/pom.xml
@@ -10,7 +10,7 @@
com.galenframework
galen-parent
- 2.4.1-SNAPSHOT
+ 2.4.5-SNAPSHOT
diff --git a/galen-core/src/main/java/com/galenframework/browser/SeleniumBrowserFactory.java b/galen-core/src/main/java/com/galenframework/browser/SeleniumBrowserFactory.java
index a651000c..a415e057 100644
--- a/galen-core/src/main/java/com/galenframework/browser/SeleniumBrowserFactory.java
+++ b/galen-core/src/main/java/com/galenframework/browser/SeleniumBrowserFactory.java
@@ -33,6 +33,8 @@
import org.openqa.selenium.phantomjs.PhantomJSDriver;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.safari.SafariDriver;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import java.util.Collections;
@@ -44,6 +46,7 @@
*/
public class SeleniumBrowserFactory implements BrowserFactory {
+ private final static Logger LOG = LoggerFactory.getLogger(SeleniumBrowserFactory.class);
public static final String FIREFOX = "firefox";
public static final String CHROME = "chrome";
public static final String IE = "ie";
@@ -82,6 +85,10 @@ private Browser createSeleniumGridBrowser() {
if (platform != null && !platform.trim().isEmpty()) {
gridFactory.setPlatform(Platform.valueOf(platform.toUpperCase()));
}
+ Boolean enableVnc = GalenConfig.getConfig().getBooleanProperty(GalenProperty.GALEN_BROWSERFACTORY_SELENIUM_GRID_ENABLEVNC);
+ if (enableVnc != false) {
+ gridFactory.setEnableVnc(enableVnc);
+ }
return gridFactory.openBrowser();
}
diff --git a/galen-core/src/main/java/com/galenframework/browser/SeleniumGridBrowserFactory.java b/galen-core/src/main/java/com/galenframework/browser/SeleniumGridBrowserFactory.java
index 25ecd3cf..2e1cd189 100644
--- a/galen-core/src/main/java/com/galenframework/browser/SeleniumGridBrowserFactory.java
+++ b/galen-core/src/main/java/com/galenframework/browser/SeleniumGridBrowserFactory.java
@@ -34,6 +34,7 @@ public class SeleniumGridBrowserFactory implements BrowserFactory {
private String browser;
private String browserVersion;
private Platform platform;
+ private Boolean enableVnc;
private Map desiredCapabilities = new HashMap<>();
public SeleniumGridBrowserFactory(String gridUrl) {
@@ -69,6 +70,10 @@ public DesiredCapabilities createCapabilities(){
desiredCapabilities.setVersion(browserVersion);
}
+ if (enableVnc != null && enableVnc != false) {
+ desiredCapabilities.setCapability("enableVNC", true);
+ }
+
for (Map.Entry dc : this.desiredCapabilities.entrySet()) {
final String value = dc.getValue();
if("true".equals(value) || "false".equals(value)) {
@@ -126,6 +131,14 @@ public String getGridUrl() {
public void setGridUrl(String gridUrl) {
this.gridUrl = gridUrl;
}
+
+ public Boolean getEnableVnc() {
+ return enableVnc;
+ }
+
+ public void setEnableVnc(Boolean enableVnc) {
+ this.enableVnc = enableVnc;
+ }
@Override
public int hashCode() {
diff --git a/galen-core/src/main/java/com/galenframework/config/GalenProperty.java b/galen-core/src/main/java/com/galenframework/config/GalenProperty.java
index 7ce191a2..e4a4b3b5 100644
--- a/galen-core/src/main/java/com/galenframework/config/GalenProperty.java
+++ b/galen-core/src/main/java/com/galenframework/config/GalenProperty.java
@@ -50,6 +50,7 @@ public enum GalenProperty {
GALEN_BROWSERFACTORY_SELENIUM_GRID_BROWSER("galen.browserFactory.selenium.grid.browser", null),
GALEN_BROWSERFACTORY_SELENIUM_GRID_BROWSERVERSION("galen.browserFactory.selenium.grid.browserVersion", null),
GALEN_BROWSERFACTORY_SELENIUM_GRID_PLATFORM("galen.browserFactory.selenium.grid.platform", null),
+ GALEN_BROWSERFACTORY_SELENIUM_GRID_ENABLEVNC("galen.browserFactory.selenium.grid.enableVnc", "false"),
GALEN_BROWSER_VIEWPORT_ADJUSTSIZE("galen.browser.viewport.adjustSize", "false"),
diff --git a/galen-core/src/main/java/com/galenframework/generator/model/GmPageSpec.java b/galen-core/src/main/java/com/galenframework/generator/model/GmPageSpec.java
index 459a00bf..94746539 100644
--- a/galen-core/src/main/java/com/galenframework/generator/model/GmPageSpec.java
+++ b/galen-core/src/main/java/com/galenframework/generator/model/GmPageSpec.java
@@ -38,12 +38,7 @@ public static GmPageSpec create(PageSpecGenerationResult result) {
Map pinPageSections = new HashMap<>();
- //TODO fix this for the cases when there are more than one root notes. Could be done by making sure that we always have single root element upfront. if not -> make a boundary box
- PageItemNode screenPin = result.getObjects().get(0);
- pinPageSections.put(screenPin, skeletonSection);
-
-
- screenPin.getChildren().forEach(bigPin -> {
+ result.getObjects().forEach(rootObject -> rootObject.getChildren().forEach(bigPin -> {
GmPageSection pageSection = pageSpec.createNewSection(bigPin.getPageItem().getName() + " elements");
bigPin.visitTree(p -> {
if (p == bigPin) {
@@ -52,7 +47,7 @@ public static GmPageSpec create(PageSpecGenerationResult result) {
pinPageSections.put(p, pageSection);
}
});
- });
+ }));
Map> generatedRules = result.getSuggestionResults().getGeneratedRules();
diff --git a/galen-core/src/main/java/com/galenframework/page/selenium/WebPageElement.java b/galen-core/src/main/java/com/galenframework/page/selenium/WebPageElement.java
index eb142374..962c5f8a 100644
--- a/galen-core/src/main/java/com/galenframework/page/selenium/WebPageElement.java
+++ b/galen-core/src/main/java/com/galenframework/page/selenium/WebPageElement.java
@@ -24,6 +24,7 @@
import org.openqa.selenium.*;
+import java.util.Locale;
public class WebPageElement extends PageElement {
@@ -55,7 +56,7 @@ public Rect calculateArea() {
private AreaFinder getAreaFinder() {
String areaFinderName = GalenConfig.getConfig().getStringProperty(GalenProperty.GALEN_BROWSER_PAGELEMENT_AREAFINDER);
- return AreaFinder.valueOf(areaFinderName.toUpperCase());
+ return AreaFinder.valueOf(areaFinderName.toUpperCase(Locale.ENGLISH));
}
private Rect correctedRect(Rect rect, CorrectionsRect corrections) {
diff --git a/galen-core/src/main/resources/html-report/galen-report.css b/galen-core/src/main/resources/html-report/galen-report.css
index 4acaf89d..178495bf 100644
--- a/galen-core/src/main/resources/html-report/galen-report.css
+++ b/galen-core/src/main/resources/html-report/galen-report.css
@@ -247,6 +247,11 @@ svg line.meta-line-guide {
.layout-spec ul.error-messages li {
margin-left: 10px;
}
+.layout-spec ul.error-messages li .link {
+ color: #B33914;
+ font-weight: bold;
+ text-decoration: underline;
+}
.layout-spec.has-failure > .title {
font-weight: bold;
color: #DB4B4B;
@@ -548,3 +553,8 @@ table.mutation-table tr.mutation-table-total td {
white-space: pre;
overflow-x: auto;
}
+
+.image-comparison-popup .image-layout {
+ display: inline-block;
+ margin: 5px;
+}
diff --git a/galen-core/src/main/resources/html-report/galen-report.js b/galen-core/src/main/resources/html-report/galen-report.js
index 8623b932..5fb99a2f 100644
--- a/galen-core/src/main/resources/html-report/galen-report.js
+++ b/galen-core/src/main/resources/html-report/galen-report.js
@@ -245,10 +245,45 @@ function toggleReportNode(node) {
node.expanded = !node.expanded;
}
+Vue.component('image-comparison-popup', {
+ props: ['imagedata'],
+ template: '#tpl-image-comparison-popup',
+ mounted() {
+ document.addEventListener('keydown', this.onKeyPress);
+ },
+ beforeDestroy() {
+ document.removeEventListener('keydown', this.onKeyPress);
+ },
+ data: function () {
+ var clientWidth = Math.max(document.documentElement.clientWidth, window.innerWidth || 0);
+ var clientHeight = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);
+ return {
+ position: {
+ top: 5,
+ left: 50,
+ width: clientWidth - 100,
+ height: clientHeight - 10
+ }
+ };
+ },
+ methods: {
+ onKeyPress: function (event) {
+ if (event.key === 'Escape') {
+ this.$emit('close');
+ }
+ }
+ }
+});
Vue.component('screenshot-popup', {
props: ['screenshot', 'highlight', 'guides', 'spec'],
template: '#tpl-screenshot-popup',
+ mounted() {
+ document.addEventListener('keydown', this.onKeyPress);
+ },
+ beforeDestroy() {
+ document.removeEventListener('keydown', this.onKeyPress);
+ },
data: function () {
var clientWidth = Math.max(document.documentElement.clientWidth, window.innerWidth || 0);
var clientHeight = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);
@@ -271,6 +306,13 @@ Vue.component('screenshot-popup', {
offsetTop: 30 - this.highlight.boundaryBox.min.y,
}
};
+ },
+ methods: {
+ onKeyPress: function (event) {
+ if (event.key === 'Escape') {
+ this.$emit('close');
+ }
+ }
}
});
@@ -340,7 +382,7 @@ Vue.component('mutation-report', {
});
Vue.component('layout-section', {
- props: ['section', 'bus'],
+ props: ['layout', 'section', 'bus'],
template: '#tpl-layout-section',
methods: {
toggleReportNode: toggleReportNode
@@ -348,7 +390,7 @@ Vue.component('layout-section', {
});
Vue.component('object-node', {
- props: ['object', 'bus'],
+ props: ['layout', 'object', 'bus'],
template: '#tpl-object-node',
methods: {
toggleReportNode: toggleReportNode
@@ -356,19 +398,28 @@ Vue.component('object-node', {
});
Vue.component('layout-spec', {
- props: ['spec', 'bus'],
+ props: ['layout', 'spec', 'bus'],
template: '#tpl-layout-spec',
data: function () {
return {
- isFailed: this.spec.errors && this.spec.errors.length > 0
+ isFailed: this.spec.errors && this.spec.errors.length > 0,
+ imageComparisonShown: false
};
},
methods: {
showSpec: function() {
- this.bus.$emit('spec-clicked', this.spec);
+ this.bus.$emit('spec-clicked', this.spec, this.layout);
}
}
-})
+});
+
+Vue.component('layout-spec-group', {
+ props: ['layout', 'specgroup', 'bus'],
+ template: '#tpl-spec-group',
+ methods: {
+ toggleReportNode: toggleReportNode
+ }
+});
Vue.component('layout-report', {
props: ['layout'],
@@ -389,15 +440,15 @@ Vue.component('layout-report', {
},
methods: {
toggleReportNode: toggleReportNode,
- collectHighlightAreas: function (objectNames) {
+ collectHighlightAreas: function (objectNames, layout) {
var self = this;
var boundaryBox = {
min: {x: 1000000, y: 1000000},
max: {x: 0, y: 0}
};
var objects = _.mapNonNull(objectNames, function (objectName, index) {
- if (self.layout.objects.hasOwnProperty(objectName)) {
- var area = self.layout.objects[objectName].area;
+ if (layout.objects.hasOwnProperty(objectName)) {
+ var area = layout.objects[objectName].area;
if (area) {
var item = {
name: objectName,
@@ -425,17 +476,17 @@ Vue.component('layout-report', {
boundaryBox: boundaryBox
};
},
- findObjectArea: function(objectName) {
- if (this.layout.objects.hasOwnProperty(objectName)) {
- return this.layout.objects[objectName].area;
+ findObjectArea: function(objectName, layout) {
+ if (layout.objects.hasOwnProperty(objectName)) {
+ return layout.objects[objectName].area;
}
return null;
},
- collectMetaGuides: function(meta) {
+ collectMetaGuides: function(meta, layout) {
var self = this;
return _.mapNonNull(meta, function (metaEntry) {
- var fromArea = self.findObjectArea(metaEntry.from.object);
- var toArea = self.findObjectArea(metaEntry.to.object);
+ var fromArea = self.findObjectArea(metaEntry.from.object, layout);
+ var toArea = self.findObjectArea(metaEntry.to.object, layout);
if (fromArea && toArea) {
var fromEdge = MetaUtils.fetchEdge(fromArea, metaEntry.from.edge);
var toEdge = MetaUtils.fetchEdge(toArea, metaEntry.to.edge);
@@ -448,13 +499,13 @@ Vue.component('layout-report', {
return null;
});
},
- specClicked: function(spec) {
+ specClicked: function(spec, layout) {
this.screenshotPopup.metaGuides = [];
if (spec.highlight && spec.highlight.length > 0) {
- this.screenshotPopup.highlightAreas = this.collectHighlightAreas(spec.highlight);
+ this.screenshotPopup.highlightAreas = this.collectHighlightAreas(spec.highlight, layout);
}
if (spec.meta && spec.meta.length > 0) {
- this.screenshotPopup.metaGuides = this.collectMetaGuides(spec.meta);
+ this.screenshotPopup.metaGuides = this.collectMetaGuides(spec.meta, layout);
}
this.screenshotPopup.spec = spec;
this.screenshotPopup.shown = true;
@@ -656,11 +707,31 @@ function enrichObjectAndReturnHasFailure(object) {
object.expanded = false;
object.hasFailure = false;
- _.forEach(object.specs, function (spec) {
- if (spec.errors && spec.errors.length > 0) {
- object.hasFailure = true;
- }
- });
+ var enrichSpec = function(parent) {
+ return function (spec) {
+ if (spec.errors && spec.errors.length > 0) {
+ parent.hasFailure = true;
+ }
+ if (spec.subLayout && spec.subLayout.sections) {
+ _.forEach(spec.subLayout.sections, function (subSection) {
+ if (enrichSectionAndReturnHasFailure(subSection)) {
+ parent.hasFailure = true;
+ }
+ });
+ }
+ };
+ };
+
+ _.forEach(object.specs, enrichSpec(object));
+ if (object.specGroups) {
+ _.forEach(object.specGroups, function (specGroup) {
+ specGroup.expanded = false;
+ _.forEach(specGroup.specs, enrichSpec(specGroup));
+ if (specGroup.hasFailure) {
+ object.hasFailure = true;
+ }
+ });
+ }
return object.hasFailure;
}
@@ -719,6 +790,21 @@ function expandOnlyErrorsInSection (section) {
_.forEach(section.sections, expandOnlyErrorsInSection);
_.forEach(section.objects, function (object) {
object.expanded = object.hasFailure;
+ if (object.specs) {
+ _.forEach(object.specs, function (spec) {
+ if (spec.subLayout && spec.subLayout.sections) {
+ _.forEach(spec.subLayout.sections, expandOnlyErrorsInSection);
+ }
+ });
+ }
+ _.forEach(object.specGroups, function (specGroup) {
+ specGroup.expanded = specGroup.hasFailure;
+ _.forEach(specGroup.specs, function (spec) {
+ if (spec.subLayout && spec.subLayout.sections) {
+ _.forEach(spec.subLayout.sections, expandOnlyErrorsInSection);
+ }
+ });
+ });
});
}
@@ -734,6 +820,7 @@ function expandOnlyErrorsInNode (node) {
expandOnlyErrorsInNode(childNode);
});
}
+
}
function visitEachSection(section, callback) {
@@ -743,6 +830,17 @@ function visitEachSection(section, callback) {
});
_.forEach(section.objects, function (object) {
callback(object, 'object');
+
+ _.forEach(object.specs, function (spec) {
+ if (spec.subLayout) {
+ _.forEach(spec.subLayout.sections, function (subSection) {
+ visitEachSection(subSection, callback);
+ });
+ }
+ });
+ _.forEach(object.specGroups, function (specGroup) {
+ callback(specGroup);
+ });
});
}
diff --git a/galen-core/src/main/resources/html-report/report-test.tpl.html b/galen-core/src/main/resources/html-report/report-test.tpl.html
index 929b56bf..3f227628 100644
--- a/galen-core/src/main/resources/html-report/report-test.tpl.html
+++ b/galen-core/src/main/resources/html-report/report-test.tpl.html
@@ -54,7 +54,7 @@
{{childNode.name}}
-
+
@@ -156,7 +156,7 @@
-
+
{{section.name}}
-
-
+
+
@@ -188,7 +188,25 @@
v-on:click="toggleReportNode(object)"
>{{object.name}}:
-
+
+
+
+
+
+
+
+
+
+
{{specgroup.name}}:
+
+
@@ -200,10 +218,42 @@
v-bind:title="spec.place ? spec.place.filePath + ':' + spec.place.lineNumber : ''"
>{{spec.name}}
+ -
+ Show image comparison
+
- {{error}}
+
+
+
+
+
+
+
+
+
+
+