diff options
author | Anna Koskinen <anna@vaadin.com> | 2015-03-13 12:33:24 +0200 |
---|---|---|
committer | Johannes Tuikkala <johannes@vaadin.com> | 2015-03-17 16:07:32 +0200 |
commit | a5cf8109f4d419a350614f77404a25b2ff991fd2 (patch) | |
tree | 41e1dd401705367a053fd53ad0314cb372462bff | |
parent | 504809f3f1e49328e33b17fac2f3f4ceab276665 (diff) | |
download | vaadin-framework-a5cf8109f4d419a350614f77404a25b2ff991fd2.tar.gz vaadin-framework-a5cf8109f4d419a350614f77404a25b2ff991fd2.zip |
VScrollTable and WidgetUtil from 7.4.1 to 7.2.6 without DeferredWorker
Change-Id: I01a4b67ddebcf6f868250bf149e507a011ef9d1e
61 files changed, 3771 insertions, 1860 deletions
diff --git a/client/src/com/vaadin/client/WidgetUtil.java b/client/src/com/vaadin/client/WidgetUtil.java new file mode 100644 index 0000000000..5f88f6da46 --- /dev/null +++ b/client/src/com/vaadin/client/WidgetUtil.java @@ -0,0 +1,1462 @@ +/* + * Copyright 2000-2014 Vaadin 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 com.vaadin.client; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; +import java.util.logging.Logger; + +import com.google.gwt.core.client.JavaScriptObject; +import com.google.gwt.core.client.Scheduler; +import com.google.gwt.core.client.Scheduler.ScheduledCommand; +import com.google.gwt.dom.client.AnchorElement; +import com.google.gwt.dom.client.DivElement; +import com.google.gwt.dom.client.Document; +import com.google.gwt.dom.client.Element; +import com.google.gwt.dom.client.NativeEvent; +import com.google.gwt.dom.client.Node; +import com.google.gwt.dom.client.NodeList; +import com.google.gwt.dom.client.Style; +import com.google.gwt.dom.client.Style.Display; +import com.google.gwt.dom.client.Style.Unit; +import com.google.gwt.dom.client.Touch; +import com.google.gwt.event.dom.client.KeyEvent; +import com.google.gwt.regexp.shared.MatchResult; +import com.google.gwt.regexp.shared.RegExp; +import com.google.gwt.user.client.Command; +import com.google.gwt.user.client.DOM; +import com.google.gwt.user.client.Event; +import com.google.gwt.user.client.EventListener; +import com.google.gwt.user.client.Window; +import com.google.gwt.user.client.ui.RootPanel; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.shared.util.SharedUtil; + +/** + * Utility methods which are related to client side code only + */ +public class WidgetUtil { + + /** + * Helper method for debugging purposes. + * + * Stops execution on firefox browsers on a breakpoint. + * + */ + public static native void browserDebugger() + /*-{ + if($wnd.console) + debugger; + }-*/; + + /** + * Helper method for a bug fix #14041. For mozilla getKeyCode return 0 for + * space bar (because space is considered as char). If return 0 use + * getCharCode. + * + * @param event + * @return return key code + * @since 7.2.4 + */ + public static int getKeyCode(KeyEvent<?> event) { + int keyCode = event.getNativeEvent().getKeyCode(); + if (keyCode == 0) { + keyCode = event.getNativeEvent().getCharCode(); + } + return keyCode; + } + + /** + * + * Returns the topmost element of from given coordinates. + * + * TODO fix crossplat issues clientX vs pageX. See quircksmode. Not critical + * for vaadin as we scroll div istead of page. + * + * @param x + * @param y + * @return the element at given coordinates + */ + public static native Element getElementFromPoint(int clientX, int clientY) + /*-{ + var el = $wnd.document.elementFromPoint(clientX, clientY); + // Call elementFromPoint two times to make sure IE8 also returns something sensible if the application is running in an iframe + el = $wnd.document.elementFromPoint(clientX, clientY); + if(el != null && el.nodeType == 3) { + el = el.parentNode; + } + return el; + }-*/; + + public static float parseRelativeSize(String size) { + if (size == null || !size.endsWith("%")) { + return -1; + } + + try { + return Float.parseFloat(size.substring(0, size.length() - 1)); + } catch (Exception e) { + getLogger().warning("Unable to parse relative size"); + return -1; + } + } + + private static final Element escapeHtmlHelper = DOM.createDiv(); + + /** + * Converts html entities to text. + * + * @param html + * @return escaped string presentation of given html + */ + public static String escapeHTML(String html) { + DOM.setInnerText(escapeHtmlHelper, html); + String escapedText = DOM.getInnerHTML(escapeHtmlHelper); + if (BrowserInfo.get().isIE8()) { + // #7478 IE8 "incorrectly" returns "<br>" for newlines set using + // setInnerText. The same for " " which is converted to " " + escapedText = escapedText.replaceAll("<(BR|br)>", "\n"); + escapedText = escapedText.replaceAll(" ", " "); + } + return escapedText; + } + + /** + * Escapes the string so it is safe to write inside an HTML attribute. + * + * @param attribute + * The string to escape + * @return An escaped version of <literal>attribute</literal>. + */ + public static String escapeAttribute(String attribute) { + if (attribute == null) { + return ""; + } + attribute = attribute.replace("\"", """); + attribute = attribute.replace("'", "'"); + attribute = attribute.replace(">", ">"); + attribute = attribute.replace("<", "<"); + attribute = attribute.replace("&", "&"); + return attribute; + } + + /** + * Clones given element as in JavaScript. + * + * Deprecate this if there appears similar method into GWT someday. + * + * @param element + * @param deep + * clone child tree also + * @return + */ + public static native Element cloneNode(Element element, boolean deep) + /*-{ + return element.cloneNode(deep); + }-*/; + + public static int measureHorizontalPaddingAndBorder(Element element, + int paddingGuess) { + String originalWidth = DOM.getStyleAttribute(element, "width"); + + int originalOffsetWidth = element.getOffsetWidth(); + int widthGuess = (originalOffsetWidth - paddingGuess); + if (widthGuess < 1) { + widthGuess = 1; + } + element.getStyle().setWidth(widthGuess, Unit.PX); + int padding = element.getOffsetWidth() - widthGuess; + + element.getStyle().setProperty("width", originalWidth); + + return padding; + } + + public static int measureVerticalPaddingAndBorder(Element element, + int paddingGuess) { + String originalHeight = DOM.getStyleAttribute(element, "height"); + int originalOffsetHeight = element.getOffsetHeight(); + int widthGuess = (originalOffsetHeight - paddingGuess); + if (widthGuess < 1) { + widthGuess = 1; + } + element.getStyle().setHeight(widthGuess, Unit.PX); + int padding = element.getOffsetHeight() - widthGuess; + + element.getStyle().setProperty("height", originalHeight); + return padding; + } + + public static int measureHorizontalBorder(Element element) { + int borders; + + if (BrowserInfo.get().isIE()) { + String width = element.getStyle().getProperty("width"); + String height = element.getStyle().getProperty("height"); + + int offsetWidth = element.getOffsetWidth(); + int offsetHeight = element.getOffsetHeight(); + if (offsetHeight < 1) { + offsetHeight = 1; + } + if (offsetWidth < 1) { + offsetWidth = 10; + } + element.getStyle().setPropertyPx("height", offsetHeight); + element.getStyle().setPropertyPx("width", offsetWidth); + + borders = element.getOffsetWidth() - element.getClientWidth(); + + element.getStyle().setProperty("width", width); + element.getStyle().setProperty("height", height); + } else { + borders = element.getOffsetWidth() + - element.getPropertyInt("clientWidth"); + } + assert borders >= 0; + + return borders; + } + + public static int measureVerticalBorder(Element element) { + int borders; + if (BrowserInfo.get().isIE()) { + String width = element.getStyle().getProperty("width"); + String height = element.getStyle().getProperty("height"); + + int offsetWidth = element.getOffsetWidth(); + int offsetHeight = element.getOffsetHeight(); + if (offsetHeight < 1) { + offsetHeight = 1; + } + if (offsetWidth < 1) { + offsetWidth = 10; + } + element.getStyle().setPropertyPx("width", offsetWidth); + + element.getStyle().setPropertyPx("height", offsetHeight); + + borders = element.getOffsetHeight() + - element.getPropertyInt("clientHeight"); + + element.getStyle().setProperty("height", height); + element.getStyle().setProperty("width", width); + } else { + borders = element.getOffsetHeight() + - element.getPropertyInt("clientHeight"); + } + assert borders >= 0; + + return borders; + } + + public static int measureMarginLeft(Element element) { + return element.getAbsoluteLeft() + - element.getParentElement().getAbsoluteLeft(); + } + + public static int setHeightExcludingPaddingAndBorder(Widget widget, + String height, int paddingBorderGuess) { + if (height.equals("")) { + setHeight(widget, ""); + return paddingBorderGuess; + } else if (height.endsWith("px")) { + int pixelHeight = Integer.parseInt(height.substring(0, + height.length() - 2)); + return setHeightExcludingPaddingAndBorder(widget.getElement(), + pixelHeight, paddingBorderGuess, false); + } else { + // Set the height in unknown units + setHeight(widget, height); + // Use the offsetWidth + return setHeightExcludingPaddingAndBorder(widget.getElement(), + widget.getOffsetHeight(), paddingBorderGuess, true); + } + } + + private static void setWidth(Widget widget, String width) { + widget.getElement().getStyle().setProperty("width", width); + } + + private static void setHeight(Widget widget, String height) { + widget.getElement().getStyle().setProperty("height", height); + } + + public static int setWidthExcludingPaddingAndBorder(Widget widget, + String width, int paddingBorderGuess) { + if (width.equals("")) { + setWidth(widget, ""); + return paddingBorderGuess; + } else if (width.endsWith("px")) { + int pixelWidth = Integer.parseInt(width.substring(0, + width.length() - 2)); + return setWidthExcludingPaddingAndBorder(widget.getElement(), + pixelWidth, paddingBorderGuess, false); + } else { + setWidth(widget, width); + return setWidthExcludingPaddingAndBorder(widget.getElement(), + widget.getOffsetWidth(), paddingBorderGuess, true); + } + } + + public static int setWidthExcludingPaddingAndBorder(Element element, + int requestedWidth, int horizontalPaddingBorderGuess, + boolean requestedWidthIncludesPaddingBorder) { + + int widthGuess = requestedWidth - horizontalPaddingBorderGuess; + if (widthGuess < 0) { + widthGuess = 0; + } + + element.getStyle().setWidth(widthGuess, Unit.PX); + int captionOffsetWidth = DOM.getElementPropertyInt(element, + "offsetWidth"); + + int actualPadding = captionOffsetWidth - widthGuess; + + if (requestedWidthIncludesPaddingBorder) { + actualPadding += actualPadding; + } + + if (actualPadding != horizontalPaddingBorderGuess) { + int w = requestedWidth - actualPadding; + if (w < 0) { + // Cannot set negative width even if we would want to + w = 0; + } + element.getStyle().setWidth(w, Unit.PX); + + } + + return actualPadding; + + } + + public static int setHeightExcludingPaddingAndBorder(Element element, + int requestedHeight, int verticalPaddingBorderGuess, + boolean requestedHeightIncludesPaddingBorder) { + + int heightGuess = requestedHeight - verticalPaddingBorderGuess; + if (heightGuess < 0) { + heightGuess = 0; + } + + element.getStyle().setHeight(heightGuess, Unit.PX); + int captionOffsetHeight = DOM.getElementPropertyInt(element, + "offsetHeight"); + + int actualPadding = captionOffsetHeight - heightGuess; + + if (requestedHeightIncludesPaddingBorder) { + actualPadding += actualPadding; + } + + if (actualPadding != verticalPaddingBorderGuess) { + int h = requestedHeight - actualPadding; + if (h < 0) { + // Cannot set negative height even if we would want to + h = 0; + } + element.getStyle().setHeight(h, Unit.PX); + + } + + return actualPadding; + + } + + public static void setFloat(Element element, String value) { + if (BrowserInfo.get().isIE()) { + element.getStyle().setProperty("styleFloat", value); + } else { + element.getStyle().setProperty("cssFloat", value); + } + } + + private static int detectedScrollbarSize = -1; + + public static int getNativeScrollbarSize() { + if (detectedScrollbarSize < 0) { + Element scroller = DOM.createDiv(); + scroller.getStyle().setProperty("width", "50px"); + scroller.getStyle().setProperty("height", "50px"); + scroller.getStyle().setProperty("overflow", "scroll"); + scroller.getStyle().setProperty("position", "absolute"); + scroller.getStyle().setProperty("marginLeft", "-5000px"); + RootPanel.getBodyElement().appendChild(scroller); + detectedScrollbarSize = scroller.getOffsetWidth() + - scroller.getPropertyInt("clientWidth"); + + RootPanel.getBodyElement().removeChild(scroller); + } + return detectedScrollbarSize; + } + + /** + * Defers the execution of {@link #runWebkitOverflowAutoFix(Element)} + * + * @since 7.2.6 + * @param elem + * with overflow auto + */ + public static void runWebkitOverflowAutoFixDeferred(final Element elem) { + Scheduler.get().scheduleDeferred(new Command() { + + @Override + public void execute() { + WidgetUtil.runWebkitOverflowAutoFix(elem); + } + }); + + } + + /** + * Run workaround for webkits overflow auto issue. + * + * See: our bug #2138 and https://bugs.webkit.org/show_bug.cgi?id=21462 + * + * @param elem + * with overflow auto + */ + public static void runWebkitOverflowAutoFix(final Element elem) { + // Add max version if fix lands sometime to Webkit + // Starting from Opera 11.00, also a problem in Opera + if (BrowserInfo.get().requiresOverflowAutoFix()) { + final String originalOverflow = elem.getStyle().getProperty( + "overflow"); + final String originalOverflowX = elem.getStyle().getProperty( + "overflowX"); + final String originalOverflowY = elem.getStyle().getProperty( + "overflowY"); + if ("hidden".equals(originalOverflow) + || "hidden".equals(originalOverflowX) + || "hidden".equals(originalOverflowY)) { + return; + } + + // check the scrolltop value before hiding the element + final int scrolltop = elem.getScrollTop(); + final int scrollleft = elem.getScrollLeft(); + elem.getStyle().setProperty("overflow", "hidden"); + + Scheduler.get().scheduleDeferred(new Command() { + @Override + public void execute() { + // Dough, Safari scroll auto means actually just a moped + elem.getStyle().setProperty("overflow", originalOverflow); + if (!originalOverflowX.isEmpty()) { + elem.getStyle().setProperty("overflowX", + originalOverflowX); + } + if (!originalOverflowY.isEmpty()) { + elem.getStyle().setProperty("overflowY", + originalOverflowY); + } + + if (scrolltop > 0 || elem.getScrollTop() > 0) { + int scrollvalue = scrolltop; + if (scrollvalue == 0) { + // mysterious are the ways of webkits scrollbar + // handling. In some cases webkit reports bad (0) + // scrolltop before hiding the element temporary, + // sometimes after. + scrollvalue = elem.getScrollTop(); + } + // fix another bug where scrollbar remains in wrong + // position + elem.setScrollTop(scrollvalue - 1); + elem.setScrollTop(scrollvalue); + } + + // fix for #6940 : Table horizontal scroll sometimes not + // updated when collapsing/expanding columns + // Also appeared in Safari 5.1 with webkit 534 (#7667) + if ((BrowserInfo.get().isChrome() || (BrowserInfo.get() + .isSafari() && BrowserInfo.get().getWebkitVersion() >= 534)) + && (scrollleft > 0 || elem.getScrollLeft() > 0)) { + int scrollvalue = scrollleft; + + if (scrollvalue == 0) { + // mysterious are the ways of webkits scrollbar + // handling. In some cases webkit may report a bad + // (0) scrollleft before hiding the element + // temporary, sometimes after. + scrollvalue = elem.getScrollLeft(); + } + // fix another bug where scrollbar remains in wrong + // position + elem.setScrollLeft(scrollvalue - 1); + elem.setScrollLeft(scrollvalue); + } + } + }); + } + + } + + public static void alert(String string) { + if (true) { + Window.alert(string); + } + } + + /** + * Gets the border-box width for the given element, i.e. element width + + * border + padding. Always rounds up to nearest integer. + * + * @param element + * The element to check + * @return The border-box width for the element + */ + public static int getRequiredWidth(com.google.gwt.dom.client.Element element) { + int reqWidth = getRequiredWidthBoundingClientRect(element); + if (BrowserInfo.get().isIE() && !BrowserInfo.get().isIE8()) { + int csSize = getRequiredWidthComputedStyle(element); + if (csSize == reqWidth + 1) { + // If computed style reports one pixel larger than requiredWidth + // we would be rounding in the wrong direction in IE9. Round up + // instead. + // We do not always use csSize as it e.g. for 100% wide Labels + // in GridLayouts produces senseless values (see e.g. + // ThemeTestUI with Runo). + return csSize; + } + } + return reqWidth; + } + + /** + * Gets the border-box height for the given element, i.e. element height + + * border + padding. Always rounds up to nearest integer. + * + * @param element + * The element to check + * @return The border-box height for the element + */ + public static int getRequiredHeight( + com.google.gwt.dom.client.Element element) { + int reqHeight = getRequiredHeightBoundingClientRect(element); + if (BrowserInfo.get().isIE() && !BrowserInfo.get().isIE8()) { + int csSize = getRequiredHeightComputedStyle(element); + if (csSize == reqHeight + 1) { + // If computed style reports one pixel larger than + // requiredHeight we would be rounding in the wrong direction in + // IE9. Round up instead. + // We do not always use csSize as it e.g. for 100% wide Labels + // in GridLayouts produces senseless values (see e.g. + // ThemeTestUI with Runo). + return csSize; + } + } + return reqHeight; + } + + /** + * Calculates the width of the element's bounding rectangle. + * <p> + * In case the browser doesn't support bounding rectangles, the returned + * value is the offset width. + * + * @param element + * the element of which to calculate the width + * @return the width of the element + */ + public static int getRequiredWidthBoundingClientRect( + com.google.gwt.dom.client.Element element) { + return (int) Math + .ceil(getRequiredWidthBoundingClientRectDouble(element)); + } + + /** + * Calculates the width of the element's bounding rectangle to subpixel + * precision. + * <p> + * In case the browser doesn't support bounding rectangles, the returned + * value is the offset width. + * + * @param element + * the element of which to calculate the width + * @return the subpixel-accurate width of the element + * @since 7.4 + */ + public static native double getRequiredWidthBoundingClientRectDouble( + com.google.gwt.dom.client.Element element) + /*-{ + if (element.getBoundingClientRect) { + var rect = element.getBoundingClientRect(); + return rect.right - rect.left; + } else { + return element.offsetWidth; + } + }-*/; + + public static native int getRequiredHeightComputedStyle( + com.google.gwt.dom.client.Element element) + /*-{ + var cs = element.ownerDocument.defaultView.getComputedStyle(element); + var heightPx = cs.height; + if(heightPx == 'auto'){ + // Fallback for when IE reports auto + heightPx = @com.vaadin.client.WidgetUtil::getRequiredHeightBoundingClientRect(Lcom/google/gwt/dom/client/Element;)(element) + 'px'; + } + var borderTopPx = cs.borderTop; + var borderBottomPx = cs.borderBottom; + var paddingTopPx = cs.paddingTop; + var paddingBottomPx = cs.paddingBottom; + + var height = heightPx.substring(0,heightPx.length-2); + var border = borderTopPx.substring(0,borderTopPx.length-2)+borderBottomPx.substring(0,borderBottomPx.length-2); + var padding = paddingTopPx.substring(0,paddingTopPx.length-2)+paddingBottomPx.substring(0,paddingBottomPx.length-2); + return Math.ceil(height+border+padding); + }-*/; + + public static native int getRequiredWidthComputedStyle( + com.google.gwt.dom.client.Element element) + /*-{ + var cs = element.ownerDocument.defaultView.getComputedStyle(element); + var widthPx = cs.width; + if(widthPx == 'auto'){ + // Fallback for when IE reports auto + widthPx = @com.vaadin.client.WidgetUtil::getRequiredWidthBoundingClientRect(Lcom/google/gwt/dom/client/Element;)(element) + 'px'; + } + var borderLeftPx = cs.borderLeft; + var borderRightPx = cs.borderRight; + var paddingLeftPx = cs.paddingLeft; + var paddingRightPx = cs.paddingRight; + + var width = widthPx.substring(0,widthPx.length-2); + var border = borderLeftPx.substring(0,borderLeftPx.length-2)+borderRightPx.substring(0,borderRightPx.length-2); + var padding = paddingLeftPx.substring(0,paddingLeftPx.length-2)+paddingRightPx.substring(0,paddingRightPx.length-2); + return Math.ceil(width+border+padding); + }-*/; + + /** + * Calculates the height of the element's bounding rectangle. + * <p> + * In case the browser doesn't support bounding rectangles, the returned + * value is the offset height. + * + * @param element + * the element of which to calculate the height + * @return the height of the element + */ + public static int getRequiredHeightBoundingClientRect( + com.google.gwt.dom.client.Element element) { + return (int) Math + .ceil(getRequiredHeightBoundingClientRectDouble(element)); + } + + /** + * Calculates the height of the element's bounding rectangle to subpixel + * precision. + * <p> + * In case the browser doesn't support bounding rectangles, the returned + * value is the offset height. + * + * @param element + * the element of which to calculate the height + * @return the subpixel-accurate height of the element + * @since 7.4 + */ + public static native double getRequiredHeightBoundingClientRectDouble( + com.google.gwt.dom.client.Element element) + /*-{ + var height; + if (element.getBoundingClientRect != null) { + var rect = element.getBoundingClientRect(); + height = rect.bottom - rect.top; + } else { + height = element.offsetHeight; + } + return height; + }-*/; + + public static int getRequiredWidth(Widget widget) { + return getRequiredWidth(widget.getElement()); + } + + public static int getRequiredHeight(Widget widget) { + return getRequiredHeight(widget.getElement()); + } + + /** + * Detects what is currently the overflow style attribute in given element. + * + * @param pe + * the element to detect + * @return true if auto or scroll + */ + public static boolean mayHaveScrollBars(com.google.gwt.dom.client.Element pe) { + String overflow = getComputedStyle(pe, "overflow"); + if (overflow != null) { + if (overflow.equals("auto") || overflow.equals("scroll")) { + return true; + } else { + return false; + } + } else { + return false; + } + } + + /** + * A simple helper method to detect "computed style" (aka style sheets + + * element styles). Values returned differ a lot depending on browsers. + * Always be very careful when using this. + * + * @param el + * the element from which the style property is detected + * @param p + * the property to detect + * @return String value of style property + */ + private static native String getComputedStyle( + com.google.gwt.dom.client.Element el, String p) + /*-{ + try { + + if (el.currentStyle) { + // IE + return el.currentStyle[p]; + } else if (window.getComputedStyle) { + // Sa, FF, Opera + var view = el.ownerDocument.defaultView; + return view.getComputedStyle(el,null).getPropertyValue(p); + } else { + // fall back for non IE, Sa, FF, Opera + return ""; + } + } catch (e) { + return ""; + } + + }-*/; + + /** + * Will (attempt) to focus the given DOM Element. + * + * @param el + * the element to focus + */ + public static native void focus(Element el) + /*-{ + try { + el.focus(); + } catch (e) { + + } + }-*/; + + /** + * Helper method to find first instance of given Widget type found by + * traversing DOM upwards from given element. + * <p> + * <strong>Note:</strong> If {@code element} is inside some widget {@code W} + * , <em>and</em> {@code W} in turn is wrapped in a {@link Composite} + * {@code C}, this method will not find {@code W}. It returns either + * {@code C} or null, depending on whether the class parameter matches. This + * may also be the case with other Composite-like classes that hijack the + * event handling of their child widget(s). + * + * @param element + * the element where to start seeking of Widget + * @param class1 + * the Widget type to seek for + */ + @SuppressWarnings("unchecked") + public static <T> T findWidget(Element element, + Class<? extends Widget> class1) { + if (element != null) { + /* First seek for the first EventListener (~Widget) from dom */ + EventListener eventListener = null; + while (eventListener == null && element != null) { + eventListener = Event.getEventListener(element); + if (eventListener == null) { + element = element.getParentElement(); + } + } + if (eventListener instanceof Widget) { + /* + * Then find the first widget of type class1 from widget + * hierarchy + */ + Widget w = (Widget) eventListener; + while (w != null) { + if (class1 == null || w.getClass() == class1) { + return (T) w; + } + w = w.getParent(); + } + } + } + return null; + } + + /** + * Force webkit to redraw an element + * + * @param element + * The element that should be redrawn + */ + public static void forceWebkitRedraw(Element element) { + Style style = element.getStyle(); + String s = style.getProperty("webkitTransform"); + if (s == null || s.length() == 0) { + style.setProperty("webkitTransform", "scale(1)"); + } else { + style.setProperty("webkitTransform", ""); + } + } + + /** + * Performs a hack to trigger a re-layout in the IE8. This is usually + * necessary in cases where IE8 "forgets" to update child elements when they + * resize. + * + * @param e + * The element to perform the hack on + */ + public static final void forceIE8Redraw(Element e) { + if (BrowserInfo.get().isIE8()) { + forceIERedraw(e); + } + } + + /** + * Performs a hack to trigger a re-layout in the IE browser. This is usually + * necessary in cases where IE "forgets" to update child elements when they + * resize. + * + * @since 7.3 + * @param e + * The element to perform the hack on + */ + public static void forceIERedraw(Element e) { + if (BrowserInfo.get().isIE()) { + setStyleTemporarily(e, "zoom", "1"); + } + } + + /** + * Detaches and re-attaches the element from its parent. The element is + * reattached at the same position in the DOM as it was before. + * + * Does nothing if the element is not attached to the DOM. + * + * @param element + * The element to detach and re-attach + */ + public static void detachAttach(Element element) { + if (element == null) { + return; + } + + Node nextSibling = element.getNextSibling(); + Node parent = element.getParentNode(); + if (parent == null) { + return; + } + + parent.removeChild(element); + if (nextSibling == null) { + parent.appendChild(element); + } else { + parent.insertBefore(element, nextSibling); + } + + } + + public static void sinkOnloadForImages(Element element) { + NodeList<com.google.gwt.dom.client.Element> imgElements = element + .getElementsByTagName("img"); + for (int i = 0; i < imgElements.getLength(); i++) { + DOM.sinkEvents(imgElements.getItem(i), Event.ONLOAD); + } + + } + + /** + * Returns the index of the childElement within its parent. + * + * @param subElement + * @return + */ + public static int getChildElementIndex(Element childElement) { + int idx = 0; + Node n = childElement; + while ((n = n.getPreviousSibling()) != null) { + idx++; + } + + return idx; + } + + /** + * Temporarily sets the {@code styleProperty} to {@code tempValue} and then + * resets it to its current value. Used mainly to work around rendering + * issues in IE (and possibly in other browsers) + * + * @param element + * The target element + * @param styleProperty + * The name of the property to set + * @param tempValue + * The temporary value + */ + public static void setStyleTemporarily(Element element, + final String styleProperty, String tempValue) { + final Style style = element.getStyle(); + final String currentValue = style.getProperty(styleProperty); + + style.setProperty(styleProperty, tempValue); + element.getOffsetWidth(); + style.setProperty(styleProperty, currentValue); + + } + + /** + * A helper method to return the client position from an event. Returns + * position from either first changed touch (if touch event) or from the + * event itself. + * + * @param event + * @return + */ + public static int getTouchOrMouseClientX(Event event) { + if (isTouchEvent(event)) { + return event.getChangedTouches().get(0).getClientX(); + } else { + return event.getClientX(); + } + } + + /** + * Find the element corresponding to the coordinates in the passed mouse + * event. Please note that this is not always the same as the target of the + * event e.g. if event capture is used. + * + * @param event + * the mouse event to get coordinates from + * @return the element at the coordinates of the event + */ + public static Element getElementUnderMouse(NativeEvent event) { + int pageX = getTouchOrMouseClientX(event); + int pageY = getTouchOrMouseClientY(event); + + return getElementFromPoint(pageX, pageY); + } + + /** + * A helper method to return the client position from an event. Returns + * position from either first changed touch (if touch event) or from the + * event itself. + * + * @param event + * @return + */ + public static int getTouchOrMouseClientY(Event event) { + if (isTouchEvent(event)) { + return event.getChangedTouches().get(0).getClientY(); + } else { + return event.getClientY(); + } + } + + /** + * + * @see #getTouchOrMouseClientY(Event) + * @param currentGwtEvent + * @return + */ + public static int getTouchOrMouseClientY(NativeEvent currentGwtEvent) { + return getTouchOrMouseClientY(Event.as(currentGwtEvent)); + } + + /** + * @see #getTouchOrMouseClientX(Event) + * + * @param event + * @return + */ + public static int getTouchOrMouseClientX(NativeEvent event) { + return getTouchOrMouseClientX(Event.as(event)); + } + + public static boolean isTouchEvent(Event event) { + return event.getType().contains("touch"); + } + + public static boolean isTouchEvent(NativeEvent event) { + return isTouchEvent(Event.as(event)); + } + + public static void simulateClickFromTouchEvent(Event touchevent, + Widget widget) { + Touch touch = touchevent.getChangedTouches().get(0); + final NativeEvent createMouseUpEvent = Document.get() + .createMouseUpEvent(0, touch.getScreenX(), touch.getScreenY(), + touch.getClientX(), touch.getClientY(), false, false, + false, false, NativeEvent.BUTTON_LEFT); + final NativeEvent createMouseDownEvent = Document.get() + .createMouseDownEvent(0, touch.getScreenX(), + touch.getScreenY(), touch.getClientX(), + touch.getClientY(), false, false, false, false, + NativeEvent.BUTTON_LEFT); + final NativeEvent createMouseClickEvent = Document.get() + .createClickEvent(0, touch.getScreenX(), touch.getScreenY(), + touch.getClientX(), touch.getClientY(), false, false, + false, false); + + /* + * Get target with element from point as we want the actual element, not + * the one that sunk the event. + */ + final Element target = getElementFromPoint(touch.getClientX(), + touch.getClientY()); + + /* + * Fixes infocusable form fields in Safari of iOS 5.x and some Android + * browsers. + */ + Widget targetWidget = findWidget(target, null); + if (targetWidget instanceof com.google.gwt.user.client.ui.Focusable) { + final com.google.gwt.user.client.ui.Focusable toBeFocusedWidget = (com.google.gwt.user.client.ui.Focusable) targetWidget; + toBeFocusedWidget.setFocus(true); + } else if (targetWidget instanceof Focusable) { + ((Focusable) targetWidget).focus(); + } + + Scheduler.get().scheduleDeferred(new ScheduledCommand() { + @Override + public void execute() { + try { + target.dispatchEvent(createMouseDownEvent); + target.dispatchEvent(createMouseUpEvent); + target.dispatchEvent(createMouseClickEvent); + } catch (Exception e) { + } + + } + }); + + } + + /** + * Gets the currently focused element. + * + * @return The active element or null if no active element could be found. + */ + public native static Element getFocusedElement() + /*-{ + if ($wnd.document.activeElement) { + return $wnd.document.activeElement; + } + + return null; + }-*/; + + /** + * Gets currently focused element and checks if it's editable + * + * @since 7.4 + * + * @return true if focused element is editable + */ + public static boolean isFocusedElementEditable() { + Element focusedElement = WidgetUtil.getFocusedElement(); + if (focusedElement != null) { + String tagName = focusedElement.getTagName(); + String contenteditable = focusedElement + .getAttribute("contenteditable"); + + return "textarea".equalsIgnoreCase(tagName) + || "input".equalsIgnoreCase(tagName) + || "true".equalsIgnoreCase(contenteditable); + } + return false; + } + + /** + * Kind of stronger version of isAttached(). In addition to std isAttached, + * this method checks that this widget nor any of its parents is hidden. Can + * be e.g used to check whether component should react to some events or + * not. + * + * @param widget + * @return true if attached and displayed + */ + public static boolean isAttachedAndDisplayed(Widget widget) { + if (widget.isAttached()) { + /* + * Failfast using offset size, then by iterating the widget tree + */ + boolean notZeroSized = widget.getOffsetHeight() > 0 + || widget.getOffsetWidth() > 0; + return notZeroSized || checkVisibilityRecursively(widget); + } else { + return false; + } + } + + private static boolean checkVisibilityRecursively(Widget widget) { + if (widget.isVisible()) { + Widget parent = widget.getParent(); + if (parent == null) { + return true; // root panel + } else { + return checkVisibilityRecursively(parent); + } + } else { + return false; + } + } + + /** + * Scrolls an element into view vertically only. Modified version of + * Element.scrollIntoView. + * + * @param elem + * The element to scroll into view + */ + public static native void scrollIntoViewVertically(Element elem) + /*-{ + var top = elem.offsetTop; + var height = elem.offsetHeight; + + if (elem.parentNode != elem.offsetParent) { + top -= elem.parentNode.offsetTop; + } + + var cur = elem.parentNode; + while (cur && (cur.nodeType == 1)) { + if (top < cur.scrollTop) { + cur.scrollTop = top; + } + if (top + height > cur.scrollTop + cur.clientHeight) { + cur.scrollTop = (top + height) - cur.clientHeight; + } + + var offsetTop = cur.offsetTop; + if (cur.parentNode != cur.offsetParent) { + offsetTop -= cur.parentNode.offsetTop; + } + + top += offsetTop - cur.scrollTop; + cur = cur.parentNode; + } + }-*/; + + /** + * Checks if the given event is either a touch event or caused by the left + * mouse button + * + * @param event + * @return true if the event is a touch event or caused by the left mouse + * button, false otherwise + */ + public static boolean isTouchEventOrLeftMouseButton(Event event) { + boolean touchEvent = WidgetUtil.isTouchEvent(event); + return touchEvent || event.getButton() == Event.BUTTON_LEFT; + } + + /** + * Resolve a relative URL to an absolute URL based on the current document's + * location. + * + * @param url + * a string with the relative URL to resolve + * @return the corresponding absolute URL as a string + */ + public static String getAbsoluteUrl(String url) { + if (BrowserInfo.get().isIE8()) { + // The hard way - must use innerHTML and attach to DOM in IE8 + DivElement divElement = Document.get().createDivElement(); + divElement.getStyle().setDisplay(Display.NONE); + + RootPanel.getBodyElement().appendChild(divElement); + divElement.setInnerHTML("<a href='" + escapeAttribute(url) + + "' ></a>"); + + AnchorElement a = divElement.getChild(0).cast(); + String href = a.getHref(); + + RootPanel.getBodyElement().removeChild(divElement); + return href; + } else { + AnchorElement a = Document.get().createAnchorElement(); + a.setHref(url); + return a.getHref(); + } + } + + /** + * Sets the selection range of an input element. + * + * We need this JSNI function to set selection range so that we can use the + * optional direction attribute to set the anchor to the end and the focus + * to the start. This makes Firefox work the same way as other browsers + * (#13477) + * + * @param elem + * the html input element. + * @param pos + * the index of the first selected character. + * @param length + * the selection length. + * @param direction + * a string indicating the direction in which the selection was + * performed. This may be "forward" or "backward", or "none" if + * the direction is unknown or irrelevant. + * + * @since 7.3 + */ + public native static void setSelectionRange(Element elem, int pos, + int length, String direction) + /*-{ + try { + elem.setSelectionRange(pos, pos + length, direction); + } catch (e) { + // Firefox throws exception if TextBox is not visible, even if attached + } + }-*/; + + /** + * The allowed value inaccuracy when comparing two double-typed pixel + * values. + * <p> + * Since we're comparing pixels on a screen, epsilon must be less than 1. + * 0.49 was deemed a perfectly fine and beautifully round number. + */ + public static final double PIXEL_EPSILON = 0.49d; + + /** + * Compares two double values with the error margin of + * {@link #PIXEL_EPSILON} (i.e. {@value #PIXEL_EPSILON}) + * + * @param num1 + * the first value for which to compare equality + * @param num2 + * the second value for which to compare equality + * @since 7.4 + * + * @return true if the values are considered equals; false otherwise + */ + public static boolean pixelValuesEqual(final double num1, final double num2) { + return Math.abs(num1 - num2) <= PIXEL_EPSILON; + } + + public static native TextRectangle getBoundingClientRect(Element e) + /*-{ + return e.getBoundingClientRect(); + }-*/; + + public static final class TextRectangle extends JavaScriptObject { + protected TextRectangle() { + } + + public native double getBottom() + /*-{ + return this.bottom; + }-*/; + + public native double getHeight() + /*-{ + return this.height; + }-*/; + + public native double getLeft() + /*-{ + return this.left; + }-*/; + + public native double getRight() + /*-{ + return this.right; + }-*/; + + public native double getTop() + /*-{ + return this.top; + }-*/; + + public native double getWidth() + /*-{ + return this.width; + }-*/; + } + + /** + * Wrap a css size value and its unit and translate back and forth to the + * string representation.<br/> + * Eg. 50%, 123px, ... + * + * @since 7.2.6 + * @author Vaadin Ltd + */ + @SuppressWarnings("serial") + public static class CssSize implements Serializable { + + /* + * Map the size units with their type. + */ + private static Map<String, Unit> type2Unit = new HashMap<String, Style.Unit>(); + static { + for (Unit unit : Unit.values()) { + type2Unit.put(unit.getType(), unit); + } + } + + /** + * Gets the unit value by its type. + * + * @param type + * the type of the unit as found in the style. + * @return the unit value. + */ + public static Unit unitByType(String type) { + return type2Unit.get(type); + } + + /* + * Regex to parse the size. + */ + private static final RegExp sizePattern = RegExp + .compile(SharedUtil.SIZE_PATTERN); + + /** + * Parse the size from string format to {@link CssSize}. + * + * @param s + * the size as string. + * @return a {@link CssSize} object. + */ + public static CssSize fromString(String s) { + if (s == null) { + return null; + } + + s = s.trim(); + if ("".equals(s)) { + return null; + } + + float size = 0; + Unit unit = null; + + MatchResult matcher = sizePattern.exec(s); + if (matcher.getGroupCount() > 1) { + + size = Float.parseFloat(matcher.getGroup(1)); + if (size < 0) { + size = -1; + unit = Unit.PX; + + } else { + String symbol = matcher.getGroup(2); + unit = unitByType(symbol); + } + } else { + throw new IllegalArgumentException("Invalid size argument: \"" + + s + "\" (should match " + sizePattern.getSource() + + ")"); + } + return new CssSize(size, unit); + } + + /** + * Creates a {@link CssSize} using a value and its measurement unit. + * + * @param value + * the value. + * @param unit + * the unit. + * @return the {@link CssSize} object. + */ + public static CssSize fromValueUnit(float value, Unit unit) { + return new CssSize(value, unit); + } + + /* + * The value. + */ + private final float value; + + /* + * The measure unit. + */ + private final Unit unit; + + private CssSize(float value, Unit unit) { + this.value = value; + this.unit = unit; + } + + /** + * Gets the value for this css size. + * + * @return the value. + */ + public float getValue() { + return value; + } + + /** + * Gets the measurement unit for this css size. + * + * @return the unit. + */ + public Unit getUnit() { + return unit; + } + + @Override + public String toString() { + return value + unit.getType(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof CssSize) { + CssSize size = (CssSize) obj; + return size.value == value && size.unit == unit; + } + + return false; + } + + /** + * Check whether the two sizes are equals. + * + * @param cssSize1 + * the first size to compare. + * @param cssSize2 + * the other size to compare with the first one. + * @return true if the two sizes are equals, otherwise false. + */ + public static boolean equals(String cssSize1, String cssSize2) { + return CssSize.fromString(cssSize1).equals( + CssSize.fromString(cssSize2)); + } + + } + + private static Logger getLogger() { + return Logger.getLogger(WidgetUtil.class.getName()); + } + +} diff --git a/client/src/com/vaadin/client/ui/VScrollTable.java b/client/src/com/vaadin/client/ui/VScrollTable.java index 2b8ffec2d7..5a48455ae3 100644 --- a/client/src/com/vaadin/client/ui/VScrollTable.java +++ b/client/src/com/vaadin/client/ui/VScrollTable.java @@ -25,6 +25,8 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; import com.google.gwt.core.client.JavaScriptObject; import com.google.gwt.core.client.Scheduler; @@ -47,8 +49,6 @@ import com.google.gwt.dom.client.TableSectionElement; import com.google.gwt.dom.client.Touch; import com.google.gwt.event.dom.client.BlurEvent; import com.google.gwt.event.dom.client.BlurHandler; -import com.google.gwt.event.dom.client.ContextMenuEvent; -import com.google.gwt.event.dom.client.ContextMenuHandler; import com.google.gwt.event.dom.client.FocusEvent; import com.google.gwt.event.dom.client.FocusHandler; import com.google.gwt.event.dom.client.KeyCodes; @@ -68,6 +68,8 @@ import com.google.gwt.regexp.shared.RegExp; import com.google.gwt.user.client.Command; import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Event; +import com.google.gwt.user.client.Event.NativePreviewEvent; +import com.google.gwt.user.client.Event.NativePreviewHandler; import com.google.gwt.user.client.Timer; import com.google.gwt.user.client.Window; import com.google.gwt.user.client.ui.FlowPanel; @@ -88,6 +90,7 @@ import com.vaadin.client.UIDL; import com.vaadin.client.Util; import com.vaadin.client.VConsole; import com.vaadin.client.VTooltip; +import com.vaadin.client.WidgetUtil; import com.vaadin.client.ui.VScrollTable.VScrollTableBody.VScrollTableRow; import com.vaadin.client.ui.dd.DDUtil; import com.vaadin.client.ui.dd.VAbstractDropHandler; @@ -128,6 +131,137 @@ public class VScrollTable extends FlowPanel implements HasWidgets, ScrollHandler, VHasDropHandler, FocusHandler, BlurHandler, Focusable, ActionOwner, SubPartAware { + /** + * Simple interface for parts of the table capable of owning a context menu. + * + * @since 7.2 + * @author Vaadin Ltd + */ + private interface ContextMenuOwner { + public void showContextMenu(Event event); + } + + /** + * Handles showing context menu on "long press" from a touch screen. + * + * @since 7.2 + * @author Vaadin Ltd + */ + private class TouchContextProvider { + private static final int TOUCH_CONTEXT_MENU_TIMEOUT = 500; + private Timer contextTouchTimeout; + + private Event touchStart; + private int touchStartY; + private int touchStartX; + + private ContextMenuOwner target; + + /** + * Initializes a handler for a certain context menu owner. + * + * @param target + * the owner of the context menu + */ + public TouchContextProvider(ContextMenuOwner target) { + this.target = target; + } + + /** + * Cancels the current context touch timeout. + */ + public void cancel() { + if (contextTouchTimeout != null) { + contextTouchTimeout.cancel(); + contextTouchTimeout = null; + } + touchStart = null; + } + + /** + * A function to handle touch context events in a table. + * + * @param event + * browser event to handle + */ + public void handleTouchEvent(final Event event) { + int type = event.getTypeInt(); + + switch (type) { + case Event.ONCONTEXTMENU: + target.showContextMenu(event); + break; + case Event.ONTOUCHSTART: + // save position to fields, touches in events are same + // instance during the operation. + touchStart = event; + + Touch touch = event.getChangedTouches().get(0); + touchStartX = touch.getClientX(); + touchStartY = touch.getClientY(); + + if (contextTouchTimeout == null) { + contextTouchTimeout = new Timer() { + + @Override + public void run() { + if (touchStart != null) { + // Open the context menu if finger + // is held in place long enough. + target.showContextMenu(touchStart); + event.preventDefault(); + touchStart = null; + } + } + }; + } + contextTouchTimeout.schedule(TOUCH_CONTEXT_MENU_TIMEOUT); + break; + case Event.ONTOUCHCANCEL: + case Event.ONTOUCHEND: + cancel(); + break; + case Event.ONTOUCHMOVE: + if (isSignificantMove(event)) { + // Moved finger before the context menu timer + // expired, so let the browser handle the event. + cancel(); + } + } + } + + /** + * Calculates how many pixels away the user's finger has traveled. This + * reduces the chance of small non-intentional movements from canceling + * the long press detection. + * + * @param event + * the Event for which to check the move distance + * @return true if this is considered an intentional move by the user + */ + protected boolean isSignificantMove(Event event) { + if (touchStart == null) { + // no touch start + return false; + } + + // Calculate the distance between touch start and the current touch + // position + Touch touch = event.getChangedTouches().get(0); + int deltaX = touch.getClientX() - touchStartX; + int deltaY = touch.getClientY() - touchStartY; + int delta = deltaX * deltaX + deltaY * deltaY; + + // Compare to the square of the significant move threshold to remove + // the need for a square root + if (delta > TouchScrollDelegate.SIGNIFICANT_MOVE_THRESHOLD + * TouchScrollDelegate.SIGNIFICANT_MOVE_THRESHOLD) { + return true; + } + return false; + } + } + public static final String STYLENAME = "v-table"; public enum SelectMode { @@ -195,6 +329,8 @@ public class VScrollTable extends FlowPanel implements HasWidgets, /** For internal use only. May be removed or replaced in the future. */ public boolean immediate; + private boolean updatedReqRows = true; + private boolean nullSelectionAllowed = true; private SelectMode selectMode = SelectMode.NONE; @@ -369,8 +505,49 @@ public class VScrollTable extends FlowPanel implements HasWidgets, /** For internal use only. May be removed or replaced in the future. */ public final TableFooter tFoot = new TableFooter(); + /** Handles context menu for table body */ + private ContextMenuOwner contextMenuOwner = new ContextMenuOwner() { + + @Override + public void showContextMenu(Event event) { + int left = WidgetUtil.getTouchOrMouseClientX(event); + int top = WidgetUtil.getTouchOrMouseClientY(event); + boolean menuShown = handleBodyContextMenu(left, top); + if (menuShown) { + event.stopPropagation(); + event.preventDefault(); + } + } + }; + + /** Handles touch events to display a context menu for table body */ + private TouchContextProvider touchContextProvider = new TouchContextProvider( + contextMenuOwner); + + /** + * For internal use only. May be removed or replaced in the future. + * + * Overwrites onBrowserEvent function on FocusableScrollPanel to give event + * access to touchContextProvider. Has to be public to give TableConnector + * access to the scrollBodyPanel field. + * + * @since 7.2 + * @author Vaadin Ltd + */ + public class FocusableScrollContextPanel extends FocusableScrollPanel { + @Override + public void onBrowserEvent(Event event) { + super.onBrowserEvent(event); + touchContextProvider.handleTouchEvent(event); + }; + + public FocusableScrollContextPanel(boolean useFakeFocusElement) { + super(useFakeFocusElement); + } + } + /** For internal use only. May be removed or replaced in the future. */ - public final FocusableScrollPanel scrollBodyPanel = new FocusableScrollPanel( + public final FocusableScrollContextPanel scrollBodyPanel = new FocusableScrollContextPanel( true); private KeyPressHandler navKeyPressHandler = new KeyPressHandler() { @@ -590,6 +767,51 @@ public class VScrollTable extends FlowPanel implements HasWidgets, private HandlerRegistration addCloseHandler; + /** + * Changes to manage mouseDown and mouseUp + */ + /** + * The element where the last mouse down event was registered. + */ + private Element lastMouseDownTarget; + + /** + * Set to true by {@link #mouseUpPreviewHandler} if it gets a mouseup at the + * same element as {@link #lastMouseDownTarget}. + */ + private boolean mouseUpPreviewMatched = false; + + private HandlerRegistration mouseUpEventPreviewRegistration; + + /** + * Previews events after a mousedown to detect where the following mouseup + * hits. + */ + private final NativePreviewHandler mouseUpPreviewHandler = new NativePreviewHandler() { + + @Override + public void onPreviewNativeEvent(NativePreviewEvent event) { + if (event.getTypeInt() == Event.ONMOUSEUP) { + mouseUpEventPreviewRegistration.removeHandler(); + + // Event's reported target not always correct if event + // capture is in use + Element elementUnderMouse = WidgetUtil + .getElementUnderMouse(event.getNativeEvent()); + if (lastMouseDownTarget != null + && lastMouseDownTarget.isOrHasChild(elementUnderMouse)) { + mouseUpPreviewMatched = true; + } else { + getLogger().log( + Level.FINEST, + "Ignoring mouseup from " + elementUnderMouse + + " when mousedown was on " + + lastMouseDownTarget); + } + } + } + }; + public VScrollTable() { setMultiSelectMode(MULTISELECT_MODE_DEFAULT); @@ -610,16 +832,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets, } scrollBodyPanel.addKeyUpHandler(navKeyUpHandler); - scrollBodyPanel.sinkEvents(Event.TOUCHEVENTS); - - scrollBodyPanel.sinkEvents(Event.ONCONTEXTMENU); - scrollBodyPanel.addDomHandler(new ContextMenuHandler() { - - @Override - public void onContextMenu(ContextMenuEvent event) { - handleBodyContextMenu(event); - } - }, ContextMenuEvent.getType()); + scrollBodyPanel.sinkEvents(Event.TOUCHEVENTS | Event.ONCONTEXTMENU); setStyleName(STYLENAME); @@ -681,19 +894,23 @@ public class VScrollTable extends FlowPanel implements HasWidgets, }); } - private void handleBodyContextMenu(ContextMenuEvent event) { + /** + * Handles a context menu event on table body. + * + * @param left + * left position of the context menu + * @param top + * top position of the context menu + * @return true if a context menu was shown, otherwise false + */ + private boolean handleBodyContextMenu(int left, int top) { if (enabled && bodyActionKeys != null) { - int left = Util.getTouchOrMouseClientX(event.getNativeEvent()); - int top = Util.getTouchOrMouseClientY(event.getNativeEvent()); top += Window.getScrollTop(); left += Window.getScrollLeft(); client.getContextMenu().showAt(this, left, top); - - // Only prevent browser context menu if there are action handlers - // registered - event.stopPropagation(); - event.preventDefault(); + return true; } + return false; } /** @@ -838,6 +1055,11 @@ public class VScrollTable extends FlowPanel implements HasWidgets, sendSelectedRows(immediate); } + private void updateFirstVisibleAndSendSelectedRows() { + updateFirstVisibleRow(); + sendSelectedRows(immediate); + } + /** * Sends the selection to the server if it has been changed since the last * update/visit. @@ -1002,7 +1224,12 @@ public class VScrollTable extends FlowPanel implements HasWidgets, // Without this call the scroll position is messed up in IE even after // the lazy scroller has set the scroll position to the first visible // item - scrollBodyPanel.getScrollPosition(); + int pos = scrollBodyPanel.getScrollPosition(); + + // Reset first row in view port so client requests correct last row. + if (pos == 0) { + firstRowInViewPort = 0; + } scrollBody = createScrollBody(); @@ -1085,25 +1312,14 @@ public class VScrollTable extends FlowPanel implements HasWidgets, selected = true; keyboardSelectionOverRowFetchInProgress = true; } - if (selected) { - - if (focusedRow == null - || !selectedRowKeys.contains(focusedRow - .getKey())) { - /* - * The focus is no longer on a selected row. Move - * focus to the selected row. (#10522) - * - * Don't do this for multiselect (#13341). - * - * Checking the selection mode here instead of in - * setRowFocus allows keyboard shift+downarrow - * selection to work as expected. - */ - - setRowFocus(row); - } + if (selected && selectedKeys.size() == 1) { + /* + * If a single item is selected, move focus to the + * selected row. (#10522) + */ + setRowFocus(row); } + if (selected != row.isSelected()) { row.toggleSelection(); @@ -1183,7 +1399,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets, @Override public void execute() { - if (firstvisible > 0) { + if (firstvisible >= 0) { firstRowInViewPort = firstvisible; if (firstvisibleOnLastPage > -1) { scrollBodyPanel @@ -1992,6 +2208,8 @@ public class VScrollTable extends FlowPanel implements HasWidgets, final FooterCell fCell = (FooterCell) footCells.next(); boolean needsIndent = hierarchyColumnIndent > 0 && hCell.isHierarchyColumn(); + hCell.saveNaturalColumnWidthIfNotSaved(i); + fCell.saveNaturalColumnWidthIfNotSaved(i); int w = hCell.getWidth(); if (hCell.isDefinedWidth()) { // server has defined column width explicitly @@ -2017,8 +2235,10 @@ public class VScrollTable extends FlowPanel implements HasWidgets, int footerWidth = fCell.getNaturalColumnWidth(i); w = headerWidth > footerWidth ? headerWidth : footerWidth; } - hCell.setNaturalMinimumColumnWidth(w); - fCell.setNaturalMinimumColumnWidth(w); + if (w != 0) { + hCell.setNaturalMinimumColumnWidth(w); + fCell.setNaturalMinimumColumnWidth(w); + } } widths[i] = w; total += w; @@ -2038,7 +2258,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets, int w = total; w += scrollBody.getCellExtraWidth() * visibleColOrder.length; if (willHaveScrollbarz) { - w += Util.getNativeScrollbarSize(); + w += WidgetUtil.getNativeScrollbarSize(); } setContentWidth(w); } @@ -2051,7 +2271,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets, availW -= scrollBody.getCellExtraWidth() * visibleColOrder.length; if (willHaveScrollbarz) { - availW -= Util.getNativeScrollbarSize(); + availW -= WidgetUtil.getNativeScrollbarSize(); } // TODO refactor this code to be the same as in resize timer @@ -2223,10 +2443,10 @@ public class VScrollTable extends FlowPanel implements HasWidgets, } boolean needsSpaceForHorizontalSrollbar = (total > availW); if (needsSpaceForHorizontalSrollbar) { - bodyHeight += Util.getNativeScrollbarSize(); + bodyHeight += WidgetUtil.getNativeScrollbarSize(); } scrollBodyPanel.setHeight(bodyHeight + "px"); - Util.runWebkitOverflowAutoFix(scrollBodyPanel.getElement()); + WidgetUtil.runWebkitOverflowAutoFix(scrollBodyPanel.getElement()); } isNewBody = false; @@ -2257,7 +2477,8 @@ public class VScrollTable extends FlowPanel implements HasWidgets, * Ensures the column alignments are correct at initial loading. <br/> * (child components widths are correct) */ - Util.runWebkitOverflowAutoFixDeferred(scrollBodyPanel.getElement()); + WidgetUtil.runWebkitOverflowAutoFixDeferred(scrollBodyPanel + .getElement()); hadScrollBars = willHaveScrollbarz; } @@ -2394,10 +2615,33 @@ public class VScrollTable extends FlowPanel implements HasWidgets, @Override public void run() { + if (client.hasActiveRequest() || navKeyDown) { // if client connection is busy, don't bother loading it more VConsole.log("Postponed rowfetch"); schedule(250); + } else if (allRenderedRowsAreNew() && !updatedReqRows) { + + /* + * If all rows are new, there might have been a server-side call + * to Table.setCurrentPageFirstItemIndex(int) In this case, + * scrolling event takes way too late, and all the rows from + * previous viewport to this one were requested. + * + * This should prevent requesting unneeded rows by updating + * reqFirstRow and reqRows before needing them. See (#14135) + */ + + setReqFirstRow((firstRowInViewPort - (int) (pageLength * cache_rate))); + int last = firstRowInViewPort + (int) (cache_rate * pageLength) + + pageLength - 1; + if (last >= totalRows) { + last = totalRows - 1; + } + setReqRows(last - getReqFirstRow() + 1); + updatedReqRows = true; + schedule(250); + } else { int firstRendered = scrollBody.getFirstRendered(); @@ -2485,6 +2729,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets, client.updateVariable(paintableId, "firstvisible", firstRowInViewPort, false); } + client.updateVariable(paintableId, "reqfirstrow", reqFirstRow, false); client.updateVariable(paintableId, "reqrows", reqRows, true); @@ -2715,6 +2960,10 @@ public class VScrollTable extends FlowPanel implements HasWidgets, } } + private void setUndefinedWidthFlagOnly() { + definedWidth = false; + } + /** * Detects if width is fixed by developer on server side or resized to * current width by user. @@ -2888,7 +3137,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets, case Event.ONTOUCHSTART: case Event.ONMOUSEDOWN: if (columnReordering - && Util.isTouchEventOrLeftMouseButton(event)) { + && WidgetUtil.isTouchEventOrLeftMouseButton(event)) { if (event.getTypeInt() == Event.ONTOUCHSTART) { /* * prevent using this event in e.g. scrolling @@ -2908,9 +3157,18 @@ public class VScrollTable extends FlowPanel implements HasWidgets, case Event.ONTOUCHEND: case Event.ONTOUCHCANCEL: if (columnReordering - && Util.isTouchEventOrLeftMouseButton(event)) { + && WidgetUtil.isTouchEventOrLeftMouseButton(event)) { dragging = false; DOM.releaseCapture(getElement()); + + if (WidgetUtil.isTouchEvent(event)) { + /* + * Prevent using in e.g. scrolling and prevent generated + * events. + */ + event.preventDefault(); + event.stopPropagation(); + } if (moved) { hideFloatingCopy(); tHead.removeSlotFocus(); @@ -2922,20 +3180,15 @@ public class VScrollTable extends FlowPanel implements HasWidgets, reOrderColumn(cid, closestSlot); } } - } - if (Util.isTouchEvent(event)) { - /* - * Prevent using in e.g. scrolling and prevent generated - * events. - */ - event.preventDefault(); - event.stopPropagation(); + moved = false; + break; } } if (!moved) { // mouse event was a click to header -> sort column - if (sortable && Util.isTouchEventOrLeftMouseButton(event)) { + if (sortable + && WidgetUtil.isTouchEventOrLeftMouseButton(event)) { if (sortColumn.equals(cid)) { // just toggle order client.updateVariable(paintableId, "sortascending", @@ -2957,7 +3210,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets, rowRequestHandler.run(); // run immediately } fireHeaderClickedEvent(event); - if (Util.isTouchEvent(event)) { + if (WidgetUtil.isTouchEvent(event)) { /* * Prevent using in e.g. scrolling and prevent generated * events. @@ -2973,7 +3226,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets, break; case Event.ONTOUCHMOVE: case Event.ONMOUSEMOVE: - if (dragging && Util.isTouchEventOrLeftMouseButton(event)) { + if (dragging && WidgetUtil.isTouchEventOrLeftMouseButton(event)) { if (event.getTypeInt() == Event.ONTOUCHMOVE) { /* * prevent using this event in e.g. scrolling @@ -2985,7 +3238,8 @@ public class VScrollTable extends FlowPanel implements HasWidgets, moved = true; } - final int clientX = Util.getTouchOrMouseClientX(event); + final int clientX = WidgetUtil + .getTouchOrMouseClientX(event); final int x = clientX + tHead.hTableWrapper.getScrollLeft(); int slotX = headerX; closestSlot = colIndex; @@ -3023,7 +3277,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets, private void onResizeEvent(Event event) { switch (DOM.eventGetType(event)) { case Event.ONMOUSEDOWN: - if (!Util.isTouchEventOrLeftMouseButton(event)) { + if (!WidgetUtil.isTouchEventOrLeftMouseButton(event)) { return; } isResizing = true; @@ -3034,7 +3288,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets, DOM.eventPreventDefault(event); break; case Event.ONMOUSEUP: - if (!Util.isTouchEventOrLeftMouseButton(event)) { + if (!WidgetUtil.isTouchEventOrLeftMouseButton(event)) { return; } isResizing = false; @@ -3051,7 +3305,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets, fireColumnResizeEvent(cid, originalWidth, getColWidth(cid)); break; case Event.ONMOUSEMOVE: - if (!Util.isTouchEventOrLeftMouseButton(event)) { + if (!WidgetUtil.isTouchEventOrLeftMouseButton(event)) { return; } if (isResizing) { @@ -3129,6 +3383,34 @@ public class VScrollTable extends FlowPanel implements HasWidgets, } /** + * Saves natural column width if it hasn't been saved already. + * + * @param columnIndex + * @since 7.3.9 + */ + protected void saveNaturalColumnWidthIfNotSaved(int columnIndex) { + if (naturalWidth < 0) { + // This is recently revealed column. Try to detect a proper + // value (greater of header and data columns) + + int hw = captionContainer.getOffsetWidth() + getHeaderPadding(); + if (BrowserInfo.get().isGecko()) { + hw += sortIndicator.getOffsetWidth(); + } + if (columnIndex < 0) { + columnIndex = 0; + for (Iterator<Widget> it = tHead.iterator(); it.hasNext(); columnIndex++) { + if (it.next() == this) { + break; + } + } + } + final int cw = scrollBody.getColWidth(columnIndex); + naturalWidth = (hw > cw ? hw : cw); + } + } + + /** * Detects the natural minimum width for the column of this header cell. * If column is resized by user or the width is defined by server the * actual width is returned. Else the natural min width is returned. @@ -3141,33 +3423,13 @@ public class VScrollTable extends FlowPanel implements HasWidgets, public int getNaturalColumnWidth(int columnIndex) { final int iw = columnIndex == getHierarchyColumnIndex() ? scrollBody .getMaxIndent() : 0; + saveNaturalColumnWidthIfNotSaved(columnIndex); if (isDefinedWidth()) { if (iw > width) { return iw; } return width; } else { - if (naturalWidth < 0) { - // This is recently revealed column. Try to detect a proper - // value (greater of header and data columns) - - int hw = captionContainer.getOffsetWidth() - + getHeaderPadding(); - if (BrowserInfo.get().isGecko()) { - hw += sortIndicator.getOffsetWidth(); - } - if (columnIndex < 0) { - columnIndex = 0; - for (Iterator<Widget> it = tHead.iterator(); it - .hasNext(); columnIndex++) { - if (it.next() == this) { - break; - } - } - } - final int cw = scrollBody.getColWidth(columnIndex); - naturalWidth = (hw > cw ? hw : cw); - } if (iw > naturalWidth) { // indent is temporary value, naturalWidth shouldn't be // updated @@ -3354,9 +3616,9 @@ public class VScrollTable extends FlowPanel implements HasWidgets, c.setText(caption); } + c.setSorted(false); if (col.hasAttribute("sortable")) { c.setSortable(true); - c.setSorted(false); } else { c.setSortable(false); } @@ -3404,7 +3666,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets, } } else if (col.hasAttribute("er")) { c.setExpandRatio(col.getFloatAttribute("er")); - + c.setUndefinedWidthFlagOnly(); } else if (recalcWidths) { c.setUndefinedWidth(); @@ -3978,7 +4240,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets, } /** - * Returns the expand ration of the cell + * Returns the expand ratio of the cell * * @return The expand ratio */ @@ -4063,6 +4325,32 @@ public class VScrollTable extends FlowPanel implements HasWidgets, } /** + * Saves natural column width if it hasn't been saved already. + * + * @param columnIndex + * @since 7.3.9 + */ + protected void saveNaturalColumnWidthIfNotSaved(int columnIndex) { + if (naturalWidth < 0) { + // This is recently revealed column. Try to detect a proper + // value (greater of header and data cols) + + final int hw = ((Element) getElement().getLastChild()) + .getOffsetWidth() + getHeaderPadding(); + if (columnIndex < 0) { + columnIndex = 0; + for (Iterator<Widget> it = tHead.iterator(); it.hasNext(); columnIndex++) { + if (it.next() == this) { + break; + } + } + } + final int cw = scrollBody.getColWidth(columnIndex); + naturalWidth = (hw > cw ? hw : cw); + } + } + + /** * Detects the natural minimum width for the column of this header cell. * If column is resized by user or the width is defined by server the * actual width is returned. Else the natural min width is returned. @@ -4075,31 +4363,13 @@ public class VScrollTable extends FlowPanel implements HasWidgets, public int getNaturalColumnWidth(int columnIndex) { final int iw = columnIndex == getHierarchyColumnIndex() ? scrollBody .getMaxIndent() : 0; + saveNaturalColumnWidthIfNotSaved(columnIndex); if (isDefinedWidth()) { if (iw > width) { return iw; } return width; } else { - if (naturalWidth < 0) { - // This is recently revealed column. Try to detect a proper - // value (greater of header and data - // cols) - - final int hw = ((Element) getElement().getLastChild()) - .getOffsetWidth() + getHeaderPadding(); - if (columnIndex < 0) { - columnIndex = 0; - for (Iterator<Widget> it = tHead.iterator(); it - .hasNext(); columnIndex++) { - if (it.next() == this) { - break; - } - } - } - final int cw = scrollBody.getColWidth(columnIndex); - naturalWidth = (hw > cw ? hw : cw); - } if (iw > naturalWidth) { return iw; } else { @@ -4466,10 +4736,12 @@ public class VScrollTable extends FlowPanel implements HasWidgets, } public int getLastRendered() { + return lastRendered; } public int getFirstRendered() { + return firstRendered; } @@ -4487,7 +4759,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets, */ public int getRequiredHeight() { return preSpacer.getOffsetHeight() + postSpacer.getOffsetHeight() - + Util.getRequiredHeight(table); + + WidgetUtil.getRequiredHeight(table); } private void constructDOM() { @@ -4553,10 +4825,12 @@ public class VScrollTable extends FlowPanel implements HasWidgets, } else if (firstIndex + rows == firstRendered) { final VScrollTableRow[] rowArray = new VScrollTableRow[rows]; int i = rows; + while (it.hasNext()) { i--; rowArray[i] = prepareRow((UIDL) it.next()); } + for (i = 0; i < rows; i++) { addRowBeforeFirstRendered(rowArray[i]); firstRendered--; @@ -4581,10 +4855,12 @@ public class VScrollTable extends FlowPanel implements HasWidgets, setLastRendered(lastRendered + 1); setContainerHeight(); fixSpacers(); + while (it.hasNext()) { addRow(prepareRow((UIDL) it.next())); setLastRendered(lastRendered + 1); } + fixSpacers(); } @@ -4599,6 +4875,14 @@ public class VScrollTable extends FlowPanel implements HasWidgets, * has changed since the last request. */ protected void ensureCacheFilled() { + + /** + * Fixes cache issue #13576 where unnecessary rows are fetched + */ + if (isLazyScrollerActive()) { + return; + } + int reactFirstRow = (int) (firstRowInViewPort - pageLength * cache_react_rate); int reactLastRow = (int) (firstRowInViewPort + pageLength + pageLength @@ -5118,7 +5402,8 @@ public class VScrollTable extends FlowPanel implements HasWidgets, return -1; } - public class VScrollTableRow extends Panel implements ActionOwner { + public class VScrollTableRow extends Panel implements ActionOwner, + ContextMenuOwner { private static final int TOUCHSCROLL_TIMEOUT = 100; private static final int DRAGMODE_MULTIROW = 2; @@ -5136,10 +5421,15 @@ public class VScrollTable extends FlowPanel implements HasWidgets, private Timer dragTouchTimeout; private int touchStartY; private int touchStartX; + + private TouchContextProvider touchContextProvider = new TouchContextProvider( + this); + private TooltipInfo tooltipInfo = null; private Map<TableCellElement, TooltipInfo> cellToolTips = new HashMap<TableCellElement, TooltipInfo>(); private boolean isDragging = false; private String rowStyle = null; + protected boolean applyZeroWidthFix = true; private VScrollTableRow(int rowKey) { this.rowKey = rowKey; @@ -5245,7 +5535,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets, * definition of zero width table cells. Instead, use 1px * and compensate with a negative margin. */ - if (width == 0) { + if (applyZeroWidthFix && width == 0) { wrapperWidth = 1; wrapperStyle.setMarginRight(-1, Unit.PX); } else { @@ -5591,6 +5881,8 @@ public class VScrollTable extends FlowPanel implements HasWidgets, boolean touchEventHandled = false; if (enabled && hasNativeTouchScrolling) { + touchContextProvider.handleTouchEvent(event); + final Element targetTdOrTr = getEventTargetTdOrTr(event); final int type = event.getTypeInt(); @@ -5681,8 +5973,8 @@ public class VScrollTable extends FlowPanel implements HasWidgets, if (!BrowserInfo.get().isAndroid()) { event.preventDefault(); event.stopPropagation(); - Util.simulateClickFromTouchEvent(touchStart, - this); + WidgetUtil.simulateClickFromTouchEvent( + touchStart, this); } touchStart = null; } @@ -5732,114 +6024,134 @@ public class VScrollTable extends FlowPanel implements HasWidgets, } break; case Event.ONMOUSEUP: - if (targetCellOrRowFound) { - /* - * Queue here, send at the same time as the - * corresponding value change event - see #7127 - */ - boolean clickEventSent = handleClickEvent(event, - targetTdOrTr, false); - - if (event.getButton() == Event.BUTTON_LEFT - && isSelectable()) { - - // Ctrl+Shift click - if ((event.getCtrlKey() || event.getMetaKey()) - && event.getShiftKey() - && isMultiSelectModeDefault()) { - toggleShiftSelection(false); - setRowFocus(this); - - // Ctrl click - } else if ((event.getCtrlKey() || event - .getMetaKey()) - && isMultiSelectModeDefault()) { - boolean wasSelected = isSelected(); - toggleSelection(); - setRowFocus(this); - /* - * next possible range select must start on - * this row - */ - selectionRangeStart = this; - if (wasSelected) { - removeRowFromUnsentSelectionRanges(this); - } + /* + * Only fire a click if the mouseup hits the same + * element as the corresponding mousedown. This is first + * checked in the event preview but we can't fire the + * event there as the event might get canceled before it + * gets here. + */ + if (mouseUpPreviewMatched + && lastMouseDownTarget != null + && lastMouseDownTarget == getElementTdOrTr(WidgetUtil + .getElementUnderMouse(event))) { + // "Click" with left, right or middle button + + if (targetCellOrRowFound) { + /* + * Queue here, send at the same time as the + * corresponding value change event - see #7127 + */ + boolean clickEventSent = handleClickEvent( + event, targetTdOrTr, false); + + if (event.getButton() == Event.BUTTON_LEFT + && isSelectable()) { + + // Ctrl+Shift click + if ((event.getCtrlKey() || event + .getMetaKey()) + && event.getShiftKey() + && isMultiSelectModeDefault()) { + toggleShiftSelection(false); + setRowFocus(this); - } else if ((event.getCtrlKey() || event - .getMetaKey()) && isSingleSelectMode()) { - // Ctrl (or meta) click (Single selection) - if (!isSelected() - || (isSelected() && nullSelectionAllowed)) { + // Ctrl click + } else if ((event.getCtrlKey() || event + .getMetaKey()) + && isMultiSelectModeDefault()) { + boolean wasSelected = isSelected(); + toggleSelection(); + setRowFocus(this); + /* + * next possible range select must start + * on this row + */ + selectionRangeStart = this; + if (wasSelected) { + removeRowFromUnsentSelectionRanges(this); + } - if (!isSelected()) { - deselectAll(); + } else if ((event.getCtrlKey() || event + .getMetaKey()) + && isSingleSelectMode()) { + // Ctrl (or meta) click (Single + // selection) + if (!isSelected() + || (isSelected() && nullSelectionAllowed)) { + + if (!isSelected()) { + deselectAll(); + } + + toggleSelection(); + setRowFocus(this); } - toggleSelection(); + } else if (event.getShiftKey() + && isMultiSelectModeDefault()) { + // Shift click + toggleShiftSelection(true); + + } else { + // click + boolean currentlyJustThisRowSelected = selectedRowKeys + .size() == 1 + && selectedRowKeys + .contains(getKey()); + + if (!currentlyJustThisRowSelected) { + if (isSingleSelectMode() + || isMultiSelectModeDefault()) { + /* + * For default multi select mode + * (ctrl/shift) and for single + * select mode we need to clear + * the previous selection before + * selecting a new one when the + * user clicks on a row. Only in + * multiselect/simple mode the + * old selection should remain + * after a normal click. + */ + deselectAll(); + } + toggleSelection(); + } else if ((isSingleSelectMode() || isMultiSelectModeSimple()) + && nullSelectionAllowed) { + toggleSelection(); + }/* + * else NOP to avoid excessive server + * visits (selection is removed with + * CTRL/META click) + */ + + selectionRangeStart = this; setRowFocus(this); } - } else if (event.getShiftKey() - && isMultiSelectModeDefault()) { - // Shift click - toggleShiftSelection(true); - - } else { - // click - boolean currentlyJustThisRowSelected = selectedRowKeys - .size() == 1 - && selectedRowKeys - .contains(getKey()); - - if (!currentlyJustThisRowSelected) { - if (isSingleSelectMode() - || isMultiSelectModeDefault()) { - /* - * For default multi select mode - * (ctrl/shift) and for single - * select mode we need to clear the - * previous selection before - * selecting a new one when the user - * clicks on a row. Only in - * multiselect/simple mode the old - * selection should remain after a - * normal click. - */ - deselectAll(); - } - toggleSelection(); - } else if ((isSingleSelectMode() || isMultiSelectModeSimple()) - && nullSelectionAllowed) { - toggleSelection(); - }/* - * else NOP to avoid excessive server - * visits (selection is removed with - * CTRL/META click) - */ - - selectionRangeStart = this; - setRowFocus(this); + // Remove IE text selection hack + if (BrowserInfo.get().isIE()) { + ((Element) event.getEventTarget() + .cast()).setPropertyJSO( + "onselectstart", null); + } + // Queue value change + sendSelectedRows(false); } - - // Remove IE text selection hack - if (BrowserInfo.get().isIE()) { - ((Element) event.getEventTarget().cast()) - .setPropertyJSO("onselectstart", - null); + /* + * Send queued click and value change events if + * any If a click event is sent, send value + * change with it regardless of the immediate + * flag, see #7127 + */ + if (immediate || clickEventSent) { + client.sendPendingVariableChanges(); } - // Queue value change - sendSelectedRows(false); - } - /* - * Send queued click and value change events if any - * If a click event is sent, send value change with - * it regardless of the immediate flag, see #7127 - */ - if (immediate || clickEventSent) { - client.sendPendingVariableChanges(); } } + mouseUpPreviewMatched = false; + lastMouseDownTarget = null; break; case Event.ONTOUCHEND: case Event.ONTOUCHCANCEL: @@ -5848,12 +6160,11 @@ public class VScrollTable extends FlowPanel implements HasWidgets, * Touch has not been handled as neither context or * drag start, handle it as a click. */ - Util.simulateClickFromTouchEvent(touchStart, this); + WidgetUtil.simulateClickFromTouchEvent(touchStart, + this); touchStart = null; } - if (contextTouchTimeout != null) { - contextTouchTimeout.cancel(); - } + touchContextProvider.cancel(); break; case Event.ONTOUCHMOVE: if (isSignificantMove(event)) { @@ -5868,9 +6179,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets, .getActiveScrollDelegate() == null)) { startRowDrag(touchStart, type, targetTdOrTr); } - if (contextTouchTimeout != null) { - contextTouchTimeout.cancel(); - } + touchContextProvider.cancel(); /* * Avoid clicks and drags by clearing touch start * flag. @@ -5883,7 +6192,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets, touchStart = event; Touch touch = event.getChangedTouches().get(0); // save position to fields, touches in events are same - // isntance during the operation. + // instance during the operation. touchStartX = touch.getClientX(); touchStartY = touch.getClientY(); /* @@ -5949,6 +6258,17 @@ public class VScrollTable extends FlowPanel implements HasWidgets, } break; case Event.ONMOUSEDOWN: + /* + * When getting a mousedown event, we must detect where + * the corresponding mouseup event if it's on a + * different part of the page. + */ + lastMouseDownTarget = getElementTdOrTr(WidgetUtil + .getElementUnderMouse(event)); + mouseUpPreviewMatched = false; + mouseUpEventPreviewRegistration = Event + .addNativePreviewHandler(mouseUpPreviewHandler); + if (targetCellOrRowFound) { setRowFocus(this); ensureFocus(); @@ -6083,7 +6403,12 @@ public class VScrollTable extends FlowPanel implements HasWidgets, */ private Element getEventTargetTdOrTr(Event event) { final Element eventTarget = event.getEventTarget().cast(); - Widget widget = Util.findWidget(eventTarget, null); + return getElementTdOrTr(eventTarget); + } + + private Element getElementTdOrTr(Element element) { + + Widget widget = WidgetUtil.findWidget(element, null); if (widget != this) { /* @@ -6103,15 +6428,16 @@ public class VScrollTable extends FlowPanel implements HasWidgets, return null; } } - return getTdOrTr(eventTarget); + return getTdOrTr(element); } + @Override public void showContextMenu(Event event) { if (enabled && actionKeys != null) { // Show context menu if there are registered action handlers - int left = Util.getTouchOrMouseClientX(event) + int left = WidgetUtil.getTouchOrMouseClientX(event) + Window.getScrollLeft(); - int top = Util.getTouchOrMouseClientY(event) + int top = WidgetUtil.getTouchOrMouseClientY(event) + Window.getScrollTop(); showContextMenu(left, top); } @@ -6172,9 +6498,9 @@ public class VScrollTable extends FlowPanel implements HasWidgets, VScrollTableRow startRow = selectionRangeStart; if (startRow == null) { startRow = focusedRow; + selectionRangeStart = focusedRow; // If start row is null then we have a multipage selection - // from - // above + // from above if (startRow == null) { startRow = (VScrollTableRow) scrollBody.iterator() .next(); @@ -6390,8 +6716,9 @@ public class VScrollTable extends FlowPanel implements HasWidgets, .getVisibleCellCount(); ix++) { spanWidth += tHead.getHeaderCell(ix).getOffsetWidth(); } - Util.setWidthExcludingPaddingAndBorder((Element) getElement() - .getChild(cellIx), spanWidth, 13, false); + WidgetUtil.setWidthExcludingPaddingAndBorder( + (Element) getElement().getChild(cellIx), spanWidth, 13, + false); } } @@ -6565,6 +6892,14 @@ public class VScrollTable extends FlowPanel implements HasWidgets, // natural width already includes indent if any int naturalColumnWidth = hCell .getNaturalColumnWidth(colIndex); + /* + * TODO If there is extra width, expand ratios are for + * additional extra widths, not for absolute column widths. + * Should be fixed in sizeInit(), too. + */ + if (hCell.getExpandRatio() > 0) { + naturalColumnWidth = 0; + } usedMinimumWidth += naturalColumnWidth; expandRatioDivider += hCell.getExpandRatio(); if (hasIndent) { @@ -6581,8 +6916,17 @@ public class VScrollTable extends FlowPanel implements HasWidgets, int totalExtraWidth = scrollBody.getCellExtraWidth() * visibleCellCount; if (willHaveScrollbars()) { - totalExtraWidth += Util.getNativeScrollbarSize(); + totalExtraWidth += WidgetUtil.getNativeScrollbarSize(); + // if there will be vertical scrollbar, let's enable it + scrollBodyPanel.getElement().getStyle().clearOverflowY(); + } else { + // if there is no need for vertical scrollbar, let's disable it + // this is necessary since sometimes the browsers insist showing + // the scrollbar even if the content would fit perfectly + scrollBodyPanel.getElement().getStyle() + .setOverflowY(Overflow.HIDDEN); } + availW -= totalExtraWidth; int forceScrollBodyWidth = -1; @@ -6600,6 +6944,15 @@ public class VScrollTable extends FlowPanel implements HasWidgets, forceScrollBodyWidth = usedMinimumWidth + totalExtraWidth; } extraSpace = 0; + // if there will be horizontal scrollbar, let's enable it + scrollBodyPanel.getElement().getStyle().clearOverflowX(); + } else { + // if there is no need for horizontal scrollbar, let's disable + // it + // this is necessary since sometimes the browsers insist showing + // the scrollbar even if the content would fit perfectly + scrollBodyPanel.getElement().getStyle() + .setOverflowX(Overflow.HIDDEN); } if (forceScrollBodyWidth > 0) { @@ -6651,6 +7004,9 @@ public class VScrollTable extends FlowPanel implements HasWidgets, int newSpace; if (expandRatioDivider > 0) { // divide excess space by expand ratios + if (hCell.getExpandRatio() > 0) { + w = 0; + } newSpace = Math.round((w + extraSpace * hCell.getExpandRatio() / expandRatioDivider)); } else { @@ -6696,7 +7052,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets, colIndex = 0; while (headCells.hasNext()) { HeaderCell hc = (HeaderCell) headCells.next(); - if (!hc.isDefinedWidth()) { + if (!hc.isResizing && !hc.isDefinedWidth()) { setColWidth(colIndex, hc.getWidthWithIndent() + availW - checksum, false); break; @@ -6711,7 +7067,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets, int bodyHeight = scrollBody.getRequiredHeight(); boolean needsSpaceForHorizontalScrollbar = (availW < usedMinimumWidth); if (needsSpaceForHorizontalScrollbar) { - bodyHeight += Util.getNativeScrollbarSize(); + bodyHeight += WidgetUtil.getNativeScrollbarSize(); } int heightBefore = getOffsetHeight(); scrollBodyPanel.setHeight(bodyHeight + "px"); @@ -6721,8 +7077,6 @@ public class VScrollTable extends FlowPanel implements HasWidgets, } } - Util.runWebkitOverflowAutoFixDeferred(scrollBodyPanel.getElement()); - forceRealignColumnHeaders(); } @@ -6758,7 +7112,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets, */ private int getBorderWidth() { if (borderWidth < 0) { - borderWidth = Util.measureHorizontalPaddingAndBorder( + borderWidth = WidgetUtil.measureHorizontalPaddingAndBorder( scrollBodyPanel.getElement(), 2); if (borderWidth < 0) { borderWidth = 0; @@ -6851,15 +7205,6 @@ public class VScrollTable extends FlowPanel implements HasWidgets, if (initializedAndAttached) { updatePageLength(); } - if (!rendering) { - // Webkit may sometimes get an odd rendering bug (white space - // between header and body), see bug #3875. Running - // overflow hack here to shake body element a bit. - // We must run the fix as a deferred command to prevent it from - // overwriting the scroll position with an outdated value, see - // #7607. - Util.runWebkitOverflowAutoFixDeferred(scrollBodyPanel.getElement()); - } triggerLazyColumnAdjustment(false); @@ -6914,6 +7259,20 @@ public class VScrollTable extends FlowPanel implements HasWidgets, return s; } + // Updates first visible row for the case we cannot wait + // for onScroll + private void updateFirstVisibleRow() { + scrollTop = scrollBodyPanel.getScrollPosition(); + firstRowInViewPort = calcFirstRowInViewPort(); + int maxFirstRow = totalRows - pageLength; + if (firstRowInViewPort > maxFirstRow && maxFirstRow >= 0) { + firstRowInViewPort = maxFirstRow; + } + lastRequestedFirstvisible = firstRowInViewPort; + client.updateVariable(paintableId, "firstvisible", firstRowInViewPort, + false); + } + /** * This method has logic which rows needs to be requested from server when * user scrolls @@ -7003,8 +7362,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets, return; } - if (firstRowInViewPort - pageLength * cache_rate > lastRendered - || firstRowInViewPort + pageLength + pageLength * cache_rate < firstRendered) { + if (allRenderedRowsAreNew()) { // need a totally new set of rows rowRequestHandler .setReqFirstRow((firstRowInViewPort - (int) (pageLength * cache_rate))); @@ -7015,11 +7373,13 @@ public class VScrollTable extends FlowPanel implements HasWidgets, } rowRequestHandler.setReqRows(last - rowRequestHandler.getReqFirstRow() + 1); + updatedReqRows = false; rowRequestHandler.deferRowFetch(); return; } if (preLimit < firstRendered) { // need some rows to the beginning of the rendered area + rowRequestHandler .setReqFirstRow((int) (firstRowInViewPort - pageLength * cache_rate)); @@ -7037,6 +7397,14 @@ public class VScrollTable extends FlowPanel implements HasWidgets, } } + private boolean allRenderedRowsAreNew() { + int firstRowInViewPort = calcFirstRowInViewPort(); + int firstRendered = scrollBody.getFirstRendered(); + int lastRendered = scrollBody.getLastRendered(); + return (firstRowInViewPort - pageLength * cache_rate > lastRendered || firstRowInViewPort + + pageLength + pageLength * cache_rate < firstRendered); + } + protected int calcFirstRowInViewPort() { return (int) Math.ceil(scrollTop / scrollBody.getRowHeight()); } @@ -7087,7 +7455,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets, Class<? extends Widget> clazz = getRowClass(); VScrollTableRow row = null; if (clazz != null) { - row = Util.findWidget(elementOver, clazz); + row = WidgetUtil.findWidget(elementOver, clazz); } if (row != null) { dropDetails.overkey = row.rowKey; @@ -7240,7 +7608,6 @@ public class VScrollTable extends FlowPanel implements HasWidgets, } if (row != null) { - // Apply focus style to new selection row.addStyleName(getStylePrimaryName() + "-focus"); @@ -7254,12 +7621,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets, // Set new focused row focusedRow = row; - /* - * Don't scroll to the focused row when in multiselect mode. - * (#13341) - */ - - if (isSingleSelectMode()) { + if (hasFocus) { ensureRowIsVisible(row); } @@ -7281,7 +7643,11 @@ public class VScrollTable extends FlowPanel implements HasWidgets, // get odd scrolling here. return; } - Util.scrollIntoViewVertically(row.getElement()); + /* + * FIXME The next line doesn't always do what expected, because if the + * row is not in the DOM it won't scroll to it. + */ + WidgetUtil.scrollIntoViewVertically(row.getElement()); } /** @@ -7375,7 +7741,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets, // focus and select the last visible row setRowFocus(lastVisibleRowInViewPort); selectFocusedRow(ctrl, shift); - sendSelectedRows(); + updateFirstVisibleAndSendSelectedRows(); } else { int indexOfToBeFocused = focusedRow.getIndex() + getFullyVisibleRowCount(); @@ -7392,20 +7758,20 @@ public class VScrollTable extends FlowPanel implements HasWidgets, setRowFocus(toBeFocusedRow); selectFocusedRow(ctrl, shift); // TODO needs scrollintoview ? - sendSelectedRows(); + updateFirstVisibleAndSendSelectedRows(); } else { // scroll down by pixels and return, to wait for // new rows, then select the last item in the // viewport selectLastItemInNextRender = true; multiselectPending = shift; - scrollByPagelenght(1); + scrollByPagelength(1); } } } } else { /* No selections, go page down by scrolling */ - scrollByPagelenght(1); + scrollByPagelength(1); } return true; } @@ -7428,7 +7794,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets, // focus and select the first visible row setRowFocus(firstVisibleRowInViewPort); selectFocusedRow(ctrl, shift); - sendSelectedRows(); + updateFirstVisibleAndSendSelectedRows(); } else { int indexOfToBeFocused = focusedRow.getIndex() - getFullyVisibleRowCount(); @@ -7443,7 +7809,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets, setRowFocus(toBeFocusedRow); selectFocusedRow(ctrl, shift); // TODO needs scrollintoview ? - sendSelectedRows(); + updateFirstVisibleAndSendSelectedRows(); } else { // unless waiting for the next rowset already // scroll down by pixels and return, to wait for @@ -7451,13 +7817,13 @@ public class VScrollTable extends FlowPanel implements HasWidgets, // viewport selectFirstItemInNextRender = true; multiselectPending = shift; - scrollByPagelenght(-1); + scrollByPagelength(-1); } } } } else { /* No selections, go page up by scrolling */ - scrollByPagelenght(-1); + scrollByPagelength(-1); } return true; @@ -7475,7 +7841,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets, if (rowByRowIndex.getIndex() == 0) { setRowFocus(rowByRowIndex); selectFocusedRow(ctrl, shift); - sendSelectedRows(); + updateFirstVisibleAndSendSelectedRows(); } else { // first row of table will come in next row fetch if (ctrl) { @@ -7501,7 +7867,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets, if (focusedRow != rowByRowIndex) { setRowFocus(rowByRowIndex); selectFocusedRow(ctrl, shift); - sendSelectedRows(); + updateFirstVisibleAndSendSelectedRows(); } } else { if (ctrl) { @@ -7531,7 +7897,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets, .getRowHeight()); } - private void scrollByPagelenght(int i) { + private void scrollByPagelength(int i) { int pixels = i * scrollBodyPanel.getOffsetHeight(); int newPixels = scrollBodyPanel.getScrollPosition() + pixels; if (newPixels < 0) { @@ -7582,7 +7948,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets, * ...and sometimes it sends blur events even though the focus * handler is still active. (#10464) */ - Element focusedElement = Util.getIEFocusedElement(); + Element focusedElement = WidgetUtil.getFocusedElement(); if (Util.getConnectorForElement(client, getParent(), focusedElement) == this && focusedElement != null && focusedElement != scrollBodyPanel.getFocusElement()) { @@ -7735,7 +8101,6 @@ public class VScrollTable extends FlowPanel implements HasWidgets, public void lazyRevertFocusToRow(final VScrollTableRow currentlyFocusedRow) { Scheduler.get().scheduleFinally(new ScheduledCommand() { - @Override public void execute() { if (currentlyFocusedRow != null) { @@ -7892,7 +8257,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets, @Override public String getSubPartName(com.google.gwt.user.client.Element subElement) { - Widget widget = Util.findWidget(subElement, null); + Widget widget = WidgetUtil.findWidget(subElement, null); if (widget instanceof HeaderCell) { return SUBPART_HEADER + "[" + tHead.visibleCells.indexOf(widget) + "]"; @@ -7923,11 +8288,15 @@ public class VScrollTable extends FlowPanel implements HasWidgets, } /** - * @since + * @since 7.2.6 */ public void onUnregister() { if (addCloseHandler != null) { addCloseHandler.removeHandler(); } } + + private static Logger getLogger() { + return Logger.getLogger(VScrollTable.class.getName()); + } } diff --git a/ivysettings.xml b/ivysettings.xml index 981ef2006d..e27dd95c12 100644 --- a/ivysettings.xml +++ b/ivysettings.xml @@ -27,6 +27,10 @@ <modules> <module organisation="com.vaadin" name="vaadin-testbench" resolver="vaadin-addons" /> + <module organisation="com.vaadin" name="vaadin-testbench-core" + resolver="vaadin-addons" /> + <module organisation="com.vaadin" name="vaadin-testbench-api" + resolver="vaadin-addons" /> <module organisation="com.vaadin" name="vaadin-buildhelpers" resolver="build-temp" /> <module organisation="com.vaadin" name="vaadin-shared" diff --git a/uitest/integration_tests.xml b/uitest/integration_tests.xml index c0d73580bb..716523eab0 100644 --- a/uitest/integration_tests.xml +++ b/uitest/integration_tests.xml @@ -27,7 +27,9 @@ <!-- Base url where the testable application is deployed --> <property name="deployment.url" value="http://${test.integration.server}:8080" /> - + <!-- TestBench license parameter --> + <property name="vaadin.testbench.developer.license" value="" /> + <property name="report.dir" location="${integration_test.dir}/result/reports-integration" /> <!-- ssh host values --> @@ -124,6 +126,7 @@ <jvmarg value="-Dserver-name=${server-name}" /> <jvmarg value="-Djava.awt.headless=true" /> <jvmarg value="-Ddemo.war=${demo.war}" /> + <jvmarg value="-Dvaadin.testbench.developer.license=${vaadin.testbench.developer.license}" /> <test name="${junit.test.suite}" todir="${server.report.dir}" /> </junit> </target> diff --git a/uitest/ivy.xml b/uitest/ivy.xml index 020543c53f..d33bffaf78 100644 --- a/uitest/ivy.xml +++ b/uitest/ivy.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE ivy-module [ - <!ENTITY jetty.version "8.1.9.v20130131"> + <!ENTITY jetty.version "8.1.12.v20130726"> ]> <ivy-module version="2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" @@ -71,11 +71,17 @@ </dependency> <!-- jetty-servlets needed by ProxyTest, but not by jetty-runner --> <dependency org="org.eclipse.jetty" name="jetty-servlets" - rev="&jetty.version;" conf="ide, build-provided, jetty-run->default" /> + rev="&jetty.version;" conf="ide, build-provided, jetty-run->default" > + <exclude org="org.eclipse.jetty.orbit"></exclude> + </dependency> <dependency org="org.eclipse.jetty" name="jetty-websocket" - rev="&jetty.version;" conf="ide, jetty-run->default" /> + rev="&jetty.version;" conf="ide, jetty-run->default"> + <exclude org="org.eclipse.jetty.orbit"></exclude> + </dependency> <dependency org="org.eclipse.jetty" name="jetty-webapp" - rev="&jetty.version;" conf="ide, build-provided, jetty-run->default" /> + rev="&jetty.version;" conf="ide, build-provided, jetty-run->default"> + <exclude org="org.eclipse.jetty.orbit"></exclude> + </dependency> <dependency org="org.mortbay.jetty" name="jetty-runner" rev="&jetty.version;" conf="ide, jetty-run->default"> <exclude org="org.eclipse.jetty.orbit"></exclude> @@ -95,10 +101,20 @@ <dependency org="org.hsqldb" name="hsqldb" rev="2.2.6" conf="build,ide -> default" /> <dependency org="com.vaadin" name="vaadin-testbench" - rev="4.0.0.alpha1" conf="build-provided,ide -> default" /> + rev="4.0.2" conf="build-provided,ide -> default" /> <!-- This should be removed once tests have been updated to use lang3 --> <dependency org="commons-lang" name="commons-lang" - rev="2.6" conf="build,ide -> default" /> + rev="2.6" conf="build,ide -> default" /> + <!--<dependency org="com.vaadin" name="vaadin-sass-compiler" + rev="${vaadin.sass.version}" conf="compile-theme->default" /> + + <dependency org="com.vaadin" name="vaadin-buildhelpers" + rev="${vaadin.version}" conf="compile-theme->build" /> --> + + <dependency org="org.eclipse.jgit" name="org.eclipse.jgit" + rev="3.5.1.201410131835-r" conf="ide,build->default"> + <exclude org="org.apache.httpcomponents"></exclude> + </dependency> </dependencies> </ivy-module> diff --git a/uitest/src/com/vaadin/tests/VerifyBrowserVersionTest.java b/uitest/src/com/vaadin/tests/VerifyBrowserVersionTest.java index 43d6a55a8b..f2d8ef8a52 100644 --- a/uitest/src/com/vaadin/tests/VerifyBrowserVersionTest.java +++ b/uitest/src/com/vaadin/tests/VerifyBrowserVersionTest.java @@ -1,12 +1,12 @@ /* * Copyright 2000-2014 Vaadin 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 @@ -22,6 +22,7 @@ import org.junit.Assert; import org.junit.Test; import org.openqa.selenium.remote.DesiredCapabilities; +import com.vaadin.testbench.parallel.Browser; import com.vaadin.tests.tb3.MultiBrowserTest; public class VerifyBrowserVersionTest extends MultiBrowserTest { diff --git a/uitest/src/com/vaadin/tests/actions/ActionsOnInvisibleComponentsTest.java b/uitest/src/com/vaadin/tests/actions/ActionsOnInvisibleComponentsTest.java index 8dfcf52b75..d15a5e28ce 100644 --- a/uitest/src/com/vaadin/tests/actions/ActionsOnInvisibleComponentsTest.java +++ b/uitest/src/com/vaadin/tests/actions/ActionsOnInvisibleComponentsTest.java @@ -7,6 +7,7 @@ import org.junit.Test; import org.openqa.selenium.interactions.Actions; import org.openqa.selenium.remote.DesiredCapabilities; +import com.vaadin.testbench.parallel.Browser; import com.vaadin.tests.tb3.MultiBrowserTest; public class ActionsOnInvisibleComponentsTest extends MultiBrowserTest { diff --git a/uitest/src/com/vaadin/tests/applicationservlet/NoApplicationClassTest.java b/uitest/src/com/vaadin/tests/applicationservlet/NoApplicationClassTest.java index 5a815fb40c..014808fe27 100644 --- a/uitest/src/com/vaadin/tests/applicationservlet/NoApplicationClassTest.java +++ b/uitest/src/com/vaadin/tests/applicationservlet/NoApplicationClassTest.java @@ -1,12 +1,12 @@ /* * Copyright 2000-2014 Vaadin 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 @@ -23,6 +23,7 @@ import org.junit.Test; import org.openqa.selenium.By; import org.openqa.selenium.remote.DesiredCapabilities; +import com.vaadin.testbench.parallel.Browser; import com.vaadin.tests.tb3.MultiBrowserTest; public class NoApplicationClassTest extends MultiBrowserTest { diff --git a/uitest/src/com/vaadin/tests/components/AbstractOrderedLayoutWithCaptionsTest.java b/uitest/src/com/vaadin/tests/components/AbstractOrderedLayoutWithCaptionsTest.java index 4f5c16218e..98150e959b 100644 --- a/uitest/src/com/vaadin/tests/components/AbstractOrderedLayoutWithCaptionsTest.java +++ b/uitest/src/com/vaadin/tests/components/AbstractOrderedLayoutWithCaptionsTest.java @@ -1,12 +1,12 @@ /* * Copyright 2000-2014 Vaadin 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 @@ -25,12 +25,13 @@ import org.junit.Test; import org.openqa.selenium.WebElement; import com.vaadin.testbench.By; +import com.vaadin.testbench.parallel.BrowserUtil; import com.vaadin.tests.tb3.MultiBrowserTest; /** * Test to see if AbstractOrderedLayout displays captions correctly with * expanding ratios. - * + * * @author Vaadin Ltd */ public class AbstractOrderedLayoutWithCaptionsTest extends MultiBrowserTest { diff --git a/uitest/src/com/vaadin/tests/components/calendar/CalendarResizeOverlappingEventsTest.java b/uitest/src/com/vaadin/tests/components/calendar/CalendarResizeOverlappingEventsTest.java index f664149cce..bac7d6b401 100644 --- a/uitest/src/com/vaadin/tests/components/calendar/CalendarResizeOverlappingEventsTest.java +++ b/uitest/src/com/vaadin/tests/components/calendar/CalendarResizeOverlappingEventsTest.java @@ -1,12 +1,12 @@ /* * Copyright 2000-2014 Vaadin 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 @@ -26,10 +26,11 @@ import org.openqa.selenium.By; import org.openqa.selenium.WebElement; import org.openqa.selenium.interactions.Actions; +import com.vaadin.testbench.parallel.BrowserUtil; import com.vaadin.tests.tb3.MultiBrowserTest; /** - * + * * @author Vaadin Ltd */ public class CalendarResizeOverlappingEventsTest extends MultiBrowserTest { diff --git a/uitest/src/com/vaadin/tests/components/combobox/ComboBoxSetNullWhenNewItemsAllowedTest.java b/uitest/src/com/vaadin/tests/components/combobox/ComboBoxSetNullWhenNewItemsAllowedTest.java index 7951187fa7..b847ae66d2 100644 --- a/uitest/src/com/vaadin/tests/components/combobox/ComboBoxSetNullWhenNewItemsAllowedTest.java +++ b/uitest/src/com/vaadin/tests/components/combobox/ComboBoxSetNullWhenNewItemsAllowedTest.java @@ -1,12 +1,12 @@ /* * Copyright 2000-2014 Vaadin 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 @@ -25,6 +25,7 @@ import org.openqa.selenium.interactions.Actions; import com.vaadin.testbench.By; import com.vaadin.testbench.commands.TestBenchElementCommands; import com.vaadin.testbench.elements.ComboBoxElement; +import com.vaadin.testbench.parallel.BrowserUtil; import com.vaadin.tests.tb3.MultiBrowserTest; /** diff --git a/uitest/src/com/vaadin/tests/components/datefield/DisabledDateFieldPopupTest.java b/uitest/src/com/vaadin/tests/components/datefield/DisabledDateFieldPopupTest.java index a57017746a..5d299ac12b 100644 --- a/uitest/src/com/vaadin/tests/components/datefield/DisabledDateFieldPopupTest.java +++ b/uitest/src/com/vaadin/tests/components/datefield/DisabledDateFieldPopupTest.java @@ -1,12 +1,12 @@ /* * Copyright 2000-2014 Vaadin 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 @@ -27,6 +27,7 @@ import org.openqa.selenium.WebElement; import org.openqa.selenium.interactions.Actions; import org.openqa.selenium.remote.DesiredCapabilities; +import com.vaadin.testbench.parallel.BrowserUtil; import com.vaadin.tests.tb3.MultiBrowserTest; public class DisabledDateFieldPopupTest extends MultiBrowserTest { diff --git a/uitest/src/com/vaadin/tests/components/javascriptcomponent/JavaScriptPreloadingTest.java b/uitest/src/com/vaadin/tests/components/javascriptcomponent/JavaScriptPreloadingTest.java index a9e7a1bca7..e34c5a3398 100644 --- a/uitest/src/com/vaadin/tests/components/javascriptcomponent/JavaScriptPreloadingTest.java +++ b/uitest/src/com/vaadin/tests/components/javascriptcomponent/JavaScriptPreloadingTest.java @@ -1,12 +1,12 @@ /* * Copyright 2000-2014 Vaadin 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 @@ -27,10 +27,11 @@ import org.openqa.selenium.remote.DesiredCapabilities; import org.openqa.selenium.support.ui.ExpectedConditions; import org.openqa.selenium.support.ui.WebDriverWait; +import com.vaadin.testbench.parallel.Browser; import com.vaadin.tests.tb3.MultiBrowserTest; /** - * + * * @since * @author Vaadin Ltd */ @@ -38,7 +39,7 @@ public class JavaScriptPreloadingTest extends MultiBrowserTest { /* * (non-Javadoc) - * + * * @see com.vaadin.tests.tb3.MultiBrowserTest#getBrowsersToTest() */ @Override diff --git a/uitest/src/com/vaadin/tests/components/menubar/MenuBarTooltipsNearEdgeTest.java b/uitest/src/com/vaadin/tests/components/menubar/MenuBarTooltipsNearEdgeTest.java index 3cfe30a991..4a7f2fa548 100644 --- a/uitest/src/com/vaadin/tests/components/menubar/MenuBarTooltipsNearEdgeTest.java +++ b/uitest/src/com/vaadin/tests/components/menubar/MenuBarTooltipsNearEdgeTest.java @@ -1,12 +1,12 @@ /* * Copyright 2000-2014 Vaadin 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 @@ -30,11 +30,12 @@ import org.openqa.selenium.internal.Locatable; import org.openqa.selenium.remote.DesiredCapabilities; import com.vaadin.testbench.elements.MenuBarElement; +import com.vaadin.testbench.parallel.Browser; import com.vaadin.tests.tb3.MultiBrowserTest; /** * Test to see if tooltips will render in the correct locations near the edges. - * + * * @author Vaadin Ltd */ public class MenuBarTooltipsNearEdgeTest extends MultiBrowserTest { diff --git a/uitest/src/com/vaadin/tests/components/nativeselect/NativeSelectsAndChromeKeyboardNavigationTest.java b/uitest/src/com/vaadin/tests/components/nativeselect/NativeSelectsAndChromeKeyboardNavigationTest.java index eb838c135e..d274f7104b 100644 --- a/uitest/src/com/vaadin/tests/components/nativeselect/NativeSelectsAndChromeKeyboardNavigationTest.java +++ b/uitest/src/com/vaadin/tests/components/nativeselect/NativeSelectsAndChromeKeyboardNavigationTest.java @@ -1,12 +1,12 @@ /* * Copyright 2000-2014 Vaadin 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 @@ -26,10 +26,11 @@ import org.openqa.selenium.WebElement; import org.openqa.selenium.interactions.Actions; import org.openqa.selenium.remote.DesiredCapabilities; +import com.vaadin.testbench.parallel.Browser; import com.vaadin.tests.tb3.MultiBrowserTest; /** - * + * * @since * @author Vaadin Ltd */ @@ -38,7 +39,7 @@ public class NativeSelectsAndChromeKeyboardNavigationTest extends /* * (non-Javadoc) - * + * * @see com.vaadin.tests.tb3.MultiBrowserTest#getBrowsersToTest() */ @Override @@ -74,7 +75,7 @@ public class NativeSelectsAndChromeKeyboardNavigationTest extends /* * (non-Javadoc) - * + * * @see com.vaadin.tests.tb3.AbstractTB3Test#getUIClass() */ @Override diff --git a/uitest/src/com/vaadin/tests/components/orderedlayout/CaptionLeakTest.java b/uitest/src/com/vaadin/tests/components/orderedlayout/CaptionLeakTest.java index a95ceca22b..86368f194c 100644 --- a/uitest/src/com/vaadin/tests/components/orderedlayout/CaptionLeakTest.java +++ b/uitest/src/com/vaadin/tests/components/orderedlayout/CaptionLeakTest.java @@ -1,12 +1,12 @@ /* * Copyright 2000-2014 Vaadin 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 @@ -19,6 +19,7 @@ import org.junit.Test; import org.openqa.selenium.By; import com.vaadin.testbench.elements.ButtonElement; +import com.vaadin.testbench.parallel.BrowserUtil; import com.vaadin.tests.tb3.MultiBrowserTest; public class CaptionLeakTest extends MultiBrowserTest { diff --git a/uitest/src/com/vaadin/tests/components/orderedlayout/VerticalLayoutFocusWithDOMChangesTest.java b/uitest/src/com/vaadin/tests/components/orderedlayout/VerticalLayoutFocusWithDOMChangesTest.java index 1afcabec1d..2469d8a204 100644 --- a/uitest/src/com/vaadin/tests/components/orderedlayout/VerticalLayoutFocusWithDOMChangesTest.java +++ b/uitest/src/com/vaadin/tests/components/orderedlayout/VerticalLayoutFocusWithDOMChangesTest.java @@ -1,12 +1,12 @@ /* * Copyright 2000-2014 Vaadin 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 @@ -24,6 +24,7 @@ import org.openqa.selenium.interactions.Actions; import org.openqa.selenium.remote.DesiredCapabilities; import com.vaadin.testbench.By; +import com.vaadin.testbench.parallel.BrowserUtil; import com.vaadin.tests.tb3.MultiBrowserTest; public class VerticalLayoutFocusWithDOMChangesTest extends MultiBrowserTest { @@ -54,8 +55,8 @@ public class VerticalLayoutFocusWithDOMChangesTest extends MultiBrowserTest { Assert.assertEquals("Just a button", activeElement.getText()); DesiredCapabilities capabilities = getDesiredCapabilities(); - if (capabilities.equals(BrowserUtil.ie(8)) - || capabilities.equals(BrowserUtil.ie(9))) { + if (capabilities.equals(BrowserUtil.ie8()) + || capabilities.equals(BrowserUtil.ie9())) { // IE8 and IE9 insert cursor in the start of input instead of end. Assert.assertEquals(incrementalText + initialText, tf1.getAttribute("value")); @@ -86,8 +87,8 @@ public class VerticalLayoutFocusWithDOMChangesTest extends MultiBrowserTest { new Actions(getDriver()).sendKeys(secondText).build().perform(); DesiredCapabilities capabilities = getDesiredCapabilities(); - if (capabilities.equals(BrowserUtil.ie(8)) - || capabilities.equals(BrowserUtil.ie(9))) { + if (capabilities.equals(BrowserUtil.ie8()) + || capabilities.equals(BrowserUtil.ie9())) { // IE8 and IE9 insert cursor in the start of input instead of end. Assert.assertEquals(secondText + firstText, tf2.getAttribute("value")); diff --git a/uitest/src/com/vaadin/tests/components/table/AddSelectionToRemovedRangeTest.java b/uitest/src/com/vaadin/tests/components/table/AddSelectionToRemovedRangeTest.java index 897511e41a..f533929d08 100644 --- a/uitest/src/com/vaadin/tests/components/table/AddSelectionToRemovedRangeTest.java +++ b/uitest/src/com/vaadin/tests/components/table/AddSelectionToRemovedRangeTest.java @@ -1,12 +1,12 @@ /* * Copyright 2000-2014 Vaadin 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 @@ -29,6 +29,7 @@ import org.openqa.selenium.interactions.Actions; import org.openqa.selenium.remote.DesiredCapabilities; import com.vaadin.testbench.By; +import com.vaadin.testbench.parallel.Browser; import com.vaadin.tests.tb3.MultiBrowserTest; public class AddSelectionToRemovedRangeTest extends MultiBrowserTest { diff --git a/uitest/src/com/vaadin/tests/components/table/CtrlShiftMultiselectTest.java b/uitest/src/com/vaadin/tests/components/table/CtrlShiftMultiselectTest.java index 255a798594..6d9a831c6d 100644 --- a/uitest/src/com/vaadin/tests/components/table/CtrlShiftMultiselectTest.java +++ b/uitest/src/com/vaadin/tests/components/table/CtrlShiftMultiselectTest.java @@ -1,12 +1,12 @@ /* * Copyright 2000-2014 Vaadin 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 @@ -25,6 +25,7 @@ import org.openqa.selenium.WebElement; import org.openqa.selenium.interactions.Actions; import org.openqa.selenium.remote.DesiredCapabilities; +import com.vaadin.testbench.parallel.Browser; import com.vaadin.tests.tb3.MultiBrowserTest; public class CtrlShiftMultiselectTest extends MultiBrowserTest { diff --git a/uitest/src/com/vaadin/tests/components/table/MemoryLeakTableTest.java b/uitest/src/com/vaadin/tests/components/table/MemoryLeakTableTest.java index b4b8d93fbe..16e8bc21da 100644 --- a/uitest/src/com/vaadin/tests/components/table/MemoryLeakTableTest.java +++ b/uitest/src/com/vaadin/tests/components/table/MemoryLeakTableTest.java @@ -24,11 +24,11 @@ import org.openqa.selenium.By; import org.openqa.selenium.JavascriptExecutor; import org.openqa.selenium.WebElement; +import com.vaadin.testbench.annotations.RunLocally; import com.vaadin.testbench.elements.ButtonElement; import com.vaadin.testbench.elements.TableElement; -import com.vaadin.tests.tb3.AbstractTB3Test.RunLocally; +import com.vaadin.testbench.parallel.Browser; import com.vaadin.tests.tb3.MultiBrowserTest; -import com.vaadin.tests.tb3.MultiBrowserTest.Browser; /** * Test case creating and deleting table component in a loop, testing memory diff --git a/uitest/src/com/vaadin/tests/components/table/SelectAllRowsTest.java b/uitest/src/com/vaadin/tests/components/table/SelectAllRowsTest.java index 0fc09adf40..41c25d7d93 100644 --- a/uitest/src/com/vaadin/tests/components/table/SelectAllRowsTest.java +++ b/uitest/src/com/vaadin/tests/components/table/SelectAllRowsTest.java @@ -1,12 +1,12 @@ /* * Copyright 2000-2014 Vaadin 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 @@ -31,6 +31,7 @@ import org.openqa.selenium.WebElement; import org.openqa.selenium.interactions.Actions; import org.openqa.selenium.remote.DesiredCapabilities; +import com.vaadin.testbench.parallel.Browser; import com.vaadin.tests.tb3.MultiBrowserTest; public class SelectAllRowsTest extends MultiBrowserTest { diff --git a/uitest/src/com/vaadin/tests/components/table/TableWithPollingTest.java b/uitest/src/com/vaadin/tests/components/table/TableWithPollingTest.java index 6aae1e27fc..2fbc4ad6ef 100644 --- a/uitest/src/com/vaadin/tests/components/table/TableWithPollingTest.java +++ b/uitest/src/com/vaadin/tests/components/table/TableWithPollingTest.java @@ -1,12 +1,12 @@ /* * Copyright 2000-2014 Vaadin 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 @@ -24,6 +24,7 @@ import org.openqa.selenium.WebElement; import org.openqa.selenium.interactions.Actions; import org.openqa.selenium.remote.DesiredCapabilities; +import com.vaadin.testbench.parallel.Browser; import com.vaadin.tests.tb3.MultiBrowserTest; public class TableWithPollingTest extends MultiBrowserTest { diff --git a/uitest/src/com/vaadin/tests/components/tabsheet/TabSheetFocusedTabTest.java b/uitest/src/com/vaadin/tests/components/tabsheet/TabSheetFocusedTabTest.java index 12ae03080b..87032e59ed 100644 --- a/uitest/src/com/vaadin/tests/components/tabsheet/TabSheetFocusedTabTest.java +++ b/uitest/src/com/vaadin/tests/components/tabsheet/TabSheetFocusedTabTest.java @@ -1,12 +1,12 @@ /* * Copyright 2000-2014 Vaadin 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 @@ -27,6 +27,7 @@ import org.openqa.selenium.interactions.Actions; import org.openqa.selenium.remote.DesiredCapabilities; import com.vaadin.testbench.By; +import com.vaadin.testbench.parallel.Browser; import com.vaadin.tests.tb3.MultiBrowserTest; public class TabSheetFocusedTabTest extends MultiBrowserTest { diff --git a/uitest/src/com/vaadin/tests/components/ui/TextAreaEventPropagationModifierKeysTest.java b/uitest/src/com/vaadin/tests/components/ui/TextAreaEventPropagationModifierKeysTest.java index fca312ba7e..b00450852e 100644 --- a/uitest/src/com/vaadin/tests/components/ui/TextAreaEventPropagationModifierKeysTest.java +++ b/uitest/src/com/vaadin/tests/components/ui/TextAreaEventPropagationModifierKeysTest.java @@ -1,12 +1,12 @@ /* * Copyright 2000-2014 Vaadin 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 @@ -25,6 +25,7 @@ import org.openqa.selenium.interactions.Actions; import org.openqa.selenium.remote.DesiredCapabilities; import com.vaadin.testbench.elements.TextAreaElement; +import com.vaadin.testbench.parallel.Browser; import com.vaadin.tests.tb3.MultiBrowserTest; public class TextAreaEventPropagationModifierKeysTest extends MultiBrowserTest { diff --git a/uitest/src/com/vaadin/tests/components/upload/TestFileUploadTest.java b/uitest/src/com/vaadin/tests/components/upload/TestFileUploadTest.java index ae966a5b07..ebc6883dcc 100644 --- a/uitest/src/com/vaadin/tests/components/upload/TestFileUploadTest.java +++ b/uitest/src/com/vaadin/tests/components/upload/TestFileUploadTest.java @@ -1,12 +1,12 @@ /* * Copyright 2000-2014 Vaadin 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 @@ -34,6 +34,7 @@ import org.openqa.selenium.remote.LocalFileDetector; import org.openqa.selenium.remote.RemoteWebElement; import com.vaadin.testbench.elements.UploadElement; +import com.vaadin.testbench.parallel.Browser; import com.vaadin.tests.tb3.MultiBrowserTest; public class TestFileUploadTest extends MultiBrowserTest { diff --git a/uitest/src/com/vaadin/tests/components/window/SubWindowsTextSelectionTest.java b/uitest/src/com/vaadin/tests/components/window/SubWindowsTextSelectionTest.java index 335590437d..88e08192aa 100644 --- a/uitest/src/com/vaadin/tests/components/window/SubWindowsTextSelectionTest.java +++ b/uitest/src/com/vaadin/tests/components/window/SubWindowsTextSelectionTest.java @@ -1,12 +1,12 @@ /* * Copyright 2000-2014 Vaadin 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 @@ -27,12 +27,13 @@ import org.openqa.selenium.WebElement; import org.openqa.selenium.interactions.Actions; import org.openqa.selenium.remote.DesiredCapabilities; +import com.vaadin.testbench.parallel.BrowserUtil; import com.vaadin.tests.tb3.MultiBrowserTest; /** * Test for issue #12726, IE's make text selection when sub windows are * dragged(moved). - * + * * @since * @author Vaadin Ltd */ @@ -56,9 +57,9 @@ public class SubWindowsTextSelectionTest extends MultiBrowserTest { @Override public List<DesiredCapabilities> getBrowsersToTest() { ArrayList<DesiredCapabilities> list = new ArrayList<DesiredCapabilities>(); - list.add(BrowserUtil.ie(9)); - list.add(BrowserUtil.ie(10)); - list.add(BrowserUtil.ie(11)); + list.add(BrowserUtil.ie9()); + list.add(BrowserUtil.ie10()); + list.add(BrowserUtil.ie11()); return list; } diff --git a/uitest/src/com/vaadin/tests/integration/AbstractIntegrationTest.java b/uitest/src/com/vaadin/tests/integration/AbstractIntegrationTest.java index 073975a509..844f0e9c29 100644 --- a/uitest/src/com/vaadin/tests/integration/AbstractIntegrationTest.java +++ b/uitest/src/com/vaadin/tests/integration/AbstractIntegrationTest.java @@ -1,12 +1,12 @@ /* * Copyright 2000-2014 Vaadin 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 @@ -15,14 +15,14 @@ */ package com.vaadin.tests.integration; +import com.vaadin.testbench.parallel.TestNameSuffix; import com.vaadin.tests.tb3.PrivateTB3Configuration; -import com.vaadin.tests.tb3.TestNameSuffix; /** * Base class for integration tests. Integration tests use the * {@literal deployment.url} parameter to determine the base deployment url * (http://hostname:123) - * + * * @author Vaadin Ltd */ @TestNameSuffix(property = "server-name") diff --git a/uitest/src/com/vaadin/tests/layouts/IE8MeasuredSizeMemoryLeakTest.java b/uitest/src/com/vaadin/tests/layouts/IE8MeasuredSizeMemoryLeakTest.java index bfe38b8865..5ac31007b3 100644 --- a/uitest/src/com/vaadin/tests/layouts/IE8MeasuredSizeMemoryLeakTest.java +++ b/uitest/src/com/vaadin/tests/layouts/IE8MeasuredSizeMemoryLeakTest.java @@ -1,12 +1,12 @@ /* * Copyright 2000-2014 Vaadin 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 @@ -23,6 +23,7 @@ import org.junit.Test; import org.openqa.selenium.JavascriptExecutor; import org.openqa.selenium.remote.DesiredCapabilities; +import com.vaadin.testbench.parallel.Browser; import com.vaadin.tests.tb3.MultiBrowserTest; public class IE8MeasuredSizeMemoryLeakTest extends MultiBrowserTest { diff --git a/uitest/src/com/vaadin/tests/push/BasicPushWebsocketTest.java b/uitest/src/com/vaadin/tests/push/BasicPushWebsocketTest.java index 093ee348b8..51612882e4 100644 --- a/uitest/src/com/vaadin/tests/push/BasicPushWebsocketTest.java +++ b/uitest/src/com/vaadin/tests/push/BasicPushWebsocketTest.java @@ -1,29 +1,29 @@ -/* - * Copyright 2000-2014 Vaadin 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 com.vaadin.tests.push; - -import java.util.List; - -import org.openqa.selenium.remote.DesiredCapabilities; - -import com.vaadin.tests.tb3.WebsocketTest; - -public class BasicPushWebsocketTest extends BasicPushTest { - @Override - public List<DesiredCapabilities> getBrowsersToTest() { - return WebsocketTest.getWebsocketBrowsers(); - } -} +///* +// * Copyright 2000-2014 Vaadin 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 com.vaadin.tests.push; +// +//import java.util.List; +// +//import org.openqa.selenium.remote.DesiredCapabilities; +// +//import com.vaadin.tests.tb3.WebsocketTest; +// +//public class BasicPushWebsocketTest extends BasicPushTest { +// @Override +// public List<DesiredCapabilities> getBrowsersToTest() { +// return WebsocketTest.getBrowsersToTest(); +// } +// } diff --git a/uitest/src/com/vaadin/tests/push/ExtremelyLongPushTimeTest.java b/uitest/src/com/vaadin/tests/push/ExtremelyLongPushTimeTest.java index 06ddc07abb..b1727a02fe 100644 --- a/uitest/src/com/vaadin/tests/push/ExtremelyLongPushTimeTest.java +++ b/uitest/src/com/vaadin/tests/push/ExtremelyLongPushTimeTest.java @@ -1,12 +1,12 @@ /* * Copyright 2000-2014 Vaadin 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 @@ -36,7 +36,7 @@ public abstract class ExtremelyLongPushTimeTest extends MultiBrowserTest { testBench(driver).disableWaitForVaadin(); // Wait for startButton to be present - waitForElementToBePresent(vaadinLocatorById("startButton")); + waitForElementPresent(vaadinLocatorById("startButton")); String logRow0Id = "Log_row_0"; By logRow0 = vaadinLocatorById(logRow0Id); diff --git a/uitest/src/com/vaadin/tests/push/ExtremelyLongPushTimeWebsocketTest.java b/uitest/src/com/vaadin/tests/push/ExtremelyLongPushTimeWebsocketTest.java index c0b188bbab..0f6d08d595 100644 --- a/uitest/src/com/vaadin/tests/push/ExtremelyLongPushTimeWebsocketTest.java +++ b/uitest/src/com/vaadin/tests/push/ExtremelyLongPushTimeWebsocketTest.java @@ -1,31 +1,31 @@ -/* - * Copyright 2000-2014 Vaadin 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 com.vaadin.tests.push; - -import java.util.List; - -import org.openqa.selenium.remote.DesiredCapabilities; - -import com.vaadin.tests.tb3.WebsocketTest; - -public class ExtremelyLongPushTimeWebsocketTest extends - ExtremelyLongPushTimeTest { - - @Override - public List<DesiredCapabilities> getBrowsersToTest() { - return WebsocketTest.getWebsocketBrowsers(); - } -} +///* +// * Copyright 2000-2014 Vaadin 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 com.vaadin.tests.push; +// +//import java.util.List; +// +//import org.openqa.selenium.remote.DesiredCapabilities; +// +//import com.vaadin.tests.tb3.WebsocketTest; +// +//public class ExtremelyLongPushTimeWebsocketTest extends +// ExtremelyLongPushTimeTest { +// +// @Override +// public List<DesiredCapabilities> getBrowsersToTest() { +// return WebsocketTest.getWebsocketBrowsers(); +// } +// } diff --git a/uitest/src/com/vaadin/tests/push/IdlePushChannelWebsocketTest.java b/uitest/src/com/vaadin/tests/push/IdlePushChannelWebsocketTest.java index 644dbd7580..0e1d1d6231 100644 --- a/uitest/src/com/vaadin/tests/push/IdlePushChannelWebsocketTest.java +++ b/uitest/src/com/vaadin/tests/push/IdlePushChannelWebsocketTest.java @@ -1,35 +1,35 @@ -/* - * Copyright 2000-2014 Vaadin 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 com.vaadin.tests.push; - -import java.util.List; - -import org.openqa.selenium.remote.DesiredCapabilities; - -import com.vaadin.tests.tb3.WebsocketTest; - -public class IdlePushChannelWebsocketTest extends IdlePushChannelTest { - - @Override - protected Class<?> getUIClass() { - return BasicPushWebsocket.class; - } - - @Override - public List<DesiredCapabilities> getBrowsersToTest() { - return WebsocketTest.getWebsocketBrowsers(); - } -} +///* +// * Copyright 2000-2014 Vaadin 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 com.vaadin.tests.push; +// +//import java.util.List; +// +//import org.openqa.selenium.remote.DesiredCapabilities; +// +//import com.vaadin.tests.tb3.WebsocketTest; +// +//public class IdlePushChannelWebsocketTest extends IdlePushChannelTest { +// +// @Override +// protected Class<?> getUIClass() { +// return BasicPushWebsocket.class; +// } +// +// @Override +// public List<DesiredCapabilities> getBrowsersToTest() { +// return WebsocketTest.getWebsocketBrowsers(); +// } +// } diff --git a/uitest/src/com/vaadin/tests/push/PushConfigurationLongPollingTest.java b/uitest/src/com/vaadin/tests/push/PushConfigurationLongPollingTest.java index ac58deea56..73f6fc1e1a 100644 --- a/uitest/src/com/vaadin/tests/push/PushConfigurationLongPollingTest.java +++ b/uitest/src/com/vaadin/tests/push/PushConfigurationLongPollingTest.java @@ -1,12 +1,12 @@ /* * Copyright 2000-2014 Vaadin 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 @@ -24,6 +24,8 @@ import org.junit.Test; import org.openqa.selenium.remote.DesiredCapabilities; import org.openqa.selenium.support.ui.Select; +import com.vaadin.testbench.parallel.Browser; + public class PushConfigurationLongPollingTest extends PushConfigurationTest { @Override diff --git a/uitest/src/com/vaadin/tests/push/PushConfigurationStreamingTest.java b/uitest/src/com/vaadin/tests/push/PushConfigurationStreamingTest.java index 8dc960c9ac..91c4f5a2a7 100644 --- a/uitest/src/com/vaadin/tests/push/PushConfigurationStreamingTest.java +++ b/uitest/src/com/vaadin/tests/push/PushConfigurationStreamingTest.java @@ -1,12 +1,12 @@ /* * Copyright 2000-2014 Vaadin 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 @@ -25,6 +25,8 @@ import org.junit.Test; import org.openqa.selenium.remote.DesiredCapabilities; import org.openqa.selenium.support.ui.Select; +import com.vaadin.testbench.parallel.Browser; + public class PushConfigurationStreamingTest extends PushConfigurationTest { @Override diff --git a/uitest/src/com/vaadin/tests/push/PushConfigurationWebSocketTest.java b/uitest/src/com/vaadin/tests/push/PushConfigurationWebSocketTest.java index c9a813fac0..a464fa20b2 100644 --- a/uitest/src/com/vaadin/tests/push/PushConfigurationWebSocketTest.java +++ b/uitest/src/com/vaadin/tests/push/PushConfigurationWebSocketTest.java @@ -1,12 +1,12 @@ /* * Copyright 2000-2014 Vaadin 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 @@ -25,6 +25,8 @@ import org.junit.Test; import org.openqa.selenium.remote.DesiredCapabilities; import org.openqa.selenium.support.ui.Select; +import com.vaadin.testbench.parallel.Browser; + public class PushConfigurationWebSocketTest extends PushConfigurationTest { @Override diff --git a/uitest/src/com/vaadin/tests/push/PushErrorHandlingTest.java b/uitest/src/com/vaadin/tests/push/PushErrorHandlingTest.java index 1f6e181c89..3865443201 100644 --- a/uitest/src/com/vaadin/tests/push/PushErrorHandlingTest.java +++ b/uitest/src/com/vaadin/tests/push/PushErrorHandlingTest.java @@ -1,12 +1,12 @@ /* * Copyright 2000-2014 Vaadin 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 @@ -21,6 +21,7 @@ import org.openqa.selenium.By; import org.openqa.selenium.WebElement; import com.vaadin.testbench.elements.LabelElement; +import com.vaadin.testbench.parallel.BrowserUtil; import com.vaadin.tests.annotations.TestCategory; import com.vaadin.tests.tb3.MultiBrowserTest; diff --git a/uitest/src/com/vaadin/tests/push/PushLargeDataLongPollingTest.java b/uitest/src/com/vaadin/tests/push/PushLargeDataLongPollingTest.java index 00ee6bae25..91c2606f08 100644 --- a/uitest/src/com/vaadin/tests/push/PushLargeDataLongPollingTest.java +++ b/uitest/src/com/vaadin/tests/push/PushLargeDataLongPollingTest.java @@ -1,12 +1,12 @@ /* * Copyright 2000-2014 Vaadin 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 @@ -42,7 +42,7 @@ public class PushLargeDataLongPollingTest extends MultiBrowserTest { private void push() throws InterruptedException { // Wait for startButton to be present - waitForElementToBePresent(vaadinLocatorById("startButton")); + waitForElementPresent(vaadinLocatorById("startButton")); String logRow0Id = "Log_row_0"; By logRow0 = vaadinLocatorById(logRow0Id); diff --git a/uitest/src/com/vaadin/tests/push/PushLargeDataStreamingTest.java b/uitest/src/com/vaadin/tests/push/PushLargeDataStreamingTest.java index 26fa512ab2..e43bef3e7f 100644 --- a/uitest/src/com/vaadin/tests/push/PushLargeDataStreamingTest.java +++ b/uitest/src/com/vaadin/tests/push/PushLargeDataStreamingTest.java @@ -1,12 +1,12 @@ /* * Copyright 2000-2014 Vaadin 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 @@ -42,7 +42,7 @@ public class PushLargeDataStreamingTest extends MultiBrowserTest { private void push() throws InterruptedException { // Wait for startButton to be present - waitForElementToBePresent(vaadinLocatorById("startButton")); + waitForElementPresent(vaadinLocatorById("startButton")); String logRow0Id = "Log_row_0"; By logRow0 = vaadinLocatorById(logRow0Id); diff --git a/uitest/src/com/vaadin/tests/push/PushLargeDataWebsocketTest.java b/uitest/src/com/vaadin/tests/push/PushLargeDataWebsocketTest.java index 57fb8c33b0..d1c11192d5 100644 --- a/uitest/src/com/vaadin/tests/push/PushLargeDataWebsocketTest.java +++ b/uitest/src/com/vaadin/tests/push/PushLargeDataWebsocketTest.java @@ -1,12 +1,12 @@ /* * Copyright 2000-2014 Vaadin 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 @@ -40,7 +40,7 @@ public class PushLargeDataWebsocketTest extends WebsocketTest { private void push() throws Exception { // Wait for startButton to be present - waitForElementToBePresent(vaadinLocatorById("startButton")); + waitForElementPresent(vaadinLocatorById("startButton")); String logRow0Id = "Log_row_0"; By logRow0 = vaadinLocatorById(logRow0Id); diff --git a/uitest/src/com/vaadin/tests/push/ReconnectTest.java b/uitest/src/com/vaadin/tests/push/ReconnectTest.java index 5ad2e7a127..5f5789d4ca 100644 --- a/uitest/src/com/vaadin/tests/push/ReconnectTest.java +++ b/uitest/src/com/vaadin/tests/push/ReconnectTest.java @@ -1,12 +1,12 @@ /* * Copyright 2000-2014 Vaadin 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 @@ -83,7 +83,8 @@ public abstract class ReconnectTest extends MultiBrowserTestWithProxy { waitForDebugMessage("Reopening push connection"); } - private void clearDebugMessages() { + @Override + protected void clearDebugMessages() { driver.findElement( By.xpath("//button[@class='v-debugwindow-button' and @title='Clear log']")) .click(); @@ -99,7 +100,8 @@ public abstract class ReconnectTest extends MultiBrowserTestWithProxy { message))); } - private void waitForDebugMessage(final String expectedMessage) { + @Override + protected void waitForDebugMessage(final String expectedMessage) { waitUntil(new ExpectedCondition<Boolean>() { @Override diff --git a/uitest/src/com/vaadin/tests/push/ReconnectWebsocketTest.java b/uitest/src/com/vaadin/tests/push/ReconnectWebsocketTest.java index efaf5d493e..fb8a407156 100644 --- a/uitest/src/com/vaadin/tests/push/ReconnectWebsocketTest.java +++ b/uitest/src/com/vaadin/tests/push/ReconnectWebsocketTest.java @@ -1,36 +1,36 @@ -/* - * Copyright 2000-2014 Vaadin 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 com.vaadin.tests.push; - -import java.util.List; - -import org.openqa.selenium.remote.DesiredCapabilities; - -import com.vaadin.tests.tb3.WebsocketTest; - -public class ReconnectWebsocketTest extends ReconnectTest { - - @Override - public List<DesiredCapabilities> getBrowsersToTest() { - return WebsocketTest.getWebsocketBrowsers(); - } - - @Override - protected Class<?> getUIClass() { - return BasicPushWebsocket.class; - } - -} +///* +// * Copyright 2000-2014 Vaadin 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 com.vaadin.tests.push; +// +//import java.util.List; +// +//import org.openqa.selenium.remote.DesiredCapabilities; +// +//import com.vaadin.tests.tb3.WebsocketTest; +// +//public class ReconnectWebsocketTest extends ReconnectTest { +// +// @Override +// public List<DesiredCapabilities> getBrowsersToTest() { +// return WebsocketTest.getWebsocketBrowsers(); +// } +// +// @Override +// protected Class<?> getUIClass() { +// return BasicPushWebsocket.class; +// } +// +// } diff --git a/uitest/src/com/vaadin/tests/push/RefreshCloseConnectionTest.java b/uitest/src/com/vaadin/tests/push/RefreshCloseConnectionTest.java index c5c6064555..452a4ad9ee 100644 --- a/uitest/src/com/vaadin/tests/push/RefreshCloseConnectionTest.java +++ b/uitest/src/com/vaadin/tests/push/RefreshCloseConnectionTest.java @@ -1,44 +1,44 @@ -/* - * Copyright 2000-2014 Vaadin 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 com.vaadin.tests.push; - -import java.util.List; - -import org.junit.Assert; -import org.junit.Test; -import org.openqa.selenium.remote.DesiredCapabilities; - -import com.vaadin.tests.tb3.MultiBrowserTest; -import com.vaadin.tests.tb3.WebsocketTest; - -public class RefreshCloseConnectionTest extends MultiBrowserTest { - @Test - public void testSessionRefresh() { - openTestURL(); - - Assert.assertEquals("1. Init", getLogRow(0)); - - openTestURL(); - - Assert.assertEquals("2. Refresh", getLogRow(1)); - Assert.assertEquals("3. Push", getLogRow(0)); - } - - @Override - public List<DesiredCapabilities> getBrowsersToTest() { - return WebsocketTest.getWebsocketBrowsers(); - } -} +///* +// * Copyright 2000-2014 Vaadin 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 com.vaadin.tests.push; +// +//import java.util.List; +// +//import org.junit.Assert; +//import org.junit.Test; +//import org.openqa.selenium.remote.DesiredCapabilities; +// +//import com.vaadin.tests.tb3.MultiBrowserTest; +//import com.vaadin.tests.tb3.WebsocketTest; +// +//public class RefreshCloseConnectionTest extends MultiBrowserTest { +// @Test +// public void testSessionRefresh() { +// openTestURL(); +// +// Assert.assertEquals("1. Init", getLogRow(0)); +// +// openTestURL(); +// +// Assert.assertEquals("2. Refresh", getLogRow(1)); +// Assert.assertEquals("3. Push", getLogRow(0)); +// } +// +// @Override +// public List<DesiredCapabilities> getBrowsersToTest() { +// return WebsocketTest.getWebsocketBrowsers(); +// } +// } diff --git a/uitest/src/com/vaadin/tests/tb3/AbstractTB3Test.java b/uitest/src/com/vaadin/tests/tb3/AbstractTB3Test.java index cfc7b37c98..ad820f3eac 100644 --- a/uitest/src/com/vaadin/tests/tb3/AbstractTB3Test.java +++ b/uitest/src/com/vaadin/tests/tb3/AbstractTB3Test.java @@ -1,12 +1,12 @@ /* * Copyright 2000-2014 Vaadin 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 @@ -16,21 +16,26 @@ package com.vaadin.tests.tb3; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; +import java.io.IOException; +import java.io.InputStream; +import java.io.StringWriter; +import java.lang.reflect.Field; import java.net.URL; +import java.util.ArrayList; import java.util.Collections; import java.util.List; - -import com.vaadin.testbench.TestBenchElement; -import org.junit.After; -import org.junit.Before; +import java.util.NoSuchElementException; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.http.HttpHost; +import org.apache.http.HttpResponse; +import org.apache.http.impl.client.DefaultHttpClient; +import org.apache.http.message.BasicHttpEntityEnclosingRequest; +import org.junit.Rule; import org.junit.runner.RunWith; import org.openqa.selenium.By; import org.openqa.selenium.JavascriptExecutor; -import org.openqa.selenium.Platform; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.interactions.HasInputDevices; @@ -38,26 +43,37 @@ import org.openqa.selenium.interactions.Keyboard; import org.openqa.selenium.interactions.Mouse; import org.openqa.selenium.interactions.internal.Coordinates; import org.openqa.selenium.internal.Locatable; -import org.openqa.selenium.remote.BrowserType; import org.openqa.selenium.remote.DesiredCapabilities; +import org.openqa.selenium.remote.HttpCommandExecutor; import org.openqa.selenium.remote.RemoteWebDriver; import org.openqa.selenium.support.ui.ExpectedCondition; import org.openqa.selenium.support.ui.ExpectedConditions; import org.openqa.selenium.support.ui.WebDriverWait; +import com.google.gwt.thirdparty.guava.common.base.Joiner; import com.thoughtworks.selenium.webdriven.WebDriverBackedSelenium; import com.vaadin.server.LegacyApplication; import com.vaadin.server.UIProvider; -import com.vaadin.testbench.TestBench; -import com.vaadin.testbench.TestBenchTestCase; +import com.vaadin.testbench.TestBenchDriverProxy; +import com.vaadin.testbench.TestBenchElement; +import com.vaadin.testbench.annotations.BrowserConfiguration; +import com.vaadin.testbench.elements.CheckBoxElement; +import com.vaadin.testbench.elements.LabelElement; +import com.vaadin.testbench.elements.TableElement; +import com.vaadin.testbench.elements.VerticalLayoutElement; +import com.vaadin.testbench.parallel.Browser; +import com.vaadin.testbench.parallel.BrowserUtil; +import com.vaadin.testbench.parallel.ParallelTest; import com.vaadin.tests.components.AbstractTestUIWithLog; -import com.vaadin.tests.tb3.MultiBrowserTest.Browser; import com.vaadin.ui.UI; +import elemental.json.JsonObject; +import elemental.json.impl.JsonUtil; + /** * Base class for TestBench 3+ tests. All TB3+ tests in the project should * extend this class. - * + * * Provides: * <ul> * <li>Helpers for browser selection</li> @@ -67,11 +83,15 @@ import com.vaadin.ui.UI; * and based on requested features, e.g. {@link #isDebug()}, {@link #isPush()}</li> * <li>Generic helpers for creating TB3+ tests</li> * </ul> - * + * * @author Vaadin Ltd */ -@RunWith(value = TB3Runner.class) -public abstract class AbstractTB3Test extends TestBenchTestCase { +@RunWith(TB3Runner.class) +public abstract class AbstractTB3Test extends ParallelTest { + + @Rule + public RetryOnFail retry = new RetryOnFail(); + /** * Height of the screenshots we want to capture */ @@ -87,65 +107,29 @@ public abstract class AbstractTB3Test extends TestBenchTestCase { */ private static final int BROWSER_TIMEOUT_IN_MS = 30 * 1000; - private DesiredCapabilities desiredCapabilities; - private boolean debug = false; private boolean push = false; - { - // Default browser to run on unless setDesiredCapabilities is called - desiredCapabilities = Browser.FIREFOX.getDesiredCapabilities(); + + static { + com.vaadin.testbench.Parameters + .setScreenshotComparisonCursorDetection(true); } /** * Connect to the hub using a remote web driver, set the canvas size and * opens the initial URL as specified by {@link #getTestUrl()} - * + * * @throws Exception */ - @Before + @Override public void setup() throws Exception { - setupDriver(); - } - - /** - * Creates and configure the web driver to be used for the test. By default - * creates a remote web driver which connects to {@link #getHubURL()} and - * selects a browser based on {@link #getDesiredCapabilities()}. - * - * This method MUST call {@link #setDriver(WebDriver)} with the newly - * generated driver. - * - * @throws Exception - * If something goes wrong - */ - protected void setupDriver() throws Exception { - DesiredCapabilities capabilities; - - Browser runLocallyBrowser = getRunLocallyBrowser(); - if (runLocallyBrowser != null) { - if (System.getenv().containsKey("TEAMCITY_VERSION")) { - throw new RuntimeException( - "@RunLocally is not supported for tests run on the build server"); - } - capabilities = runLocallyBrowser.getDesiredCapabilities(); - setupLocalDriver(capabilities); - } else { - capabilities = getDesiredCapabilities(); - - if (System.getProperty("useLocalWebDriver") != null) { - setupLocalDriver(capabilities); - } else { - WebDriver dr = TestBench.createDriver(new RemoteWebDriver( - new URL(getHubURL()), capabilities)); - setDriver(dr); - } - } + super.setup(); int w = SCREENSHOT_WIDTH; int h = SCREENSHOT_HEIGHT; - if (BrowserUtil.isIE8(capabilities)) { + if (BrowserUtil.isIE8(super.getDesiredCapabilities())) { // IE8 gets size wrong, who would have guessed... w += 4; h += 4; @@ -158,85 +142,131 @@ public abstract class AbstractTB3Test extends TestBenchTestCase { } - protected Browser getRunLocallyBrowser() { - RunLocally runLocally = getClass().getAnnotation(RunLocally.class); - if (runLocally != null) { - return runLocally.value(); - } else { - return null; + /** + * Method for closing the tested application. + */ + protected void closeApplication() { + if (driver != null) { + try { + openTestURL("closeApplication"); + } catch (Exception e) { + e.printStackTrace(); + } } } protected WebElement getTooltipElement() { - return getDriver().findElement(com.vaadin.testbench.By.className("v-tooltip-text")); + return getDriver().findElement( + com.vaadin.testbench.By.className("v-tooltip-text")); } protected Coordinates getCoordinates(TestBenchElement element) { return ((Locatable) element.getWrappedElement()).getCoordinates(); } - @Retention(RetentionPolicy.RUNTIME) - @Target(ElementType.TYPE) - public @interface RunLocally { - public Browser value() default Browser.FIREFOX; + private boolean hasDebugMessage(String message) { + return getDebugMessage(message) != null; } - /** - * Creates a {@link WebDriver} instance used for running the test locally - * for debug purposes. Used only when {@link #runLocally()} is overridden to - * return true; - */ - protected abstract void setupLocalDriver( - DesiredCapabilities desiredCapabilities); + private WebElement getDebugMessage(String message) { + return driver.findElement(By.xpath(String.format( + "//span[@class='v-debugwindow-message' and text()='%s']", + message))); + } + + protected void waitForDebugMessage(final String expectedMessage) { + waitForDebugMessage(expectedMessage, 30); + } + + protected void waitForDebugMessage(final String expectedMessage, int timeout) { + waitUntil(new ExpectedCondition<Boolean>() { + + @Override + public Boolean apply(WebDriver input) { + return hasDebugMessage(expectedMessage); + } + }, timeout); + } + + protected void clearDebugMessages() { + driver.findElement( + By.xpath("//button[@class='v-debugwindow-button' and @title='Clear log']")) + .click(); + } + + protected void waitUntilRowIsVisible(final TableElement table, final int row) { + waitUntil(new ExpectedCondition<Object>() { + @Override + public Object apply(WebDriver input) { + try { + return table.getCell(row, 0) != null; + } catch (NoSuchElementException e) { + return false; + } + } + }); + } + + protected void scrollTable(TableElement table, int rows, int rowToWait) { + testBenchElement(table.findElement(By.className("v-scrollable"))) + .scroll(rows * 30); + + waitUntilRowIsVisible(table, rowToWait); + } /** * Opens the given test (defined by {@link #getTestUrl()}, optionally with * debug window and/or push (depending on {@link #isDebug()} and * {@link #isPush()}. */ - protected void openTestURL() { - driver.get(getTestUrl()); + protected void openTestURL(String... parameters) { + openTestURL(getUIClass(), parameters); } /** - * Returns the full URL to be used for the test - * - * @return the full URL for the test + * Opens the given test (defined by {@link #getTestUrl()}, optionally with + * debug window and/or push (depending on {@link #isDebug()} and + * {@link #isPush()}. */ - protected String getTestUrl() { - String baseUrl = getBaseURL(); - if (baseUrl.endsWith("/")) { - baseUrl = baseUrl.substring(0, baseUrl.length() - 1); + protected void openTestURL(Class<?> uiClass, String... parameters) { + String url = getTestURL(uiClass); + + if (parameters.length > 0) { + url += "?" + Joiner.on("&").join(parameters); } - return baseUrl + getDeploymentPath(); + driver.get(url); } /** - * - * @return the location (URL) of the TB hub + * Returns the full URL to be used for the test + * + * @return the full URL for the test */ - protected String getHubURL() { - return "http://" + getHubHostname() + ":4444/wd/hub"; + protected String getTestUrl() { + return StringUtils.strip(getBaseURL(), "/") + getDeploymentPath(); } /** - * Used for building the hub URL to use for the test - * - * @return the host name of the TestBench hub + * Returns the full URL to be used for the test for the provided UI class. + * + * @return the full URL for the test */ - protected abstract String getHubHostname(); + protected String getTestURL(Class<?> uiClass) { + return StringUtils.strip(getBaseURL(), "/") + + getDeploymentPath(uiClass); + } /** * Used to determine what URL to initially open for the test - * + * * @return the host name of development server */ protected abstract String getDeploymentHostname(); /** * Used to determine what port the test is running on - * + * * @return The port teh test is running on, by default 8888 */ protected abstract int getDeploymentPort(); @@ -248,57 +278,23 @@ public abstract class AbstractTB3Test extends TestBenchTestCase { * ran and before running that, * {@link #setDesiredCapabilities(DesiredCapabilities)} is invoked with the * value returned by this method. - * + * * This method is not static to allow overriding it in sub classes. By * default runs the test only on Firefox - * + * * @return The browsers to run the test on */ + @BrowserConfiguration public List<DesiredCapabilities> getBrowsersToTest() { return Collections.singletonList(Browser.FIREFOX .getDesiredCapabilities()); } /** - * Used to determine which capabilities should be used when setting up a - * {@link WebDriver} for this test. Typically set by a test runner or left - * at its default (Firefox 24). If you want to run a test on a single - * browser other than Firefox 24 you can override this method. - * - * @return the requested browser capabilities - */ - protected DesiredCapabilities getDesiredCapabilities() { - return desiredCapabilities; - } - - /** - * Sets the requested browser capabilities (typically browser name and - * version) - * - * @param desiredCapabilities - */ - public void setDesiredCapabilities(DesiredCapabilities desiredCapabilities) { - this.desiredCapabilities = desiredCapabilities; - } - - /** - * Shuts down the driver after the test has been completed - * - * @throws Exception - */ - @After - public void tearDown() throws Exception { - if (driver != null) { - driver.quit(); - } - driver = null; - } - - /** * Finds an element based on the part of a TB2 style locator following the * :: (e.g. vaadin=runLabelModes::PID_Scheckboxaction-Enabled/domChild[0] -> * PID_Scheckboxaction-Enabled/domChild[0]). - * + * * @param vaadinLocator * The part following :: of the vaadin locator string * @return @@ -309,12 +305,11 @@ public abstract class AbstractTB3Test extends TestBenchTestCase { /** * Uses JavaScript to determine the currently focused element. - * + * * @return Focused element or null */ protected WebElement getFocusedElement() { - Object focusedElement = ((JavascriptExecutor) getDriver()) - .executeScript("return document.activeElement"); + Object focusedElement = executeScript("return document.activeElement"); if (null != focusedElement) { return (WebElement) focusedElement; } else { @@ -323,8 +318,21 @@ public abstract class AbstractTB3Test extends TestBenchTestCase { } /** + * Executes the given Javascript + * + * @param script + * the script to execute + * @return whatever + * {@link org.openqa.selenium.JavascriptExecutor#executeScript(String, Object...)} + * returns + */ + protected Object executeScript(String script) { + return ((JavascriptExecutor) getDriver()).executeScript(script); + } + + /** * Find a Vaadin element based on its id given using Component.setId - * + * * @param id * The id to locate * @return @@ -338,7 +346,7 @@ public abstract class AbstractTB3Test extends TestBenchTestCase { * following the :: (e.g. * vaadin=runLabelModes::PID_Scheckboxaction-Enabled/domChild[0] -> * PID_Scheckboxaction-Enabled/domChild[0]). - * + * * @param vaadinLocator * The part following :: of the vaadin locator string * @return @@ -352,7 +360,7 @@ public abstract class AbstractTB3Test extends TestBenchTestCase { /** * Constructs a {@link By} locator for the id given using Component.setId - * + * * @param id * The id to locate * @return a locator for the given id @@ -364,11 +372,11 @@ public abstract class AbstractTB3Test extends TestBenchTestCase { /** * Waits up to 10s for the given condition to become true. Use e.g. as * {@link #waitUntil(ExpectedConditions.textToBePresentInElement(by, text))} - * + * * @param condition * the condition to wait for to become true */ - protected void waitUntil(ExpectedCondition<Boolean> condition) { + protected <T> void waitUntil(ExpectedCondition<T> condition) { waitUntil(condition, 10); } @@ -376,11 +384,11 @@ public abstract class AbstractTB3Test extends TestBenchTestCase { * Waits the given number of seconds for the given condition to become true. * Use e.g. as {@link * #waitUntil(ExpectedConditions.textToBePresentInElement(by, text))} - * + * * @param condition * the condition to wait for to become true */ - protected void waitUntil(ExpectedCondition<Boolean> condition, + protected <T> void waitUntil(ExpectedCondition<T> condition, long timeoutInSeconds) { new WebDriverWait(driver, timeoutInSeconds).until(condition); } @@ -389,11 +397,11 @@ public abstract class AbstractTB3Test extends TestBenchTestCase { * Waits up to 10s for the given condition to become false. Use e.g. as * {@link #waitUntilNot(ExpectedConditions.textToBePresentInElement(by, * text))} - * + * * @param condition * the condition to wait for to become false */ - protected void waitUntilNot(ExpectedCondition<Boolean> condition) { + protected <T> void waitUntilNot(ExpectedCondition<T> condition) { waitUntilNot(condition, 10); } @@ -401,24 +409,52 @@ public abstract class AbstractTB3Test extends TestBenchTestCase { * Waits the given number of seconds for the given condition to become * false. Use e.g. as {@link * #waitUntilNot(ExpectedConditions.textToBePresentInElement(by, text))} - * + * * @param condition * the condition to wait for to become false */ - protected void waitUntilNot(ExpectedCondition<Boolean> condition, + protected <T> void waitUntilNot(ExpectedCondition<T> condition, long timeoutInSeconds) { waitUntil(ExpectedConditions.not(condition), timeoutInSeconds); } - protected void waitForElementToBePresent(By by) { - waitUntil(ExpectedConditions.not(ExpectedConditions - .invisibilityOfElementLocated(by))); + protected void waitForElementPresent(final By by) { + waitUntil(ExpectedConditions.presenceOfElementLocated(by)); + } + + protected void waitForElementVisible(final By by) { + waitUntil(ExpectedConditions.visibilityOfElementLocated(by)); + } + + /** + * Checks if the given element has the given class name. + * + * Matches only full class names, i.e. has ("foo") does not match + * class="foobar" + * + * @param element + * @param className + * @return + */ + protected boolean hasCssClass(WebElement element, String className) { + String classes = element.getAttribute("class"); + if (classes == null || classes.isEmpty()) { + return (className == null || className.isEmpty()); + } + + for (String cls : classes.split(" ")) { + if (className.equals(cls)) { + return true; + } + } + + return false; } /** * For tests extending {@link AbstractTestUIWithLog}, returns the element * for the Nth log row - * + * * @param rowNr * The log row to retrieve * @return the Nth log row @@ -430,7 +466,7 @@ public abstract class AbstractTB3Test extends TestBenchTestCase { /** * For tests extending {@link AbstractTestUIWithLog}, returns the text in * the Nth log row - * + * * @param rowNr * The log row to retrieve text for * @return the text in the log row @@ -441,7 +477,7 @@ public abstract class AbstractTB3Test extends TestBenchTestCase { /** * Asserts that {@literal a} is >= {@literal b} - * + * * @param message * The message to include in the {@link AssertionError} * @param a @@ -460,7 +496,7 @@ public abstract class AbstractTB3Test extends TestBenchTestCase { /** * Asserts that {@literal a} is > {@literal b} - * + * * @param message * The message to include in the {@link AssertionError} * @param a @@ -478,7 +514,7 @@ public abstract class AbstractTB3Test extends TestBenchTestCase { /** * Asserts that {@literal a} is <= {@literal b} - * + * * @param message * The message to include in the {@link AssertionError} * @param a @@ -497,7 +533,7 @@ public abstract class AbstractTB3Test extends TestBenchTestCase { /** * Asserts that {@literal a} is < {@literal b} - * + * * @param message * The message to include in the {@link AssertionError} * @param a @@ -522,12 +558,12 @@ public abstract class AbstractTB3Test extends TestBenchTestCase { /** * Returns the path that should be used for the test. The path contains the * full path (appended to hostname+port) and must start with a slash. - * + * * @param push * true if "?debug" should be added * @param debug * true if /run-push should be used instead of /run - * + * * @return The URL path to the UI class to test */ protected String getDeploymentPath() { @@ -544,13 +580,13 @@ public abstract class AbstractTB3Test extends TestBenchTestCase { * Returns the UI class the current test is connected to (or in special * cases UIProvider or LegacyApplication). Uses the enclosing class if the * test class is a static inner class to a UI class. - * + * * Test which are not enclosed by a UI class must implement this method and * return the UI class they want to test. - * + * * Note that this method will update the test name to the enclosing class to * be compatible with TB2 screenshot naming - * + * * @return the UI class the current test is connected to */ protected Class<?> getUIClass() { @@ -588,7 +624,7 @@ public abstract class AbstractTB3Test extends TestBenchTestCase { /** * Returns whether to run the test in debug mode (with the debug console * open) or not - * + * * @return true to run with the debug window open, false by default */ protected final boolean isDebug() { @@ -598,7 +634,7 @@ public abstract class AbstractTB3Test extends TestBenchTestCase { /** * Sets whether to run the test in debug mode (with the debug console open) * or not. - * + * * @param debug * true to open debug window, false otherwise */ @@ -610,7 +646,7 @@ public abstract class AbstractTB3Test extends TestBenchTestCase { * Returns whether to run the test with push enabled (using /run-push) or * not. Note that push tests can and should typically be created using @Push * on the UI instead of overriding this method - * + * * @return true if /run-push is used, false otherwise */ protected final boolean isPush() { @@ -621,7 +657,7 @@ public abstract class AbstractTB3Test extends TestBenchTestCase { * Sets whether to run the test with push enabled (using /run-push) or not. * Note that push tests can and should typically be created using @Push on * the UI instead of overriding this method - * + * * @param push * true to use /run-push in the test, false otherwise */ @@ -633,10 +669,10 @@ public abstract class AbstractTB3Test extends TestBenchTestCase { * Returns the path for the given UI class when deployed on the test server. * The path contains the full path (appended to hostname+port) and must * start with a slash. - * + * * This method takes into account {@link #isPush()} and {@link #isDebug()} * when the path is generated. - * + * * @param uiClass * @param push * true if "?debug" should be added @@ -644,13 +680,14 @@ public abstract class AbstractTB3Test extends TestBenchTestCase { * true if /run-push should be used instead of /run * @return The path to the given UI class */ - private String getDeploymentPath(Class<?> uiClass) { + protected String getDeploymentPath(Class<?> uiClass) { String runPath = "/run"; if (isPush()) { runPath = "/run-push"; } - if (UI.class.isAssignableFrom(uiClass)) { + if (UI.class.isAssignableFrom(uiClass) + || UIProvider.class.isAssignableFrom(uiClass)) { return runPath + "/" + uiClass.getCanonicalName() + (isDebug() ? "?debug" : ""); } else if (LegacyApplication.class.isAssignableFrom(uiClass)) { @@ -665,7 +702,7 @@ public abstract class AbstractTB3Test extends TestBenchTestCase { /** * Used to determine what URL to initially open for the test - * + * * @return The base URL for the test. Does not include a trailing slash. */ protected String getBaseURL() { @@ -675,7 +712,7 @@ public abstract class AbstractTB3Test extends TestBenchTestCase { /** * Generates the application id based on the URL in a way compatible with * VaadinServletService. - * + * * @param pathWithQueryParameters * The path part of the URL, possibly still containing query * parameters @@ -696,7 +733,7 @@ public abstract class AbstractTB3Test extends TestBenchTestCase { /** * Sleeps for the given number of ms but ensures that the browser connection * does not time out. - * + * * @param timeoutMillis * Number of ms to wait * @throws InterruptedException @@ -713,250 +750,9 @@ public abstract class AbstractTB3Test extends TestBenchTestCase { } /** - * Provides helper method for selecting the browser to run on - * - * @author Vaadin Ltd - */ - public static class BrowserUtil { - /** - * Gets the capabilities for Safari of the given version - * - * @param version - * the major version - * @return an object describing the capabilities required for running a - * test on the given Safari version - */ - public static DesiredCapabilities safari(int version) { - DesiredCapabilities c = DesiredCapabilities.safari(); - c.setPlatform(Platform.MAC); - c.setVersion("" + version); - return c; - } - - /** - * Gets the capabilities for Chrome of the given version - * - * @param version - * the major version - * @return an object describing the capabilities required for running a - * test on the given Chrome version - */ - public static DesiredCapabilities chrome(int version) { - DesiredCapabilities c = DesiredCapabilities.chrome(); - c.setVersion("" + version); - c.setPlatform(Platform.XP); - return c; - } - - /** - * Gets the capabilities for Opera of the given version - * - * @param version - * the major version - * @return an object describing the capabilities required for running a - * test on the given Opera version - */ - public static DesiredCapabilities opera(int version) { - DesiredCapabilities c = DesiredCapabilities.opera(); - c.setVersion("" + version); - c.setPlatform(Platform.XP); - return c; - } - - /** - * Gets the capabilities for Firefox of the given version - * - * @param version - * the major version - * @return an object describing the capabilities required for running a - * test on the given Firefox version - */ - public static DesiredCapabilities firefox(int version) { - DesiredCapabilities c = DesiredCapabilities.firefox(); - c.setVersion("" + version); - c.setPlatform(Platform.XP); - return c; - } - - /** - * Gets the capabilities for Internet Explorer of the given version - * - * @param version - * the major version - * @return an object describing the capabilities required for running a - * test on the given Internet Explorer version - */ - public static DesiredCapabilities ie(int version) { - DesiredCapabilities c = DesiredCapabilities.internetExplorer(); - c.setVersion("" + version); - return c; - } - - /** - * Gets the capabilities for PhantomJS of the given version - * - * @param version - * the major version - * @return an object describing the capabilities required for running a - * test on the given PhantomJS version - */ - public static DesiredCapabilities phantomJS(int version) { - DesiredCapabilities c = DesiredCapabilities.phantomjs(); - c.setPlatform(Platform.LINUX); - c.setVersion("" + version); - return c; - } - - /** - * Checks if the given capabilities refer to Internet Explorer 8 - * - * @param capabilities - * @return true if the capabilities refer to IE8, false otherwise - */ - public static boolean isIE8(DesiredCapabilities capabilities) { - return isIE(capabilities) && "8".equals(capabilities.getVersion()); - } - - /** - * @param capabilities - * The capabilities to check - * @return true if the capabilities refer to Internet Explorer, false - * otherwise - */ - public static boolean isIE(DesiredCapabilities capabilities) { - return BrowserType.IE.equals(capabilities.getBrowserName()); - } - - /** - * @param capabilities - * The capabilities to check - * @return true if the capabilities refer to Chrome, false otherwise - */ - public static boolean isChrome(DesiredCapabilities capabilities) { - return BrowserType.CHROME.equals(capabilities.getBrowserName()); - } - - /** - * @param capabilities - * The capabilities to check - * @return true if the capabilities refer to Opera, false otherwise - */ - public static boolean isOpera(DesiredCapabilities capabilities) { - return BrowserType.OPERA.equals(capabilities.getBrowserName()); - } - - /** - * @param capabilities - * The capabilities to check - * @return true if the capabilities refer to Safari, false otherwise - */ - public static boolean isSafari(DesiredCapabilities capabilities) { - return BrowserType.SAFARI.equals(capabilities.getBrowserName()); - } - - /** - * @param capabilities - * The capabilities to check - * @return true if the capabilities refer to Firefox, false otherwise - */ - public static boolean isFirefox(DesiredCapabilities capabilities) { - return BrowserType.FIREFOX.equals(capabilities.getBrowserName()); - } - - /** - * @param capabilities - * The capabilities to check - * @return true if the capabilities refer to PhantomJS, false otherwise - */ - public static boolean isPhantomJS(DesiredCapabilities capabilities) { - return BrowserType.PHANTOMJS.equals(capabilities.getBrowserName()); - } - - /** - * Returns a human readable identifier of the given browser. Used for - * test naming and screenshots - * - * @param capabilities - * @return a human readable string describing the capabilities - */ - public static String getBrowserIdentifier( - DesiredCapabilities capabilities) { - if (isIE(capabilities)) { - return "InternetExplorer"; - } else if (isFirefox(capabilities)) { - return "Firefox"; - } else if (isChrome(capabilities)) { - return "Chrome"; - } else if (isSafari(capabilities)) { - return "Safari"; - } else if (isOpera(capabilities)) { - return "Opera"; - } else if (isPhantomJS(capabilities)) { - return "PhantomJS"; - } - - return capabilities.getBrowserName(); - } - - /** - * Returns a human readable identifier of the platform described by the - * given capabilities. Used mainly for screenshots - * - * @param capabilities - * @return a human readable string describing the platform - */ - public static String getPlatform(DesiredCapabilities capabilities) { - if (capabilities.getPlatform() == Platform.WIN8 - || capabilities.getPlatform() == Platform.WINDOWS - || capabilities.getPlatform() == Platform.VISTA - || capabilities.getPlatform() == Platform.XP) { - return "Windows"; - } else if (capabilities.getPlatform() == Platform.MAC) { - return "Mac"; - } - return capabilities.getPlatform().toString(); - } - - /** - * Returns a string which uniquely (enough) identifies this browser. - * Used mainly in screenshot names. - * - * @param capabilities - * - * @return a unique string for each browser - */ - public static String getUniqueIdentifier( - DesiredCapabilities capabilities) { - return getUniqueIdentifier(getPlatform(capabilities), - getBrowserIdentifier(capabilities), - capabilities.getVersion()); - } - - /** - * Returns a string which uniquely (enough) identifies this browser. - * Used mainly in screenshot names. - * - * @param capabilities - * - * @return a unique string for each browser - */ - public static String getUniqueIdentifier( - DesiredCapabilities capabilities, String versionOverride) { - return getUniqueIdentifier(getPlatform(capabilities), - getBrowserIdentifier(capabilities), versionOverride); - } - - private static String getUniqueIdentifier(String platform, - String browser, String version) { - return platform + "_" + browser + "_" + version; - } - - } - - /** * Called by the test runner whenever there is an exception in the test that * will cause termination of the test - * + * * @param t * the throwable which caused the termination */ @@ -967,7 +763,7 @@ public abstract class AbstractTB3Test extends TestBenchTestCase { /** * Returns the mouse object for doing mouse commands - * + * * @return Returns the mouse */ public Mouse getMouse() { @@ -976,7 +772,7 @@ public abstract class AbstractTB3Test extends TestBenchTestCase { /** * Returns the keyboard object for controlling keyboard events - * + * * @return Return the keyboard */ public Keyboard getKeyboard() { @@ -995,7 +791,134 @@ public abstract class AbstractTB3Test extends TestBenchTestCase { } protected void openDebugLogTab() { - findElement(By.xpath("//button[@title='Debug message log']")).click(); + + waitUntil(new ExpectedCondition<Boolean>() { + @Override + public Boolean apply(WebDriver input) { + WebElement element = getDebugLogButton(); + return element != null; + } + }, 15); + getDebugLogButton().click(); } + private WebElement getDebugLogButton() { + return findElement(By.xpath("//button[@title='Debug message log']")); + } + + /** + * Should the "require window focus" be enabled for Internet Explorer. + * RequireWindowFocus makes tests more stable but seems to be broken with + * certain commands such as sendKeys. Therefore it is not enabled by default + * for all tests + * + * @return true, to use the "require window focus" feature, false otherwise + */ + protected boolean requireWindowFocusForIE() { + return false; + } + + /** + * Should the "enable persistent hover" be enabled for Internet Explorer. + * + * Persistent hovering causes continuous firing of mouse over events at the + * last location the mouse cursor has been moved to. This is to avoid + * problems where the real mouse cursor is inside the browser window and + * Internet Explorer uses that location for some undefined operation + * (http:// + * jimevansmusic.blogspot.fi/2012/06/whats-wrong-with-internet-explorer + * .html) + * + * @return true, to use the "persistent hover" feature, false otherwise + */ + protected boolean usePersistentHoverForIE() { + return true; + } + + // FIXME: Remove this once TB4 getRemoteControlName works properly + private RemoteWebDriver getRemoteDriver() { + WebDriver d = getDriver(); + if (d instanceof TestBenchDriverProxy) { + try { + Field f = TestBenchDriverProxy.class + .getDeclaredField("actualDriver"); + f.setAccessible(true); + return (RemoteWebDriver) f.get(d); + } catch (Exception e) { + e.printStackTrace(); + } + } + + if (d instanceof RemoteWebDriver) { + return (RemoteWebDriver) d; + } + + return null; + + } + + // FIXME: Remove this once TB4 getRemoteControlName works properly + protected String getRemoteControlName() { + try { + RemoteWebDriver d = getRemoteDriver(); + if (d == null) { + return null; + } + HttpCommandExecutor ce = (HttpCommandExecutor) d + .getCommandExecutor(); + String hostName = ce.getAddressOfRemoteServer().getHost(); + int port = ce.getAddressOfRemoteServer().getPort(); + HttpHost host = new HttpHost(hostName, port); + DefaultHttpClient client = new DefaultHttpClient(); + URL sessionURL = new URL("http://" + hostName + ":" + port + + "/grid/api/testsession?session=" + d.getSessionId()); + BasicHttpEntityEnclosingRequest r = new BasicHttpEntityEnclosingRequest( + "POST", sessionURL.toExternalForm()); + HttpResponse response = client.execute(host, r); + JsonObject object = extractObject(response); + URL myURL = new URL(object.getString("proxyId")); + if ((myURL.getHost() != null) && (myURL.getPort() != -1)) { + return myURL.getHost(); + } + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + protected boolean logContainsText(String string) { + List<String> logs = getLogs(); + + for (String text : logs) { + if (text.contains(string)) { + return true; + } + } + + return false; + } + + protected List<String> getLogs() { + VerticalLayoutElement log = $(VerticalLayoutElement.class).id("Log"); + List<LabelElement> logLabels = log.$(LabelElement.class).all(); + List<String> logTexts = new ArrayList<String>(); + + for (LabelElement label : logLabels) { + logTexts.add(label.getText()); + } + + return logTexts; + } + + private static JsonObject extractObject(HttpResponse resp) + throws IOException { + InputStream contents = resp.getEntity().getContent(); + StringWriter writer = new StringWriter(); + IOUtils.copy(contents, writer, "UTF8"); + return JsonUtil.parse(writer.toString()); + } + + protected void click(CheckBoxElement checkbox) { + checkbox.findElement(By.xpath("input")).click(); + } } diff --git a/uitest/src/com/vaadin/tests/tb3/AffectedTB3TestLocator.java b/uitest/src/com/vaadin/tests/tb3/AffectedTB3TestLocator.java new file mode 100644 index 0000000000..d65eba278b --- /dev/null +++ b/uitest/src/com/vaadin/tests/tb3/AffectedTB3TestLocator.java @@ -0,0 +1,92 @@ +/* + * Copyright 2000-2014 Vaadin 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 com.vaadin.tests.tb3; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +public class AffectedTB3TestLocator extends TB3TestLocator { + + private final ChangedTB3TestLocator changedTB3TestLocator; + + public AffectedTB3TestLocator() { + changedTB3TestLocator = new ChangedTB3TestLocator(); + } + + @Override + protected <T> List<Class<? extends T>> findClasses(Class<T> baseClass, + String basePackage, String[] ignoredPackages) throws IOException { + List<Class<? extends T>> allTestClasses = super.findClasses(baseClass, + basePackage, ignoredPackages); + + List<Class<? extends T>> changedTestClasses = changedTB3TestLocator + .findClasses(baseClass, basePackage, ignoredPackages); + + return getAffectedTestClasses(allTestClasses, changedTestClasses); + } + + private <T> List<Class<? extends T>> getAffectedTestClasses( + List<Class<? extends T>> allTestClasses, + List<Class<? extends T>> changedTestClasses) throws IOException { + + Set testClasses = new HashSet(changedTestClasses); + testClasses + .addAll(getTestClassesWithAffectedPackageName(allTestClasses)); + + List<Class<? extends T>> affectedTestClasses = new ArrayList<Class<? extends T>>(); + affectedTestClasses.addAll(testClasses); + + return affectedTestClasses; + } + + private <T> List<Class<? extends T>> getTestClassesWithAffectedPackageName( + List<Class<? extends T>> classes) { + List<Class<? extends T>> affectedTestClasses = new ArrayList<Class<? extends T>>(); + List<String> affectedFiles = getAffectedFiles(); + + for (Class c : classes) { + String[] packageParts = c.getName().split("\\."); + String lastPart = packageParts[packageParts.length - 2]; + + for (String f : affectedFiles) { + if (f.toLowerCase().contains(lastPart.toLowerCase())) { + affectedTestClasses.add(c); + + // Break here not to accidentally add the same test class + // multiple times if it matches more than one file. + break; + } + } + } + + return affectedTestClasses; + } + + private List<String> getAffectedFiles() { + List<String> affectedFilePaths = new ArrayList<String>(); + + for (String path : changedTB3TestLocator.getChangedFilePaths()) { + if (!path.toLowerCase().contains("test")) { + affectedFilePaths.add(path); + } + } + + return affectedFilePaths; + } +}
\ No newline at end of file diff --git a/uitest/src/com/vaadin/tests/tb3/AffectedTB3Tests.java b/uitest/src/com/vaadin/tests/tb3/AffectedTB3Tests.java new file mode 100644 index 0000000000..d9f90bc7ca --- /dev/null +++ b/uitest/src/com/vaadin/tests/tb3/AffectedTB3Tests.java @@ -0,0 +1,28 @@ +package com.vaadin.tests.tb3; + +import java.io.IOException; + +import org.junit.runner.RunWith; +import org.junit.runners.model.InitializationError; + +import com.vaadin.tests.tb3.AffectedTB3Tests.AffectedTB3TestSuite; + +/** + * Test suite that runs tests from test classes which have changes or have + * similar package name compare the the changes files in the current workspace. + * If there are no changes in the workspace, it will run the changes to test + * classes introduced in the HEAD commit. + * + * @author Vaadin Ltd + */ +@RunWith(AffectedTB3TestSuite.class) +public class AffectedTB3Tests { + public static class AffectedTB3TestSuite extends TB3TestSuite { + public AffectedTB3TestSuite(Class<?> klass) throws InitializationError, + IOException { + super(klass, AbstractTB3Test.class, "com.vaadin.tests", + new String[] { "com.vaadin.tests.integration" }, + new AffectedTB3TestLocator()); + } + } +}
\ No newline at end of file diff --git a/uitest/src/com/vaadin/tests/tb3/AllTB3Tests.java b/uitest/src/com/vaadin/tests/tb3/AllTB3Tests.java index b7cc8284d1..def4460070 100644 --- a/uitest/src/com/vaadin/tests/tb3/AllTB3Tests.java +++ b/uitest/src/com/vaadin/tests/tb3/AllTB3Tests.java @@ -1,12 +1,12 @@ /* * Copyright 2000-2014 Vaadin 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 @@ -16,6 +16,8 @@ package com.vaadin.tests.tb3; +import java.io.IOException; + import org.junit.runner.RunWith; import org.junit.runners.model.InitializationError; @@ -24,7 +26,7 @@ import com.vaadin.tests.tb3.AllTB3Tests.AllTB3TestsSuite; /** * Test consisting of all TB3 tests except integration tests (classes extending * AbstractTB3Test, excludes package com.vaadin.test.integration). - * + * * @author Vaadin Ltd */ @RunWith(AllTB3TestsSuite.class) @@ -32,7 +34,8 @@ public class AllTB3Tests { public static class AllTB3TestsSuite extends TB3TestSuite { - public AllTB3TestsSuite(Class<?> klass) throws InitializationError { + public AllTB3TestsSuite(Class<?> klass) throws InitializationError, + IOException { super(klass, AbstractTB3Test.class, "com.vaadin.tests", new String[] { "com.vaadin.tests.integration" }); } diff --git a/uitest/src/com/vaadin/tests/tb3/ChangedTB3TestLocator.java b/uitest/src/com/vaadin/tests/tb3/ChangedTB3TestLocator.java new file mode 100644 index 0000000000..0ae9472134 --- /dev/null +++ b/uitest/src/com/vaadin/tests/tb3/ChangedTB3TestLocator.java @@ -0,0 +1,170 @@ +/* + * Copyright 2000-2014 Vaadin 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 com.vaadin.tests.tb3; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jgit.api.DiffCommand; +import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.api.errors.GitAPIException; +import org.eclipse.jgit.diff.DiffEntry; +import org.eclipse.jgit.diff.DiffEntry.ChangeType; +import org.eclipse.jgit.diff.DiffFormatter; +import org.eclipse.jgit.diff.RawTextComparator; +import org.eclipse.jgit.errors.AmbiguousObjectException; +import org.eclipse.jgit.errors.IncorrectObjectTypeException; +import org.eclipse.jgit.errors.MissingObjectException; +import org.eclipse.jgit.errors.NoWorkTreeException; +import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.revwalk.RevWalk; +import org.eclipse.jgit.storage.file.FileRepositoryBuilder; +import org.eclipse.jgit.util.io.DisabledOutputStream; + +/** + * + * @since + * @author Vaadin Ltd + */ +public class ChangedTB3TestLocator extends TB3TestLocator { + + @Override + protected <T> List<Class<? extends T>> findClasses(Class<T> baseClass, + String basePackage, String[] ignoredPackages) throws IOException { + + return getChangedTestClasses(baseClass); + } + + protected List<String> getChangedFilePaths() { + List<String> filePaths = new ArrayList<String>(); + + for (DiffEntry diff : getDiffs()) { + if (diff.getChangeType() != ChangeType.DELETE) { + filePaths.add(diff.getNewPath()); + System.out.println("Using changed file: " + diff.getNewPath()); + } + } + + return filePaths; + } + + private List<DiffEntry> getDiffs() { + try { + FileRepositoryBuilder builder = new FileRepositoryBuilder(); + Repository repository = builder.setWorkTree(new File(".")) + .readEnvironment() // scan environment GIT_* variables + .findGitDir() // scan up the file system tree + .build(); + + List<DiffEntry> diffsInWorkingTree = getDiffsInWorkingTree(repository); + + if (diffsInWorkingTree.isEmpty()) { + return getDiffsInHead(repository); + } + + return diffsInWorkingTree; + + } catch (IOException e) { + e.printStackTrace(); + } catch (NoWorkTreeException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (GitAPIException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return null; + } + + private List<DiffEntry> getDiffsInWorkingTree(Repository repository) + throws GitAPIException { + Git git = new Git(repository); + DiffCommand diffCommand = git.diff(); + + List<DiffEntry> diffsInWorkingTree = new ArrayList<DiffEntry>(); + + for (DiffEntry diff : diffCommand.call()) { + if (pathIsExcluded(diff.getNewPath())) { + continue; + } + + diffsInWorkingTree.add(diff); + } + + return diffsInWorkingTree; + } + + private boolean pathIsExcluded(String path) { + // Exclude temporary junit files and screenshots. + return path.startsWith("uitest/junit") + || getScreenshotDirectory().contains(path); + } + + private String getScreenshotDirectory() { + return PrivateTB3Configuration + .getProperty(PrivateTB3Configuration.SCREENSHOT_DIRECTORY); + } + + private List<DiffEntry> getDiffsInHead(Repository repository) + throws AmbiguousObjectException, IncorrectObjectTypeException, + IOException, MissingObjectException { + RevWalk rw = new RevWalk(repository); + ObjectId head = repository.resolve(Constants.HEAD); + RevCommit commit = rw.parseCommit(head); + RevCommit parent = rw.parseCommit(commit.getParent(0).getId()); + DiffFormatter df = new DiffFormatter(DisabledOutputStream.INSTANCE); + df.setRepository(repository); + df.setDiffComparator(RawTextComparator.DEFAULT); + df.setDetectRenames(true); + List<DiffEntry> diffs = df.scan(parent.getTree(), commit.getTree()); + + return diffs; + } + + private <T> List<Class<? extends T>> getChangedTestClasses( + Class<T> baseClass) { + List<String> changedTestFilePaths = getTestFilePaths(); + List<Class<? extends T>> testClasses = new ArrayList<Class<? extends T>>(); + + for (String filePath : changedTestFilePaths) { + String path = filePath.replace("uitest/src/", "").replace(".java", + ""); + String className = path.replace("/", "."); + addClassIfMatches(testClasses, className, baseClass); + } + + return testClasses; + } + + private List<String> getTestFilePaths() { + List<String> changedTestFilePaths = new ArrayList<String>(); + + for (String filePath : getChangedFilePaths()) { + if (filePath.toLowerCase().startsWith("uitest") + && filePath.toLowerCase().endsWith(".java")) { + changedTestFilePaths.add(filePath); + } + } + + return changedTestFilePaths; + } + +} diff --git a/uitest/src/com/vaadin/tests/tb3/ChangedTB3Tests.java b/uitest/src/com/vaadin/tests/tb3/ChangedTB3Tests.java new file mode 100644 index 0000000000..2ca4ed20d7 --- /dev/null +++ b/uitest/src/com/vaadin/tests/tb3/ChangedTB3Tests.java @@ -0,0 +1,44 @@ +/* + * Copyright 2000-2014 Vaadin 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 com.vaadin.tests.tb3; + +import java.io.IOException; + +import org.junit.runner.RunWith; +import org.junit.runners.model.InitializationError; + +import com.vaadin.tests.tb3.ChangedTB3Tests.ChangedTB3TestsSuite; + +/** + * Test suite that runs tests from test classes which have changes in the + * current workspace. If there are no changes in the workspace, it will run the + * changes to test classes introduced in the HEAD commit. + * + * @since + * @author Vaadin Ltd + */ +@RunWith(ChangedTB3TestsSuite.class) +public class ChangedTB3Tests { + public static class ChangedTB3TestsSuite extends TB3TestSuite { + public ChangedTB3TestsSuite(Class<?> klass) throws InitializationError, + IOException { + super(klass, AbstractTB3Test.class, "com.vaadin.tests", + new String[] { "com.vaadin.tests.integration" }, + new ChangedTB3TestLocator()); + + } + } +} diff --git a/uitest/src/com/vaadin/tests/tb3/MultiBrowserTest.java b/uitest/src/com/vaadin/tests/tb3/MultiBrowserTest.java index ccbb6ca872..217a3b56a4 100644 --- a/uitest/src/com/vaadin/tests/tb3/MultiBrowserTest.java +++ b/uitest/src/com/vaadin/tests/tb3/MultiBrowserTest.java @@ -1,12 +1,12 @@ /* * Copyright 2000-2014 Vaadin 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 @@ -17,82 +17,94 @@ package com.vaadin.tests.tb3; import java.util.ArrayList; -import java.util.Collections; import java.util.List; +import org.openqa.selenium.ie.InternetExplorerDriver; import org.openqa.selenium.remote.DesiredCapabilities; +import com.vaadin.testbench.parallel.Browser; +import com.vaadin.testbench.parallel.BrowserUtil; + /** * Base class for tests which should be run on all supported browsers. The test * is automatically launched for multiple browsers in parallel by the test * runner. - * + * * Sub classes can, but typically should not, restrict the browsers used by * implementing a - * + * * <pre> * @Parameters * public static Collection<DesiredCapabilities> getBrowsersForTest() { * } * </pre> - * + * * @author Vaadin Ltd */ public abstract class MultiBrowserTest extends PrivateTB3Configuration { - protected List<DesiredCapabilities> getBrowsersExcludingIE() { - List<DesiredCapabilities> browsers = new ArrayList<DesiredCapabilities>(getAllBrowsers()); - browsers.remove(Browser.IE8.getDesiredCapabilities()); - browsers.remove(Browser.IE9.getDesiredCapabilities()); - browsers.remove(Browser.IE10.getDesiredCapabilities()); - browsers.remove(Browser.IE11.getDesiredCapabilities()); + protected List<DesiredCapabilities> getBrowsersSupportingWebSocket() { + // No WebSocket support in IE8-9 and PhantomJS + return getBrowserCapabilities(Browser.IE10, Browser.IE11, + Browser.FIREFOX, Browser.CHROME); + } - return browsers; + protected List<DesiredCapabilities> getBrowsersExcludingPhantomJS() { + return getBrowserCapabilities(Browser.IE8, Browser.IE9, Browser.IE10, + Browser.IE11, Browser.CHROME, Browser.FIREFOX); } - public enum Browser { - FIREFOX(BrowserUtil.firefox(24)), CHROME(BrowserUtil.chrome(33)), SAFARI( - BrowserUtil.safari(7)), IE8(BrowserUtil.ie(8)), IE9(BrowserUtil - .ie(9)), IE10(BrowserUtil.ie(10)), IE11(BrowserUtil.ie(11)), OPERA( - BrowserUtil.opera(17)), PHANTOMJS(BrowserUtil.phantomJS(1)); - private DesiredCapabilities desiredCapabilities; + protected List<DesiredCapabilities> getBrowsersExcludingIE() { + return getBrowserCapabilities(Browser.FIREFOX, Browser.CHROME, + Browser.PHANTOMJS); + } - private Browser(DesiredCapabilities desiredCapabilities) { - this.desiredCapabilities = desiredCapabilities; - } + protected List<DesiredCapabilities> getBrowsersExcludingIE8() { + return getBrowserCapabilities(Browser.IE9, Browser.IE10, Browser.IE11, + Browser.FIREFOX, Browser.CHROME, Browser.PHANTOMJS); + } - public DesiredCapabilities getDesiredCapabilities() { - return desiredCapabilities; - } + protected List<DesiredCapabilities> getBrowsersSupportingShiftClick() { + return getBrowserCapabilities(Browser.IE8, Browser.IE9, Browser.IE10, + Browser.IE11, Browser.CHROME); } - static List<DesiredCapabilities> allBrowsers = new ArrayList<DesiredCapabilities>(); - static { - allBrowsers.add(Browser.IE8.getDesiredCapabilities()); - allBrowsers.add(Browser.IE9.getDesiredCapabilities()); - allBrowsers.add(Browser.IE10.getDesiredCapabilities()); - allBrowsers.add(Browser.IE11.getDesiredCapabilities()); - allBrowsers.add(Browser.FIREFOX.getDesiredCapabilities()); - // Uncomment once we have the capability to run on Safari 6 - // allBrowsers.add(SAFARI); - allBrowsers.add(Browser.CHROME.getDesiredCapabilities()); - allBrowsers.add(Browser.PHANTOMJS.getDesiredCapabilities()); - // Re-enable this when it is possible to run on a modern Opera version - // allBrowsers.add(Browser.OPERA.getDesiredCapabilities()); + protected List<DesiredCapabilities> getIEBrowsersOnly() { + return getBrowserCapabilities(Browser.IE8, Browser.IE9, Browser.IE10, + Browser.IE11); } - /** - * @return all supported browsers which are actively tested - */ - public static List<DesiredCapabilities> getAllBrowsers() { - return Collections.unmodifiableList(allBrowsers); + @Override + public void setDesiredCapabilities(DesiredCapabilities desiredCapabilities) { + if (BrowserUtil.isIE(desiredCapabilities)) { + if (requireWindowFocusForIE()) { + desiredCapabilities.setCapability( + InternetExplorerDriver.REQUIRE_WINDOW_FOCUS, true); + } + if (!usePersistentHoverForIE()) { + desiredCapabilities.setCapability( + InternetExplorerDriver.ENABLE_PERSISTENT_HOVERING, + false); + } + } + + super.setDesiredCapabilities(desiredCapabilities); } @Override public List<DesiredCapabilities> getBrowsersToTest() { - // Return a copy so sub classes can do - // super.getBrowseresToTest().remove(something) - return new ArrayList<DesiredCapabilities>(getAllBrowsers()); + // Uncomment Safari and Opera if those become tested browsers again. + return getBrowserCapabilities(Browser.IE8, Browser.IE9, Browser.IE10, + Browser.IE11, Browser.FIREFOX, Browser.CHROME, + Browser.PHANTOMJS /* , Browser.SAFARI, Browser.OPERA */); } + protected List<DesiredCapabilities> getBrowserCapabilities( + Browser... browsers) { + List<DesiredCapabilities> capabilities = new ArrayList<DesiredCapabilities>(); + for (Browser browser : browsers) { + capabilities.add(browser.getDesiredCapabilities()); + } + return capabilities; + } } diff --git a/uitest/src/com/vaadin/tests/tb3/MultiBrowserTestWithProxy.java b/uitest/src/com/vaadin/tests/tb3/MultiBrowserTestWithProxy.java index 921fa080cd..4a2f8e088a 100755 --- a/uitest/src/com/vaadin/tests/tb3/MultiBrowserTestWithProxy.java +++ b/uitest/src/com/vaadin/tests/tb3/MultiBrowserTestWithProxy.java @@ -1,12 +1,12 @@ /* * Copyright 2000-2014 Vaadin 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 @@ -23,7 +23,7 @@ import org.junit.After; import com.jcraft.jsch.JSch; import com.jcraft.jsch.JSchException; import com.jcraft.jsch.Session; -import com.vaadin.tests.annotations.TestCategory; +import com.vaadin.testbench.parallel.TestCategory; @TestCategory("push") public abstract class MultiBrowserTestWithProxy extends MultiBrowserTest { diff --git a/uitest/src/com/vaadin/tests/tb3/PrivateTB3Configuration.java b/uitest/src/com/vaadin/tests/tb3/PrivateTB3Configuration.java index 15ca97f701..434eaca4d4 100644 --- a/uitest/src/com/vaadin/tests/tb3/PrivateTB3Configuration.java +++ b/uitest/src/com/vaadin/tests/tb3/PrivateTB3Configuration.java @@ -1,12 +1,12 @@ /* * Copyright 2000-2013 Vaadind 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 @@ -22,32 +22,31 @@ import java.io.IOException; import java.net.InetAddress; import java.net.NetworkInterface; import java.net.SocketException; -import java.util.Arrays; import java.util.Enumeration; import java.util.Properties; -import org.openqa.selenium.WebDriver; -import org.openqa.selenium.chrome.ChromeDriver; -import org.openqa.selenium.firefox.FirefoxBinary; -import org.openqa.selenium.firefox.FirefoxDriver; -import org.openqa.selenium.phantomjs.PhantomJSDriver; -import org.openqa.selenium.remote.DesiredCapabilities; -import org.openqa.selenium.safari.SafariDriver; - -import com.vaadin.testbench.TestBench; -import com.vaadin.tests.tb3.MultiBrowserTest.Browser; +import com.vaadin.testbench.annotations.BrowserFactory; +import com.vaadin.testbench.annotations.RunOnHub; /** * Provides values for parameters which depend on where the test is run. * Parameters should be configured in work/eclipse-run-selected-test.properties. * A template is available in uitest/. - * + * * @author Vaadin Ltd */ +@RunOnHub("tb3-hub.intra.itmill.com") +@BrowserFactory(VaadinBrowserFactory.class) public abstract class PrivateTB3Configuration extends ScreenshotTB3Test { + /** + * + */ + public static final String SCREENSHOT_DIRECTORY = "com.vaadin.testbench.screenshot.directory"; private static final String RUN_LOCALLY_PROPERTY = "com.vaadin.testbench.runLocally"; private static final String HOSTNAME_PROPERTY = "com.vaadin.testbench.deployment.hostname"; private static final String PORT_PROPERTY = "com.vaadin.testbench.deployment.port"; + private static final String DEPLOYMENT_PROPERTY = "com.vaadin.testbench.deployment.url"; + private static final String HUB_URL = "com.vaadin.testbench.hub.url"; private static final Properties properties = new Properties(); private static final File propertiesFile = new File("work", "eclipse-run-selected-test.properties"); @@ -61,7 +60,7 @@ public abstract class PrivateTB3Configuration extends ScreenshotTB3Test { } } - private static String getProperty(String name) { + protected static String getProperty(String name) { String property = properties.getProperty(name); if (property == null) { property = System.getProperty(name); @@ -82,17 +81,32 @@ public abstract class PrivateTB3Configuration extends ScreenshotTB3Test { @Override protected String getScreenshotDirectory() { - String screenshotDirectory = getProperty("com.vaadin.testbench.screenshot.directory"); + String screenshotDirectory = getProperty(SCREENSHOT_DIRECTORY); if (screenshotDirectory == null) { throw new RuntimeException( - "No screenshot directory defined. Use -Dcom.vaadin.testbench.screenshot.directory=<path>"); + "No screenshot directory defined. Use -D" + + SCREENSHOT_DIRECTORY + "=<path>"); } return screenshotDirectory; } @Override - protected String getHubHostname() { - return "tb3-hub.intra.itmill.com"; + protected String getHubURL() { + String hubUrl = getProperty(HUB_URL); + if (hubUrl == null || hubUrl.trim().isEmpty()) { + return super.getHubURL(); + } + + return hubUrl; + } + + @Override + protected String getBaseURL() { + String url = getProperty(DEPLOYMENT_PROPERTY); + if (url == null || url.trim().isEmpty()) { + return super.getBaseURL(); + } + return url; } @Override @@ -105,7 +119,7 @@ public abstract class PrivateTB3Configuration extends ScreenshotTB3Test { /** * Gets the hostname that tests are configured to use. - * + * * @return the host name configuration value */ public static String getConfiguredDeploymentHostname() { @@ -125,7 +139,7 @@ public abstract class PrivateTB3Configuration extends ScreenshotTB3Test { /** * Gets the port that tests are configured to use. - * + * * @return the port configuration value */ public static int getConfiguredDeploymentPort() { @@ -142,7 +156,7 @@ public abstract class PrivateTB3Configuration extends ScreenshotTB3Test { /** * Tries to automatically determine the IP address of the machine the test * is running on. - * + * * @return An IP address of one of the network interfaces in the machine. * @throws RuntimeException * if there was an error or no IP was found @@ -176,75 +190,4 @@ public abstract class PrivateTB3Configuration extends ScreenshotTB3Test { throw new RuntimeException( "No compatible (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16) ip address found."); } - - /* - * (non-Javadoc) - * - * @see com.vaadin.tests.tb3.AbstractTB3Test#setupLocalDriver() - */ - @Override - protected void setupLocalDriver(DesiredCapabilities desiredCapabilities) { - WebDriver driver; - if (BrowserUtil.isFirefox(desiredCapabilities)) { - String firefoxPath = getProperty("firefox.path"); - if (firefoxPath != null) { - driver = new FirefoxDriver(new FirefoxBinary(new File( - firefoxPath)), null); - } else { - driver = new FirefoxDriver(); - } - } else if (BrowserUtil.isChrome(desiredCapabilities)) { - String propertyName = "chrome.driver.path"; - String chromeDriverPath = getProperty(propertyName); - if (chromeDriverPath == null) { - throw new RuntimeException( - "You need to install ChromeDriver to use @" - + RunLocally.class.getSimpleName() - + " with Chrome." - + "\nFirst install it from https://code.google.com/p/selenium/wiki/ChromeDriver." - + "\nThen update " - + propertiesFile.getAbsolutePath() - + " to define a property named " - + propertyName - + " containing the path of your local ChromeDriver installation."); - } - System.setProperty("webdriver.chrome.driver", chromeDriverPath); - driver = new ChromeDriver(); - } else if (BrowserUtil.isSafari(desiredCapabilities)) { - driver = new SafariDriver(); - } else if (BrowserUtil.isPhantomJS(desiredCapabilities)) { - driver = new PhantomJSDriver(); - } else { - throw new RuntimeException( - "Not implemented support for running locally on " - + BrowserUtil - .getBrowserIdentifier(desiredCapabilities)); - } - setDriver(TestBench.createDriver(driver)); - setDesiredCapabilities(desiredCapabilities); - } - - @Override - protected Browser getRunLocallyBrowser() { - Browser runLocallyBrowser = super.getRunLocallyBrowser(); - if (runLocallyBrowser != null) { - // Always use annotation value if present - return runLocallyBrowser; - } - - String runLocallyValue = getProperty(RUN_LOCALLY_PROPERTY); - if (runLocallyValue == null || runLocallyValue.trim().isEmpty()) { - return null; - } - - String browserName = runLocallyValue.trim().toUpperCase(); - try { - return Browser.valueOf(browserName); - } catch (IllegalArgumentException e) { - throw new RuntimeException("Invalid " + RUN_LOCALLY_PROPERTY - + " property from " + getSource(RUN_LOCALLY_PROPERTY) - + ": " + runLocallyValue + ". Expected one of " - + Arrays.toString(Browser.values())); - } - } } diff --git a/uitest/src/com/vaadin/tests/tb3/ScreenshotTB3Test.java b/uitest/src/com/vaadin/tests/tb3/ScreenshotTB3Test.java index 1782e0042e..d43befdb55 100644 --- a/uitest/src/com/vaadin/tests/tb3/ScreenshotTB3Test.java +++ b/uitest/src/com/vaadin/tests/tb3/ScreenshotTB3Test.java @@ -1,12 +1,12 @@ /* * Copyright 2000-2014 Vaadin 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 @@ -16,36 +16,58 @@ package com.vaadin.tests.tb3; -import java.awt.image.BufferedImage; -import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileFilter; +import java.io.FileNotFoundException; import java.io.IOException; import java.util.ArrayList; import java.util.List; -import javax.imageio.ImageIO; - +import org.apache.commons.io.FileUtils; import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.rules.TestRule; import org.junit.rules.TestWatcher; -import org.openqa.selenium.OutputType; -import org.openqa.selenium.TakesScreenshot; +import org.junit.runner.Description; import org.openqa.selenium.remote.DesiredCapabilities; import com.vaadin.testbench.Parameters; -import com.vaadin.testbench.commands.TestBenchCommands; +import com.vaadin.testbench.ScreenshotOnFailureRule; +import com.vaadin.testbench.parallel.BrowserUtil; +import com.vaadin.testbench.screenshot.ImageFileUtil; /** * Base class which provides functionality for tests which use the automatic * screenshot comparison function. - * + * * @author Vaadin Ltd */ public abstract class ScreenshotTB3Test extends AbstractTB3Test { + @Rule + public ScreenshotOnFailureRule screenshotOnFailure = new ScreenshotOnFailureRule( + this, true) { + + @Override + protected void failed(Throwable throwable, Description description) { + super.failed(throwable, description); + closeApplication(); + } + + @Override + protected void succeeded(Description description) { + super.succeeded(description); + closeApplication(); + } + + @Override + protected File getErrorScreenshotFile(Description description) { + return ImageFileUtil + .getErrorScreenshotFile(getScreenshotFailureName()); + }; + }; + private String screenshotBaseName; @Rule @@ -68,13 +90,15 @@ public abstract class ScreenshotTB3Test extends AbstractTB3Test { * Contains a list of screenshot identifiers for which * {@link #compareScreen(String)} has failed during the test */ - private List<String> screenshotFailures = new ArrayList<String>(); + private List<String> screenshotFailures; /** * Defines TestBench screen comparison parameters before each test run */ @Before public void setupScreenComparisonParameters() { + screenshotFailures = new ArrayList<String>(); + Parameters.setScreenshotErrorDirectory(getScreenshotErrorDirectory()); Parameters .setScreenshotReferenceDirectory(getScreenshotReferenceDirectory()); @@ -84,13 +108,13 @@ public abstract class ScreenshotTB3Test extends AbstractTB3Test { * Grabs a screenshot and compares with the reference image with the given * identifier. Supports alternative references and will succeed if the * screenshot matches at least one of the references. - * + * * In case of a failed comparison this method stores the grabbed screenshots * in the error directory as defined by * {@link #getScreenshotErrorDirectory()}. It will also generate a html file * in the same directory, comparing the screenshot with the first found * reference. - * + * * @param identifier * @throws IOException */ @@ -149,6 +173,27 @@ public abstract class ScreenshotTB3Test extends AbstractTB3Test { deleteFailureFiles(failurePng); } } + if (referenceToKeep != null) { + File errorPng = getErrorFileFromReference(referenceToKeep); + enableAutoswitch(new File(errorPng.getParentFile(), + errorPng.getName() + ".html")); + } + } + + private void enableAutoswitch(File htmlFile) throws FileNotFoundException, + IOException { + if (htmlFile == null || !htmlFile.exists()) { + return; + } + + String html = FileUtils.readFileToString(htmlFile); + + html = html.replace("body onclick=\"", + "body onclick=\"clearInterval(autoSwitch);"); + html = html.replace("</script>", + ";autoSwitch=setInterval(switchImage,500);</script>"); + + FileUtils.writeStringToFile(htmlFile, html); } private void deleteFailureFiles(File failurePng) { @@ -161,7 +206,7 @@ public abstract class ScreenshotTB3Test extends AbstractTB3Test { /** * Returns a new File which points to a .html file instead of the given .png * file - * + * * @param png * @return */ @@ -171,7 +216,7 @@ public abstract class ScreenshotTB3Test extends AbstractTB3Test { } /** - * + * * @param referenceFile * The reference image file (in the directory defined by * {@link #getScreenshotReferenceDirectory()}) @@ -180,14 +225,25 @@ public abstract class ScreenshotTB3Test extends AbstractTB3Test { * given reference image fails. */ private File getErrorFileFromReference(File referenceFile) { - return new File(referenceFile.getAbsolutePath().replace( - getScreenshotReferenceDirectory(), - getScreenshotErrorDirectory())); + + String absolutePath = referenceFile.getAbsolutePath(); + String screenshotReferenceDirectory = getScreenshotReferenceDirectory(); + String screenshotErrorDirectory = getScreenshotErrorDirectory(); + // We throw an exception to safeguard against accidental reference + // deletion. See (#14446) + if (!absolutePath.contains(screenshotReferenceDirectory)) { + throw new IllegalStateException( + "Reference screenshot not in reference directory. Screenshot path: '" + + absolutePath + "', directory path: '" + + screenshotReferenceDirectory + "'"); + } + return new File(absolutePath.replace(screenshotReferenceDirectory, + screenshotErrorDirectory)); } /** * Finds alternative references for the given files - * + * * @param reference * @return all references which should be considered when comparing with the * given files, including the given reference @@ -248,11 +304,23 @@ public abstract class ScreenshotTB3Test extends AbstractTB3Test { protected abstract String getScreenshotDirectory(); /** + * @return the base directory of 'reference' and 'errors' screenshots with a + * trailing file separator + */ + private String getScreenshotDirectoryWithTrailingSeparator() { + String screenshotDirectory = getScreenshotDirectory(); + if (!screenshotDirectory.endsWith(File.separator)) { + screenshotDirectory += File.separator; + } + return screenshotDirectory; + } + + /** * @return the directory where reference images are stored (the 'reference' * folder inside the screenshot directory) */ private String getScreenshotReferenceDirectory() { - return getScreenshotDirectory() + "/reference"; + return getScreenshotDirectoryWithTrailingSeparator() + "reference"; } /** @@ -260,13 +328,13 @@ public abstract class ScreenshotTB3Test extends AbstractTB3Test { * (the 'errors' folder inside the screenshot directory) */ private String getScreenshotErrorDirectory() { - return getScreenshotDirectory() + "/errors"; + return getScreenshotDirectoryWithTrailingSeparator() + "errors"; } /** * Checks if any screenshot comparisons failures occurred during the test * and combines all comparison errors into one exception - * + * * @throws IOException * If there were failures during the test */ @@ -280,48 +348,15 @@ public abstract class ScreenshotTB3Test extends AbstractTB3Test { } - /* - * (non-Javadoc) - * - * @see - * com.vaadin.tests.tb3.AbstractTB3Test#onUncaughtException(java.lang.Throwable - * ) - */ - @Override - public void onUncaughtException(Throwable cause) { - super.onUncaughtException(cause); - // Grab a "failure" screenshot and store in the errors folder for later - // analysis - try { - TestBenchCommands testBench = testBench(); - if (testBench != null) { - testBench.disableWaitForVaadin(); - } - } catch (Throwable t) { - t.printStackTrace(); - } - try { - if (driver != null) { - BufferedImage screenshotImage = ImageIO - .read(new ByteArrayInputStream( - ((TakesScreenshot) driver) - .getScreenshotAs(OutputType.BYTES))); - ImageIO.write(screenshotImage, "png", new File( - getScreenshotFailureName())); - } - } catch (Throwable t) { - t.printStackTrace(); - } - - } - /** * @return the name of a "failure" image which is stored in the folder * defined by {@link #getScreenshotErrorDirectory()} when the test * fails */ private String getScreenshotFailureName() { - return getScreenshotErrorBaseName() + "-failure.png"; + return getScreenshotBaseName() + "_" + + getUniqueIdentifier(getDesiredCapabilities()) + + "-failure.png"; } /** @@ -334,7 +369,7 @@ public abstract class ScreenshotTB3Test extends AbstractTB3Test { /** * Returns the name of the reference file based on the given parameters. - * + * * @param testName * @param capabilities * @param identifier @@ -348,7 +383,7 @@ public abstract class ScreenshotTB3Test extends AbstractTB3Test { * Returns the name of the reference file based on the given parameters. The * version given in {@literal capabilities} is used unless it is overridden * by the {@literal versionOverride} parameter. - * + * * @param testName * @param capabilities * @param identifier @@ -358,20 +393,53 @@ public abstract class ScreenshotTB3Test extends AbstractTB3Test { Integer versionOverride) { String uniqueBrowserIdentifier; if (versionOverride == null) { - uniqueBrowserIdentifier = BrowserUtil - .getUniqueIdentifier(getDesiredCapabilities()); + uniqueBrowserIdentifier = getUniqueIdentifier(getDesiredCapabilities()); } else { - uniqueBrowserIdentifier = BrowserUtil.getUniqueIdentifier( + uniqueBrowserIdentifier = getUniqueIdentifier( getDesiredCapabilities(), "" + versionOverride); } // WindowMaximizeRestoreTest_Windows_InternetExplorer_8_window-1-moved-maximized-restored.png - return getScreenshotReferenceDirectory() + "/" + return getScreenshotReferenceDirectory() + File.separator + getScreenshotBaseName() + "_" + uniqueBrowserIdentifier + "_" + identifier + ".png"; } /** + * Returns a string which uniquely (enough) identifies this browser. Used + * mainly in screenshot names. + * + * @param capabilities + * @param versionOverride + * + * @return a unique string for each browser + */ + private String getUniqueIdentifier(DesiredCapabilities capabilities, + String versionOverride) { + return getUniqueIdentifier(BrowserUtil.getPlatform(capabilities), + BrowserUtil.getBrowserIdentifier(capabilities), versionOverride); + } + + /** + * Returns a string which uniquely (enough) identifies this browser. Used + * mainly in screenshot names. + * + * @param capabilities + * + * @return a unique string for each browser + */ + private String getUniqueIdentifier(DesiredCapabilities capabilities) { + return getUniqueIdentifier(BrowserUtil.getPlatform(capabilities), + BrowserUtil.getBrowserIdentifier(capabilities), + capabilities.getVersion()); + } + + private String getUniqueIdentifier(String platform, String browser, + String version) { + return platform + "_" + browser + "_" + version; + } + + /** * Returns the base name of the screenshot in the error directory. This is a * name so that all files matching {@link #getScreenshotErrorBaseName()}* * are owned by this test instance (taking into account @@ -399,13 +467,12 @@ public abstract class ScreenshotTB3Test extends AbstractTB3Test { errorDirectory.mkdirs(); } - final String errorBase = getScreenshotErrorBaseName() - .replace("\\", "/"); + final String errorBase = getScreenshotErrorBaseName(); File[] files = errorDirectory.listFiles(new FileFilter() { @Override public boolean accept(File pathname) { - String thisFile = pathname.getAbsolutePath().replace("\\", "/"); + String thisFile = pathname.getAbsolutePath(); if (thisFile.startsWith(errorBase)) { return true; } diff --git a/uitest/src/com/vaadin/tests/tb3/ServletIntegrationTests.java b/uitest/src/com/vaadin/tests/tb3/ServletIntegrationTests.java index 294d012be5..c884f69bd1 100644 --- a/uitest/src/com/vaadin/tests/tb3/ServletIntegrationTests.java +++ b/uitest/src/com/vaadin/tests/tb3/ServletIntegrationTests.java @@ -1,12 +1,12 @@ /* * Copyright 2000-2014 Vaadin 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 @@ -16,6 +16,8 @@ package com.vaadin.tests.tb3; +import java.io.IOException; + import org.junit.runner.RunWith; import org.junit.runners.model.InitializationError; @@ -27,7 +29,7 @@ public class ServletIntegrationTests { public static class ServletIntegrationTestSuite extends TB3TestSuite { public ServletIntegrationTestSuite(Class<?> klass) - throws InitializationError { + throws InitializationError, IOException { super(klass, AbstractServletIntegrationTest.class, "com.vaadin.tests.integration", new String[] {}); } diff --git a/uitest/src/com/vaadin/tests/tb3/SingleBrowserTest.java b/uitest/src/com/vaadin/tests/tb3/SingleBrowserTest.java new file mode 100644 index 0000000000..ffb57b5b47 --- /dev/null +++ b/uitest/src/com/vaadin/tests/tb3/SingleBrowserTest.java @@ -0,0 +1,31 @@ +/* + * Copyright 2000-2014 Vaadin 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 com.vaadin.tests.tb3; + +import java.util.Collections; +import java.util.List; + +import org.openqa.selenium.remote.DesiredCapabilities; + +import com.vaadin.testbench.parallel.Browser; + +public abstract class SingleBrowserTest extends PrivateTB3Configuration { + @Override + public List<DesiredCapabilities> getBrowsersToTest() { + return Collections.singletonList(Browser.PHANTOMJS + .getDesiredCapabilities()); + } +}
\ No newline at end of file diff --git a/uitest/src/com/vaadin/tests/tb3/TB3Runner.java b/uitest/src/com/vaadin/tests/tb3/TB3Runner.java index e1693e50d7..23a6370572 100644 --- a/uitest/src/com/vaadin/tests/tb3/TB3Runner.java +++ b/uitest/src/com/vaadin/tests/tb3/TB3Runner.java @@ -16,34 +16,16 @@ package com.vaadin.tests.tb3; -import java.lang.annotation.Annotation; import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.Collection; -import java.util.LinkedList; -import java.util.List; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import org.apache.http.params.HttpConnectionParams; -import org.apache.http.params.HttpParams; -import org.junit.Ignore; -import org.junit.Test; -import org.junit.runners.BlockJUnit4ClassRunner; +import org.apache.http.client.HttpClient; import org.junit.runners.Parameterized; -import org.junit.runners.model.FrameworkMethod; import org.junit.runners.model.InitializationError; -import org.junit.runners.model.Statement; -import org.openqa.selenium.remote.DesiredCapabilities; import org.openqa.selenium.remote.HttpCommandExecutor; import org.openqa.selenium.remote.internal.HttpClientFactory; -import com.vaadin.tests.annotations.TestCategory; -import com.vaadin.tests.tb3.AbstractTB3Test.BrowserUtil; -import com.vaadin.tests.tb3.MultiBrowserTest.Browser; +import com.vaadin.testbench.parallel.ParallelRunner; /** * This runner is loosely based on FactoryTestRunner by Ted Young @@ -53,33 +35,16 @@ import com.vaadin.tests.tb3.MultiBrowserTest.Browser; * * @since 7.1 */ -public class TB3Runner extends BlockJUnit4ClassRunner { +public class TB3Runner extends ParallelRunner { /** * Socket timeout for HTTP connections to the grid hub. The connection is - * closed after 15 minutes of inactivity to avoid builds hanging for up to + * closed after 30 minutes of inactivity to avoid builds hanging for up to * three hours per connection if the test client crashes/hangs. */ - private static final int SOCKET_TIMEOUT = 15 * 60 * 1000; - - /** - * This is the total limit of actual JUnit test instances run in parallel - */ - private static final int MAX_CONCURRENT_TESTS; - - /** - * This is static so it is shared by all tests running concurrently on the - * same machine and thus can limit the number of threads in use. - */ - private static final ExecutorService service; + private static final int SOCKET_TIMEOUT = 30 * 60 * 1000; static { - if (System.getProperty("useLocalWebDriver") != null) { - MAX_CONCURRENT_TESTS = 10; - } else { - MAX_CONCURRENT_TESTS = 50; - } - service = Executors.newFixedThreadPool(MAX_CONCURRENT_TESTS); // reduce socket timeout to avoid tests hanging for three hours try { @@ -89,11 +54,16 @@ public class TB3Runner extends BlockJUnit4ClassRunner { field.setAccessible(true); field.set(null, new HttpClientFactory() { @Override - public HttpParams getHttpParams() { - HttpParams params = super.getHttpParams(); - // fifteen minute timeout - HttpConnectionParams.setSoTimeout(params, SOCKET_TIMEOUT); - return params; + public HttpClient getGridHttpClient(int connection_timeout, + int socket_timeout) { + + if (socket_timeout == 0 || socket_timeout > SOCKET_TIMEOUT) { + return super.getGridHttpClient(connection_timeout, + SOCKET_TIMEOUT); + } + + return super.getGridHttpClient(connection_timeout, + socket_timeout); } }); } catch (Exception e) { @@ -103,311 +73,8 @@ public class TB3Runner extends BlockJUnit4ClassRunner { } } - protected static boolean localWebDriverIsUsed() { - String useLocalWebDriver = System.getProperty("useLocalWebDriver"); - - return useLocalWebDriver != null - && useLocalWebDriver.toLowerCase().equals("true"); - } - public TB3Runner(Class<?> klass) throws InitializationError { super(klass); - setScheduler(new ParallelScheduler(service)); - } - - @Override - protected List<FrameworkMethod> computeTestMethods() { - List<FrameworkMethod> tests = new LinkedList<FrameworkMethod>(); - - if (!AbstractTB3Test.class.isAssignableFrom(getTestClass() - .getJavaClass())) { - throw new RuntimeException(getClass().getName() + " only supports " - + AbstractTB3Test.class.getName()); - } - - try { - AbstractTB3Test testClassInstance = getTestClassInstance(); - Collection<DesiredCapabilities> desiredCapabilities = getDesiredCapabilities(testClassInstance); - - TestNameSuffix testNameSuffixProperty = findAnnotation( - testClassInstance.getClass(), TestNameSuffix.class); - - for (FrameworkMethod m : getTestMethods()) { - // No browsers available for this test, so we need to - // wrap the test method inside IgnoredTestMethod. - // This will add @Ignore annotation to it. - if (desiredCapabilities.size() <= 0 - || categoryIsExcludedOrNotExcplicitlyIncluded()) { - tests.add(new IgnoredTestMethod(m.getMethod())); - } else { - for (DesiredCapabilities capabilities : desiredCapabilities) { - TB3Method method = new TB3Method(m.getMethod(), - capabilities); - if (testNameSuffixProperty != null) { - method.setTestNameSuffix("-" - + System.getProperty(testNameSuffixProperty - .property())); - } - tests.add(method); - } - } - } - } catch (Exception e) { - throw new RuntimeException("Error retrieving browsers to run on", e); - } - - return tests; - } - - private boolean categoryIsExcludedOrNotExcplicitlyIncluded() { - Class<?> c = getTestClass().getJavaClass(); - - if (categoryIsExcluded(c)) { - return true; - } - - if (explicitInclusionIsUsed()) { - return !categoryIsIncluded(c); - } - - return false; - } - - private boolean categoryIsIncluded(Class<?> c) { - String include = System.getProperty("categories.include"); - if (include != null && include.trim().length() > 0) { - return hasCategoryFor(c, include.toLowerCase().trim()); - } - - return false; - } - - private static boolean explicitInclusionIsUsed() { - String include = System.getProperty("categories.include"); - - return include != null && include.trim().length() > 0; - } - - private static boolean categoryIsExcluded(Class<?> c) { - String exclude = System.getProperty("categories.exclude"); - if (exclude != null && exclude.trim().length() > 0) { - return hasCategoryFor(c, exclude.toLowerCase().trim()); - } - - return false; - } - - private static boolean hasCategoryFor(Class<?> c, String searchString) { - if (hasCategory(c)) { - return searchString.contains(getCategory(c).toLowerCase()); - } - - return false; - } - - private static boolean hasCategory(Class<?> c) { - return c.getAnnotation(TestCategory.class) != null; - } - - private static String getCategory(Class<?> c) { - return c.getAnnotation(TestCategory.class).value(); - } - - private List<FrameworkMethod> getTestMethods() { - return getTestClass().getAnnotatedMethods(Test.class); - } - - /* - * Returns a list of desired browser capabilities according to browsers - * defined in the test class, filtered by possible filter parameters. Use - * {@code @RunLocally} annotation or com.vaadin.testbench.runLocally - * property to override all capabilities. - */ - private Collection<DesiredCapabilities> getDesiredCapabilities( - AbstractTB3Test testClassInstance) { - Collection<DesiredCapabilities> desiredCapabilites = getFilteredCapabilities(testClassInstance); - - Browser runLocallyBrowser = testClassInstance.getRunLocallyBrowser(); - if (runLocallyBrowser != null) { - desiredCapabilites = new ArrayList<DesiredCapabilities>(); - desiredCapabilites.add(runLocallyBrowser.getDesiredCapabilities()); - } - - return desiredCapabilites; - } - - /* - * Takes the desired browser capabilities defined in the test class and - * returns a list of browser capabilities filtered browsers.include and - * browsers.exclude system properties. (if present) - */ - private Collection<DesiredCapabilities> getFilteredCapabilities( - AbstractTB3Test testClassInstance) { - Collection<DesiredCapabilities> desiredCapabilites = testClassInstance - .getBrowsersToTest(); - - ArrayList<DesiredCapabilities> filteredCapabilities = new ArrayList<DesiredCapabilities>(); - - String include = System.getProperty("browsers.include"); - String exclude = System.getProperty("browsers.exclude"); - - for (DesiredCapabilities d : desiredCapabilites) { - String browserName = (d.getBrowserName() + d.getVersion()) - .toLowerCase(); - if (include != null && include.trim().length() > 0) { - if (include.trim().toLowerCase().contains(browserName)) { - filteredCapabilities.add(d); - } - } else { - filteredCapabilities.add(d); - } - - if (exclude != null && exclude.trim().length() > 0) { - if (exclude.trim().toLowerCase().contains(browserName)) { - filteredCapabilities.remove(d); - } - } - - } - return filteredCapabilities; - } - - private AbstractTB3Test getTestClassInstance() - throws InstantiationException, IllegalAccessException, - InvocationTargetException { - AbstractTB3Test testClassInstance = (AbstractTB3Test) getTestClass() - .getOnlyConstructor().newInstance(); - return testClassInstance; - } - - // This is a FrameworkMethod class that will always - // return @Ignore and @Test annotations for the wrapped method. - private class IgnoredTestMethod extends FrameworkMethod { - - private class IgnoreTestAnnotations { - - // We use this method to easily get our hands on - // the Annotation instances for @Ignore and @Test - @Ignore - @Test - public void ignoredTest() { - } - } - - public IgnoredTestMethod(Method method) { - super(method); - } - - @Override - public Annotation[] getAnnotations() { - return getIgnoredTestMethod().getAnnotations(); - } - - private Method getIgnoredTestMethod() { - try { - return IgnoreTestAnnotations.class.getMethod("ignoredTest", - null); - } catch (Exception e) { - return null; - } - - } - - @Override - public <T extends Annotation> T getAnnotation(Class<T> annotationType) { - return getIgnoredTestMethod().getAnnotation(annotationType); - } - } - - /** - * Finds the given annotation in the given class or one of its super - * classes. Return the first found annotation - * - * @param searchClass - * @param annotationClass - * @return - */ - private <T extends Annotation> T findAnnotation(Class<?> searchClass, - Class<T> annotationClass) { - if (searchClass == Object.class) { - return null; - } - - if (searchClass.getAnnotation(annotationClass) != null) { - return searchClass.getAnnotation(annotationClass); - } - - return findAnnotation(searchClass.getSuperclass(), annotationClass); - } - - /* - * (non-Javadoc) - * - * @see - * org.junit.runners.BlockJUnit4ClassRunner#withBefores(org.junit.runners - * .model.FrameworkMethod, java.lang.Object, - * org.junit.runners.model.Statement) - */ - @Override - protected Statement withBefores(final FrameworkMethod method, - final Object target, Statement statement) { - if (!(method instanceof TB3Method)) { - throw new RuntimeException("Unexpected method type " - + method.getClass().getName() + ", expected TB3Method"); - } - final TB3Method tb3method = (TB3Method) method; - - // setDesiredCapabilities before running the real @Befores (which use - // capabilities) - - final Statement realBefores = super.withBefores(method, target, - statement); - return new Statement() { - - @Override - public void evaluate() throws Throwable { - ((AbstractTB3Test) target) - .setDesiredCapabilities(tb3method.capabilities); - try { - realBefores.evaluate(); - } catch (Throwable t) { - // Give the test a chance to e.g. produce an error - // screenshot before failing the test by re-throwing the - // exception - ((AbstractTB3Test) target).onUncaughtException(t); - throw t; - } - } - }; - } - - private static class TB3Method extends FrameworkMethod { - private DesiredCapabilities capabilities; - private String testNameSuffix = ""; - - public TB3Method(Method method, DesiredCapabilities capabilities) { - super(method); - this.capabilities = capabilities; - } - - public void setTestNameSuffix(String testNameSuffix) { - this.testNameSuffix = testNameSuffix; - } - - @Override - public Object invokeExplosively(final Object target, Object... params) - throws Throwable { - // Executes the test method with the supplied parameters - return super.invokeExplosively(target); - } - - @Override - public String getName() { - return String.format("%s[%s]", getMethod().getName() - + testNameSuffix, - BrowserUtil.getUniqueIdentifier(capabilities)); - } - } } diff --git a/uitest/src/com/vaadin/tests/tb3/TB3TestLocator.java b/uitest/src/com/vaadin/tests/tb3/TB3TestLocator.java new file mode 100644 index 0000000000..b102309fc1 --- /dev/null +++ b/uitest/src/com/vaadin/tests/tb3/TB3TestLocator.java @@ -0,0 +1,218 @@ +/* + * Copyright 2000-2014 Vaadin 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 com.vaadin.tests.tb3; + +import java.io.File; +import java.io.IOException; +import java.lang.reflect.Modifier; +import java.net.JarURLConnection; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.Enumeration; +import java.util.List; +import java.util.jar.JarEntry; + +public class TB3TestLocator { + /** + * Traverses the directory on the classpath (inside or outside a Jar file) + * specified by 'basePackage'. Collects all classes inside the location + * which can be assigned to 'baseClass' except for classes inside packages + * listed in 'ignoredPackages'. + * + * @param baseClass + * @param basePackage + * @param ignorePackages + * @return + */ + public Class<?>[] findTests(Class<? extends AbstractTB3Test> baseClass, + String basePackage, String[] ignorePackages) { + try { + List<?> l = findClasses(baseClass, basePackage, ignorePackages); + return l.toArray(new Class[] {}); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return null; + } + + /** + * Traverses the directory on the classpath (inside or outside a Jar file) + * specified by 'basePackage'. Collects all classes inside the location + * which can be assigned to 'baseClass' except for classes inside packages + * listed in 'ignoredPackages'. + * + * @param baseClass + * @param basePackage + * @param ignoredPackages + * @return + * @throws IOException + */ + protected <T> List<Class<? extends T>> findClasses(Class<T> baseClass, + String basePackage, String[] ignoredPackages) throws IOException { + List<Class<? extends T>> classes = new ArrayList<Class<? extends T>>(); + String basePackageDirName = "/" + basePackage.replace('.', '/'); + URL location = baseClass.getResource(basePackageDirName); + if (location.getProtocol().equals("file")) { + try { + File f = new File(location.toURI()); + if (!f.exists()) { + throw new IOException("Directory " + f.toString() + + " does not exist"); + } + findPackages(f, basePackage, baseClass, classes, + ignoredPackages); + } catch (URISyntaxException e) { + throw new IOException(e.getMessage()); + } + } else if (location.getProtocol().equals("jar")) { + JarURLConnection juc = (JarURLConnection) location.openConnection(); + findClassesInJar(juc, basePackage, baseClass, classes); + } + + Collections.sort(classes, new Comparator<Class<? extends T>>() { + + @Override + public int compare(Class<? extends T> o1, Class<? extends T> o2) { + return o1.getName().compareTo(o2.getName()); + } + + }); + + return classes; + } + + /** + * Traverses the given directory and collects all classes which are inside + * the given 'javaPackage' and can be assigned to the given 'baseClass'. The + * found classes are added to 'result'. + * + * @param parent + * The directory to traverse + * @param javaPackage + * The java package which 'parent' contains + * @param baseClass + * The class which the target classes extend + * @param result + * The collection to which found classes are added + * @param ignoredPackages + * A collection of packages (including sub packages) to ignore + */ + private <T> void findPackages(File parent, String javaPackage, + Class<T> baseClass, Collection<Class<? extends T>> result, + String[] ignoredPackages) { + for (String ignoredPackage : ignoredPackages) { + if (javaPackage.equals(ignoredPackage)) { + return; + } + } + + for (File file : parent.listFiles()) { + if (file.isDirectory()) { + findPackages(file, javaPackage + "." + file.getName(), + baseClass, result, ignoredPackages); + } else if (file.getName().endsWith(".class")) { + String fullyQualifiedClassName = javaPackage + "." + + file.getName().replace(".class", ""); + addClassIfMatches(result, fullyQualifiedClassName, baseClass); + } + } + + } + + /** + * Traverses a Jar file using the given connection and collects all classes + * which are inside the given 'javaPackage' and can be assigned to the given + * 'baseClass'. The found classes are added to 'result'. + * + * @param javaPackage + * The java package containing the classes (classes may be in a + * sub package) + * @param baseClass + * The class which the target classes extend + * @param result + * The collection to which found classes are added + * @throws IOException + */ + private <T> void findClassesInJar(JarURLConnection juc, String javaPackage, + Class<T> baseClass, Collection<Class<? extends T>> result) + throws IOException { + String javaPackageDir = javaPackage.replace('.', '/'); + Enumeration<JarEntry> ent = juc.getJarFile().entries(); + while (ent.hasMoreElements()) { + JarEntry e = ent.nextElement(); + if (e.getName().endsWith(".class") + && e.getName().startsWith(javaPackageDir)) { + String fullyQualifiedClassName = e.getName().replace('/', '.') + .replace(".class", ""); + addClassIfMatches(result, fullyQualifiedClassName, baseClass); + } + } + } + + /** + * Verifies that the class represented by 'fullyQualifiedClassName' can be + * loaded, assigned to 'baseClass' and is not an abstract or anonymous + * class. + * + * @param result + * The collection to add to + * @param fullyQualifiedClassName + * The candidate class + * @param baseClass + * The class 'fullyQualifiedClassName' should be assignable to + */ + @SuppressWarnings("unchecked") + protected <T> void addClassIfMatches(Collection<Class<? extends T>> result, + String fullyQualifiedClassName, Class<T> baseClass) { + try { + // Try to load the class + + Class<?> c = Class.forName(fullyQualifiedClassName); + if (!baseClass.isAssignableFrom(c)) { + return; + } + if (!includeInSuite(c)) { + return; + } + + if (!Modifier.isAbstract(c.getModifiers()) && !c.isAnonymousClass()) { + result.add((Class<? extends T>) c); + } + } catch (Exception e) { + // Could ignore that class cannot be loaded + e.printStackTrace(); + } catch (LinkageError e) { + // Ignore. Client side classes will at least throw LinkageErrors + } + + } + + /** + * @return true if the class should be included in the suite, false if not + */ + private boolean includeInSuite(Class<?> c) { + if (c.getAnnotation(ExcludeFromSuite.class) != null) { + return false; + } + + return true; + } +}
\ No newline at end of file diff --git a/uitest/src/com/vaadin/tests/tb3/TB3TestSuite.java b/uitest/src/com/vaadin/tests/tb3/TB3TestSuite.java index 703d01c122..8f6a29d275 100644 --- a/uitest/src/com/vaadin/tests/tb3/TB3TestSuite.java +++ b/uitest/src/com/vaadin/tests/tb3/TB3TestSuite.java @@ -1,252 +1,46 @@ /* * Copyright 2000-2014 Vaadin 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 com.vaadin.tests.tb3; -import java.io.File; import java.io.IOException; -import java.lang.reflect.Modifier; -import java.net.JarURLConnection; -import java.net.URISyntaxException; -import java.net.URL; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.Enumeration; -import java.util.List; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.jar.JarEntry; -import org.junit.runners.Suite; import org.junit.runners.model.InitializationError; +import com.vaadin.testbench.parallel.ParallelTestSuite; + /** * Test suite which consists of all the TB3 tests passed in the constructor. * Runs the tests in parallel using a {@link ParallelScheduler} - * + * * @author Vaadin Ltd */ -public class TB3TestSuite extends Suite { - - /** - * This only restricts the number of test suites running concurrently. The - * number of tests to run concurrently are configured in {@link TB3Runner}. - */ - private static final int MAX_CONCURRENT_TEST_SUITES = 20; - - /** - * This is static so it is shared by all test suites running concurrently on - * the same machine and thus can limit the number of threads in use. - */ - private final ExecutorService service = Executors - .newFixedThreadPool(MAX_CONCURRENT_TEST_SUITES); - +public class TB3TestSuite extends ParallelTestSuite { public TB3TestSuite(Class<?> klass, Class<? extends AbstractTB3Test> baseClass, String basePackage, - String[] ignorePackages) throws InitializationError { - super(klass, findTests(baseClass, basePackage, ignorePackages)); - setScheduler(new ParallelScheduler(service)); + String[] ignorePackages) throws InitializationError, IOException { + this(klass, baseClass, basePackage, ignorePackages, + new TB3TestLocator()); } - /** - * Traverses the directory on the classpath (inside or outside a Jar file) - * specified by 'basePackage'. Collects all classes inside the location - * which can be assigned to 'baseClass' except for classes inside packages - * listed in 'ignoredPackages'. - * - * @param baseClass - * @param basePackage - * @param ignorePackages - * @return - */ - private static Class<?>[] findTests( + public TB3TestSuite(Class<?> klass, Class<? extends AbstractTB3Test> baseClass, String basePackage, - String[] ignorePackages) { - try { - List<?> l = findClasses(baseClass, basePackage, ignorePackages); - return l.toArray(new Class[] {}); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - return null; - } - - /** - * Traverses the directory on the classpath (inside or outside a Jar file) - * specified by 'basePackage'. Collects all classes inside the location - * which can be assigned to 'baseClass' except for classes inside packages - * listed in 'ignoredPackages'. - * - * @param baseClass - * @param basePackage - * @param ignoredPackages - * @return - * @throws IOException - */ - private static <T> List<Class<? extends T>> findClasses(Class<T> baseClass, - String basePackage, String[] ignoredPackages) throws IOException { - List<Class<? extends T>> classes = new ArrayList<Class<? extends T>>(); - String basePackageDirName = "/" + basePackage.replace('.', '/'); - URL location = baseClass.getResource(basePackageDirName); - if (location.getProtocol().equals("file")) { - try { - File f = new File(location.toURI()); - if (!f.exists()) { - throw new IOException("Directory " + f.toString() - + " does not exist"); - } - findPackages(f, basePackage, baseClass, classes, - ignoredPackages); - } catch (URISyntaxException e) { - throw new IOException(e.getMessage()); - } - } else if (location.getProtocol().equals("jar")) { - JarURLConnection juc = (JarURLConnection) location.openConnection(); - findClassesInJar(juc, basePackage, baseClass, classes); - } - - Collections.sort(classes, new Comparator<Class<? extends T>>() { - - @Override - public int compare(Class<? extends T> o1, Class<? extends T> o2) { - return o1.getName().compareTo(o2.getName()); - } - - }); - return classes; - } - - /** - * Traverses the given directory and collects all classes which are inside - * the given 'javaPackage' and can be assigned to the given 'baseClass'. The - * found classes are added to 'result'. - * - * @param parent - * The directory to traverse - * @param javaPackage - * The java package which 'parent' contains - * @param baseClass - * The class which the target classes extend - * @param result - * The collection to which found classes are added - * @param ignoredPackages - * A collection of packages (including sub packages) to ignore - */ - private static <T> void findPackages(File parent, String javaPackage, - Class<T> baseClass, Collection<Class<? extends T>> result, - String[] ignoredPackages) { - for (String ignoredPackage : ignoredPackages) { - if (javaPackage.equals(ignoredPackage)) { - return; - } - } - - for (File file : parent.listFiles()) { - if (file.isDirectory()) { - findPackages(file, javaPackage + "." + file.getName(), - baseClass, result, ignoredPackages); - } else if (file.getName().endsWith(".class")) { - String fullyQualifiedClassName = javaPackage + "." - + file.getName().replace(".class", ""); - addClassIfMatches(result, fullyQualifiedClassName, baseClass); - } - } - - } - - /** - * Traverses a Jar file using the given connection and collects all classes - * which are inside the given 'javaPackage' and can be assigned to the given - * 'baseClass'. The found classes are added to 'result'. - * - * @param javaPackage - * The java package containing the classes (classes may be in a - * sub package) - * @param baseClass - * The class which the target classes extend - * @param result - * The collection to which found classes are added - * @throws IOException - */ - private static <T> void findClassesInJar(JarURLConnection juc, - String javaPackage, Class<T> baseClass, - Collection<Class<? extends T>> result) throws IOException { - String javaPackageDir = javaPackage.replace('.', '/'); - Enumeration<JarEntry> ent = juc.getJarFile().entries(); - while (ent.hasMoreElements()) { - JarEntry e = ent.nextElement(); - if (e.getName().endsWith(".class") - && e.getName().startsWith(javaPackageDir)) { - String fullyQualifiedClassName = e.getName().replace('/', '.') - .replace(".class", ""); - addClassIfMatches(result, fullyQualifiedClassName, baseClass); - } - } - } - - /** - * Verifies that the class represented by 'fullyQualifiedClassName' can be - * loaded, assigned to 'baseClass' and is not an abstract or anonymous - * class. - * - * @param result - * The collection to add to - * @param fullyQualifiedClassName - * The candidate class - * @param baseClass - * The class 'fullyQualifiedClassName' should be assignable to - */ - @SuppressWarnings("unchecked") - private static <T> void addClassIfMatches( - Collection<Class<? extends T>> result, - String fullyQualifiedClassName, Class<T> baseClass) { - try { - // Try to load the class - - Class<?> c = Class.forName(fullyQualifiedClassName); - if (!baseClass.isAssignableFrom(c)) { - return; - } - if (!includeInSuite(c)) { - return; - } - - if (!Modifier.isAbstract(c.getModifiers()) && !c.isAnonymousClass()) { - result.add((Class<? extends T>) c); - } - } catch (Exception e) { - // Could ignore that class cannot be loaded - e.printStackTrace(); - } catch (LinkageError e) { - // Ignore. Client side classes will at least throw LinkageErrors - } - - } - - /** - * @return true if the class should be included in the suite, false if not - */ - private static boolean includeInSuite(Class<?> c) { - if (c.getAnnotation(ExcludeFromSuite.class) != null) { - return false; - } - - return true; + String[] ignorePackages, TB3TestLocator locator) + throws InitializationError, IOException { + super(klass, locator + .findClasses(baseClass, basePackage, ignorePackages).toArray( + new Class<?>[] {})); } -} +}
\ No newline at end of file diff --git a/uitest/src/com/vaadin/tests/tb3/VaadinBrowserFactory.java b/uitest/src/com/vaadin/tests/tb3/VaadinBrowserFactory.java new file mode 100644 index 0000000000..d3e02d378d --- /dev/null +++ b/uitest/src/com/vaadin/tests/tb3/VaadinBrowserFactory.java @@ -0,0 +1,60 @@ +/* + * Copyright 2000-2014 Vaadin 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 com.vaadin.tests.tb3; + +import org.openqa.selenium.Platform; +import org.openqa.selenium.ie.InternetExplorerDriver; +import org.openqa.selenium.remote.DesiredCapabilities; + +import com.vaadin.testbench.parallel.Browser; +import com.vaadin.testbench.parallel.DefaultBrowserFactory; + +public class VaadinBrowserFactory extends DefaultBrowserFactory { + + @Override + public DesiredCapabilities create(Browser browser) { + switch (browser) { + case IE8: + return createIE(browser, "8"); + case IE9: + return createIE(browser, "9"); + case IE10: + return createIE(browser, "10"); + case IE11: + return createIE(browser, "11"); + case PHANTOMJS: + return create(browser, "1", Platform.LINUX); + case CHROME: + return create(browser, "40", Platform.VISTA); + case FIREFOX: + default: + return create(browser, "24", Platform.XP); + } + } + + private DesiredCapabilities createIE(Browser browser, String version) { + DesiredCapabilities capabilities = create(browser, version, + Platform.WINDOWS); + capabilities.setCapability( + InternetExplorerDriver.IE_ENSURE_CLEAN_SESSION, true); + return capabilities; + } + + @Override + public DesiredCapabilities create(Browser browser, String version) { + return create(browser); + } +} diff --git a/uitest/src/com/vaadin/tests/tb3/WebsocketTest.java b/uitest/src/com/vaadin/tests/tb3/WebsocketTest.java index 778c8b9113..df95b1b087 100644 --- a/uitest/src/com/vaadin/tests/tb3/WebsocketTest.java +++ b/uitest/src/com/vaadin/tests/tb3/WebsocketTest.java @@ -1,64 +1,39 @@ /* * Copyright 2000-2014 Vaadin 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 com.vaadin.tests.tb3; -import java.util.ArrayList; -import java.util.Collections; import java.util.List; import org.openqa.selenium.remote.DesiredCapabilities; -import com.vaadin.tests.annotations.TestCategory; -import com.vaadin.tests.tb3.MultiBrowserTest.Browser; +import com.vaadin.testbench.parallel.TestCategory; /** * A {@link MultiBrowserTest} which restricts the tests to the browsers which * support websocket - * + * * @author Vaadin Ltd */ @TestCategory("push") -public abstract class WebsocketTest extends PrivateTB3Configuration { - private static List<DesiredCapabilities> websocketBrowsers = new ArrayList<DesiredCapabilities>(); - static { - websocketBrowsers.addAll(MultiBrowserTest.getAllBrowsers()); - websocketBrowsers.remove(Browser.IE8.getDesiredCapabilities()); - websocketBrowsers.remove(Browser.IE9.getDesiredCapabilities()); - websocketBrowsers.remove(Browser.PHANTOMJS.getDesiredCapabilities()); - } - - /** - * @return All supported browsers which are actively tested and support - * websockets - */ - public static List<DesiredCapabilities> getWebsocketBrowsers() { - return Collections.unmodifiableList(websocketBrowsers); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.tests.tb3.AbstractTB3Test#getBrowserToRunOn() - */ +public abstract class WebsocketTest extends MultiBrowserTest { @Override public List<DesiredCapabilities> getBrowsersToTest() { - return new ArrayList<DesiredCapabilities>(getWebsocketBrowsers()); + return getBrowsersSupportingWebSocket(); } -} +}
\ No newline at end of file diff --git a/uitest/src/com/vaadin/tests/widgetset/server/gwtrpc/GwtRpcTest.java b/uitest/src/com/vaadin/tests/widgetset/server/gwtrpc/GwtRpcTest.java index d27884a13a..b2aec030a5 100644 --- a/uitest/src/com/vaadin/tests/widgetset/server/gwtrpc/GwtRpcTest.java +++ b/uitest/src/com/vaadin/tests/widgetset/server/gwtrpc/GwtRpcTest.java @@ -36,7 +36,7 @@ public class GwtRpcTest extends MultiBrowserTest { By label = By.id(GwtRpcButtonConnector.SUCCESS_LABEL_ID); - waitForElementToBePresent(label); + waitForElementPresent(label); getDriver().findElement(label); } diff --git a/uitest/tb3test.xml b/uitest/tb3test.xml index 6e0f25a8f7..edf1283f64 100644 --- a/uitest/tb3test.xml +++ b/uitest/tb3test.xml @@ -1,45 +1,43 @@ <?xml version="1.0"?> <project name="tb3test" xmlns:antcontrib="antlib:net.sf.antcontrib" xmlns:ivy="antlib:org.apache.ivy.ant" basedir="."> - - <dirname property="tb3test.dir" file="${ant.file.tb3test}" /> - <property name="report.dir" location="${tb3test.dir}/result/reports-tb3" /> - <property name="browsers.include" value="" /> - <property name="browsers.exclude" value="" /> - <property name="categories.include" value="" /> - <property name="categories.exclude" value="" /> - - <ivy:resolve file="${tb3test.dir}/ivy.xml" conf="build, build-provided" /> - <ivy:cachepath pathid="classpath.tb3.lib" conf="build, build-provided" /> - <path id="classpath.tb3"> - <path refid="classpath.tb3.lib" /> - <path location="${tb3test.dir}/result/classes" /> - </path> - - <target name="run-all-tb3-tests" unless="tests.tb3.skip" description="Run all the TB3 tests (except server tests) in the project"> - <antcall target="run-tb3-suite"> - <param name="junit.test.suite" value="com.vaadin.tests.tb3.AllTB3Tests" /> - </antcall> - </target> - - <target name="run-tb3-suite"> - <fail unless="junit.test.suite" message="Define suite to run using junit.test.suite" /> - <fail unless="com.vaadin.testbench.screenshot.directory" message="Define screenshot directory using -Dcom.vaadin.testbench.screenshot.directory" /> - <delete dir="${report.dir}" /> - <mkdir dir="${report.dir}" /> - - <junit showoutput="no" printsummary="no" fork="yes"> - <formatter type="xml" /> - <classpath refid="classpath.tb3" /> - - <jvmarg value="-Dcom.vaadin.testbench.screenshot.directory=${com.vaadin.testbench.screenshot.directory}" /> - <jvmarg value="-Djava.awt.headless=true" /> - <jvmarg value="-Dbrowsers.include=${browsers.include}" /> - <jvmarg value="-Dbrowsers.exclude=${browsers.exclude}" /> - <jvmarg value="-Dcategories.include=${categories.include}" /> - <jvmarg value="-Dcategories.exclude=${categories.exclude}" /> - <test name="${junit.test.suite}" todir="${report.dir}" /> - </junit> - - </target> - -</project> + <dirname property="tb3test.dir" file="${ant.file.tb3test}" /> + <property name="report.dir" location="${tb3test.dir}/result/reports-tb3" /> + <property name="browsers.include" value="" /> + <property name="browsers.exclude" value="" /> + <property name="categories.include" value="" /> + <property name="categories.exclude" value="" /> + <property name="useLocalWebDriver" value="false" /> + <property name="com.vaadin.testbench.max.retries" value="0" /> + <property name="com.vaadin.testbench.hub.url" value="" /> + <property name="vaadin.testbench.developer.license" value="" /> + <property name="junit.test.suite" value="com.vaadin.tests.tb3.AllTB3Tests" /> + <ivy:resolve file="${tb3test.dir}/ivy.xml" conf="build, build-provided" /> + <ivy:cachepath pathid="classpath.tb3.lib" conf="build, build-provided" /> + <path id="classpath.tb3"> + <path refid="classpath.tb3.lib" /> + <path location="${tb3test.dir}/result/classes" /> + </path> + <target name="run-all-tb3-tests" unless="tests.tb3.skip" description="Run all the TB3 tests (except server tests) in the project"> + <antcall target="run-tb3-suite" /> + </target> + <target name="run-tb3-suite"> + <fail unless="com.vaadin.testbench.screenshot.directory" message="Define screenshot directory using -Dcom.vaadin.testbench.screenshot.directory" /> + <delete dir="${report.dir}" /> + <mkdir dir="${report.dir}" /> + <junit showoutput="no" printsummary="no" fork="yes"> + <formatter type="xml" /> + <classpath refid="classpath.tb3" /> + <jvmarg value="-Dcom.vaadin.testbench.screenshot.directory=${com.vaadin.testbench.screenshot.directory}" /> + <jvmarg value="-Djava.awt.headless=true" /> + <jvmarg value="-Dbrowsers.include=${browsers.include}" /> + <jvmarg value="-Dbrowsers.exclude=${browsers.exclude}" /> + <jvmarg value="-Dcategories.include=${categories.include}" /> + <jvmarg value="-Dcategories.exclude=${categories.exclude}" /> + <jvmarg value="-DuseLocalWebDriver=${useLocalWebDriver}" /> + <jvmarg value="-Dcom.vaadin.testbench.max.retries=${com.vaadin.testbench.max.retries}" /> + <jvmarg value="-Dcom.vaadin.testbench.hub.url=${com.vaadin.testbench.hub.url}" /> + <jvmarg value="-Dvaadin.testbench.developer.license=${vaadin.testbench.developer.license}" /> + <test name="${junit.test.suite}" todir="${report.dir}" /> + </junit> + </target> +</project>
\ No newline at end of file |