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}}:
- + + + +
+ + + + @@ -200,10 +218,42 @@ v-bind:title="spec.place ? spec.place.filePath + ':' + spec.place.lineNumber : ''" >{{spec.name}}
    +
  • + Show image comparison +
  • {{error}}
+
+ +
+ + + + + + + +