diff options
-rw-r--r-- | client/src/com/vaadin/client/ApplicationConnection.java | 89 | ||||
-rw-r--r-- | client/src/com/vaadin/client/Util.java | 55 | ||||
-rw-r--r-- | client/src/com/vaadin/client/ui/VPanel.java | 44 | ||||
-rw-r--r-- | client/src/com/vaadin/client/ui/VTabsheet.java | 3 | ||||
-rw-r--r-- | client/src/com/vaadin/client/ui/VWindow.java | 32 | ||||
-rw-r--r-- | client/src/com/vaadin/client/ui/ui/UIConnector.java | 25 | ||||
-rw-r--r-- | liferay/build.xml | 6 | ||||
-rw-r--r-- | uitest/src/com/vaadin/tests/components/tabsheet/TabSheetErrorTooltip.java | 60 | ||||
-rw-r--r-- | uitest/src/com/vaadin/tests/components/tabsheet/TabSheetErrorTooltipTest.java | 81 | ||||
-rw-r--r-- | uitest/src/com/vaadin/tests/components/window/ComboboxScrollableWindow.java | 66 | ||||
-rw-r--r-- | uitest/src/com/vaadin/tests/components/window/ComboboxScrollableWindowTest.java | 57 | ||||
-rw-r--r-- | uitest/src/com/vaadin/tests/tb3/ScreenshotTB3Test.java | 56 | ||||
-rw-r--r-- | uitest/tb3test.xml | 9 | ||||
-rw-r--r-- | uitest/test.xml | 10 |
14 files changed, 472 insertions, 121 deletions
diff --git a/client/src/com/vaadin/client/ApplicationConnection.java b/client/src/com/vaadin/client/ApplicationConnection.java index 08c755ef79..da41543894 100644 --- a/client/src/com/vaadin/client/ApplicationConnection.java +++ b/client/src/com/vaadin/client/ApplicationConnection.java @@ -26,6 +26,7 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.logging.Logger; import com.google.gwt.aria.client.LiveValue; import com.google.gwt.aria.client.RelevantValue; @@ -64,6 +65,7 @@ import com.google.gwt.user.client.Window.ClosingHandler; import com.google.gwt.user.client.ui.HasWidgets; import com.google.gwt.user.client.ui.Widget; import com.vaadin.client.ApplicationConfiguration.ErrorMessage; +import com.vaadin.client.ApplicationConnection.ApplicationStoppedEvent; import com.vaadin.client.ResourceLoader.ResourceLoadEvent; import com.vaadin.client.ResourceLoader.ResourceLoadListener; import com.vaadin.client.communication.HasJavaScriptConnectorHelper; @@ -290,7 +292,7 @@ public class ApplicationConnection { } @Override - public com.google.gwt.event.shared.GwtEvent.Type<CommunicationHandler> getAssociatedType() { + public Type<CommunicationHandler> getAssociatedType() { return TYPE; } @@ -310,7 +312,7 @@ public class ApplicationConnection { } @Override - public com.google.gwt.event.shared.GwtEvent.Type<CommunicationHandler> getAssociatedType() { + public Type<CommunicationHandler> getAssociatedType() { return TYPE; } @@ -345,7 +347,7 @@ public class ApplicationConnection { public static Type<CommunicationHandler> TYPE = new Type<CommunicationHandler>(); @Override - public com.google.gwt.event.shared.GwtEvent.Type<CommunicationHandler> getAssociatedType() { + public Type<CommunicationHandler> getAssociatedType() { return TYPE; } @@ -356,6 +358,34 @@ public class ApplicationConnection { } /** + * Event triggered when a application is stopped by calling + * {@link ApplicationConnection#setApplicationRunning(false)}. + * + * To listen for the event add a {@link ApplicationStoppedHandler} by + * invoking + * {@link ApplicationConnection#addHandler(ApplicationStoppedEvent.Type, ApplicationStoppedHandler)} + * to the {@link ApplicationConnection} + * + * @since 7.1.8 + * @author Vaadin Ltd + */ + public static class ApplicationStoppedEvent extends + GwtEvent<ApplicationStoppedHandler> { + + public static Type<ApplicationStoppedHandler> TYPE = new Type<ApplicationStoppedHandler>(); + + @Override + public Type<ApplicationStoppedHandler> getAssociatedType() { + return TYPE; + } + + @Override + protected void dispatch(ApplicationStoppedHandler listener) { + listener.onApplicationStopped(this); + } + } + + /** * Allows custom handling of communication errors. */ public interface CommunicationErrorHandler { @@ -373,6 +403,27 @@ public class ApplicationConnection { public boolean onError(String details, int statusCode); } + /** + * A listener for listening to application stopped events. The listener can + * be added to a {@link ApplicationConnection} by invoking + * {@link ApplicationConnection#addHandler(ApplicationStoppedEvent.Type, ApplicationStoppedHandler)} + * + * @since 7.1.8 + * @author Vaadin Ltd + */ + public interface ApplicationStoppedHandler extends EventHandler { + + /** + * Triggered when the {@link ApplicationConnection} marks a previously + * running application as stopped by invoking + * {@link ApplicationConnection#setApplicationRunning(false)} + * + * @param event + * the event triggered by the {@link ApplicationConnection} + */ + void onApplicationStopped(ApplicationStoppedEvent event); + } + private CommunicationErrorHandler communicationErrorDelegate = null; private VLoadingIndicator loadingIndicator; @@ -756,6 +807,10 @@ public class ApplicationConnection { showCommunicationError(details, statusCode); } endRequest(); + + // Consider application not running any more and prevent all + // future requests + setApplicationRunning(false); } @Override @@ -887,10 +942,10 @@ public class ApplicationConnection { VConsole.log("JSON parsing took " + (new Date().getTime() - start.getTime()) + "ms"); - if (applicationRunning) { + if (isApplicationRunning()) { handleReceivedJSONMessage(start, jsonText, json); } else { - applicationRunning = true; + setApplicationRunning(true); handleWhenCSSLoaded(jsonText, json); } } @@ -1149,7 +1204,7 @@ public class ApplicationConnection { retryCanceledActiveRequest = false; webkitMaybeIgnoringRequests = false; - if (applicationRunning) { + if (isApplicationRunning()) { checkForPendingVariableBursts(); runPostRequestHooks(configuration.getRootPanelId()); } @@ -1499,7 +1554,7 @@ public class ApplicationConnection { error.getString("message"), error.getString("url")); - applicationRunning = false; + setApplicationRunning(false); } Profiler.leave("Error handling"); } @@ -2422,6 +2477,12 @@ public class ApplicationConnection { */ public void addMethodInvocationToQueue(MethodInvocation invocation, boolean delayed, boolean lastOnly) { + if (!isApplicationRunning()) { + getLogger() + .warning( + "Trying to invoke method on not yet started or stopped application"); + return; + } String tag; if (lastOnly) { tag = invocation.getLastOnlyTag(); @@ -2480,7 +2541,7 @@ public class ApplicationConnection { private boolean deferedSendPending = false; private void doSendPendingVariableChanges() { - if (applicationRunning) { + if (isApplicationRunning()) { if (hasActiveRequest() || (push != null && !push.isActive())) { // skip empty queues if there are pending bursts to be sent if (pendingInvocations.size() > 0 || pendingBursts.size() == 0) { @@ -2492,6 +2553,11 @@ public class ApplicationConnection { } else { buildAndSendVariableBurst(pendingInvocations); } + } else { + getLogger() + .warning( + "Trying to send variable changes from not yet started or stopped application"); + return; } } @@ -3393,6 +3459,9 @@ public class ApplicationConnection { } public void setApplicationRunning(boolean running) { + if (applicationRunning && !running) { + eventBus.fireEvent(new ApplicationStoppedEvent()); + } applicationRunning = running; } @@ -3495,4 +3564,8 @@ public class ApplicationConnection { } } + private static Logger getLogger() { + return Logger.getLogger(ApplicationConnection.class.getName()); + } + } diff --git a/client/src/com/vaadin/client/Util.java b/client/src/com/vaadin/client/Util.java index 8972670232..8a5712215d 100644 --- a/client/src/com/vaadin/client/Util.java +++ b/client/src/com/vaadin/client/Util.java @@ -32,6 +32,7 @@ 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.user.client.Command; import com.google.gwt.user.client.DOM; @@ -518,6 +519,60 @@ public class Util { } /** + * Prevents some browsers from adding scroll bars to a component (such as a + * Window) whose contents fit in the component. + * <p> + * See: bugs #11994 and #12736. + * + * @param contentNode + * an element that contains a scrollable element as its first + * child + * + * @since 7.1.8 + */ + public static void removeUnneededScrollbars(final Element contentNode) { + if (BrowserInfo.get().isWebkit()) { + + /* + * Shake up the DOM a bit to make the window shed unnecessary + * scrollbars and resize correctly afterwards. This resulting code + * took over a week to summon forth, and involved some pretty hairy + * black magic. Don't touch it unless you know what you're doing! + * Fixes ticket #11994. Later modified to fix ticket #12736. + */ + Scheduler.get().scheduleFinally(new ScheduledCommand() { + + @Override + public void execute() { + final com.google.gwt.dom.client.Element scrollable = contentNode + .getFirstChildElement(); + + // Adjusting the width or height may change the scroll + // position, so store the current position + int horizontalScrollPosition = scrollable.getScrollLeft(); + int verticalScrollPosition = scrollable.getScrollTop(); + + final String oldWidth = scrollable.getStyle().getWidth(); + final String oldHeight = scrollable.getStyle().getHeight(); + + scrollable.getStyle().setWidth(110, Unit.PCT); + scrollable.getStyle().setHeight(110, Unit.PCT); + scrollable.getOffsetWidth(); + scrollable.getOffsetHeight(); + scrollable.getStyle().setProperty("width", oldWidth); + scrollable.getStyle().setProperty("height", oldHeight); + + // Restore the scroll position + scrollable.setScrollLeft(horizontalScrollPosition); + scrollable.setScrollTop(verticalScrollPosition); + + } + }); + + } + } + + /** * Parses shared state and fetches the relative size of the component. If a * dimension is not specified as relative it will return -1. If the shared * state does not contain width or height specifications this will return diff --git a/client/src/com/vaadin/client/ui/VPanel.java b/client/src/com/vaadin/client/ui/VPanel.java index 15c3883b11..307a2e4a91 100644 --- a/client/src/com/vaadin/client/ui/VPanel.java +++ b/client/src/com/vaadin/client/ui/VPanel.java @@ -16,18 +16,15 @@ package com.vaadin.client.ui; -import com.google.gwt.core.client.Scheduler; -import com.google.gwt.core.client.Scheduler.ScheduledCommand; import com.google.gwt.dom.client.DivElement; import com.google.gwt.dom.client.Document; -import com.google.gwt.dom.client.Style.Unit; import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Element; import com.google.gwt.user.client.Event; import com.google.gwt.user.client.ui.SimplePanel; import com.vaadin.client.ApplicationConnection; -import com.vaadin.client.BrowserInfo; import com.vaadin.client.Focusable; +import com.vaadin.client.Util; import com.vaadin.client.ui.ShortcutActionHandler.ShortcutActionHandlerOwner; import com.vaadin.client.ui.TouchScrollDelegate.TouchScrollHandler; @@ -210,43 +207,6 @@ public class VPanel extends SimplePanel implements ShortcutActionHandlerOwner, touchScrollHandler = TouchScrollDelegate.enableTouchScrolling(this); } touchScrollHandler.addElement(contentNode); - - /* - * Shake up the DOM a bit to make the window shed unnecessary scroll - * bars and resize correctly afterwards. This resulting code took over a - * week to summon forth, and involved some pretty hairy black magic. - * Don't touch it unless you know what you're doing! Fixes ticket - * #12727. - * - * This solution comes from the ticket #11994: Windows get unnecessary - * scroll bars in WebKit when content is 100% wide. - */ - if (BrowserInfo.get().isWebkit()) { - Scheduler.get().scheduleFinally(new ScheduledCommand() { - @Override - public void execute() { - final com.google.gwt.dom.client.Element scrollable = contentNode - .getFirstChildElement(); - - int contentNodeScrollTop = contentNode.getScrollTop(); - int contentNodeScrollLeft = contentNode.getScrollLeft(); - - final String oldWidth = scrollable.getStyle().getWidth(); - final String oldHeight = scrollable.getStyle().getHeight(); - - scrollable.getStyle().setWidth(110, Unit.PCT); - scrollable.getOffsetWidth(); - scrollable.getStyle().setProperty("width", oldWidth); - - scrollable.getStyle().setHeight(110, Unit.PCT); - scrollable.getOffsetHeight(); - scrollable.getStyle().setProperty("height", oldHeight); - - // Recovering scroll position: - contentNode.setScrollTop(contentNodeScrollTop); - contentNode.setScrollLeft(contentNodeScrollLeft); - } - }); - } + Util.removeUnneededScrollbars(contentNode); } } diff --git a/client/src/com/vaadin/client/ui/VTabsheet.java b/client/src/com/vaadin/client/ui/VTabsheet.java index 04cd9c09ba..9ad518b85b 100644 --- a/client/src/com/vaadin/client/ui/VTabsheet.java +++ b/client/src/com/vaadin/client/ui/VTabsheet.java @@ -324,7 +324,8 @@ public class VTabsheet extends VTabsheetBase implements Focusable, } public boolean updateCaption(UIDL uidl) { - if (uidl.hasAttribute(TabsheetBaseConstants.ATTRIBUTE_TAB_DESCRIPTION)) { + if (uidl.hasAttribute(TabsheetBaseConstants.ATTRIBUTE_TAB_DESCRIPTION) + || uidl.hasAttribute(TabsheetBaseConstants.ATTRIBUTE_TAB_ERROR_MESSAGE)) { setTooltipInfo(new TooltipInfo( uidl.getStringAttribute(TabsheetBaseConstants.ATTRIBUTE_TAB_DESCRIPTION), uidl.getStringAttribute(TabsheetBaseConstants.ATTRIBUTE_TAB_ERROR_MESSAGE))); diff --git a/client/src/com/vaadin/client/ui/VWindow.java b/client/src/com/vaadin/client/ui/VWindow.java index 03ad8d03c8..6a1a2e547b 100644 --- a/client/src/com/vaadin/client/ui/VWindow.java +++ b/client/src/com/vaadin/client/ui/VWindow.java @@ -536,36 +536,10 @@ public class VWindow extends VWindowOverlay implements if (!visibilityChangesDisabled) { super.setVisible(visible); } - if (visible && BrowserInfo.get().isWebkit()) { - - /* - * Shake up the DOM a bit to make the window shed unnecessary - * scrollbars and resize correctly afterwards. This resulting code - * took over a week to summon forth, and involved some pretty hairy - * black magic. Don't touch it unless you know what you're doing! - * Fixes ticket #11994 - */ - Scheduler.get().scheduleFinally(new ScheduledCommand() { - @Override - public void execute() { - final com.google.gwt.dom.client.Element scrollable = contents - .getFirstChildElement(); - final String oldWidth = scrollable.getStyle().getWidth(); - final String oldHeight = scrollable.getStyle().getHeight(); - - scrollable.getStyle().setWidth(110, Unit.PCT); - scrollable.getOffsetWidth(); - scrollable.getStyle().setProperty("width", oldWidth); - - scrollable.getStyle().setHeight(110, Unit.PCT); - scrollable.getOffsetHeight(); - scrollable.getStyle().setProperty("height", oldHeight); - - updateContentsSize(); - positionOrSizeUpdated(); - } - }); + Util.removeUnneededScrollbars(contents); + updateContentsSize(); + positionOrSizeUpdated(); } } diff --git a/client/src/com/vaadin/client/ui/ui/UIConnector.java b/client/src/com/vaadin/client/ui/ui/UIConnector.java index 903a2cc3fb..2a4a9824d8 100644 --- a/client/src/com/vaadin/client/ui/ui/UIConnector.java +++ b/client/src/com/vaadin/client/ui/ui/UIConnector.java @@ -45,6 +45,7 @@ import com.google.gwt.user.client.ui.RootPanel; import com.google.gwt.user.client.ui.Widget; import com.google.web.bindery.event.shared.HandlerRegistration; import com.vaadin.client.ApplicationConnection; +import com.vaadin.client.ApplicationConnection.ApplicationStoppedEvent; import com.vaadin.client.BrowserInfo; import com.vaadin.client.ComponentConnector; import com.vaadin.client.ConnectorHierarchyChangeEvent; @@ -316,7 +317,8 @@ public class UIConnector extends AbstractSingleComponentContainerConnector .getPaintableAttribute("focused", getConnection()); if (paintable == null) { - // Do not try to focus invisible components which not present in UIDL + // Do not try to focus invisible components which not + // present in UIDL return; } @@ -463,6 +465,21 @@ public class UIConnector extends AbstractSingleComponentContainerConnector // side-effects from focusing (scrollIntoView). getWidget().getElement().focus(); } + + applicationConnection.addHandler( + ApplicationConnection.ApplicationStoppedEvent.TYPE, + new ApplicationConnection.ApplicationStoppedHandler() { + + @Override + public void onApplicationStopped( + ApplicationStoppedEvent event) { + // Stop any polling + if (pollTimer != null) { + pollTimer.cancel(); + pollTimer = null; + } + } + }); } private ClickEventHandler clickEventHandler = new ClickEventHandler(this) { @@ -687,6 +704,12 @@ public class UIConnector extends AbstractSingleComponentContainerConnector pollTimer = new Timer() { @Override public void run() { + if (getState().pollInterval < 0) { + // Polling has been cancelled server side + pollTimer.cancel(); + pollTimer = null; + return; + } getRpcProxy(UIServerRpc.class).poll(); // Send changes even though poll is @Delayed getConnection().sendPendingVariableChanges(); diff --git a/liferay/build.xml b/liferay/build.xml index a13cb37366..fc1d748e55 100644 --- a/liferay/build.xml +++ b/liferay/build.xml @@ -69,4 +69,8 @@ <antcall target="common.clean" /> </target> -</project>
\ No newline at end of file + <target name="checkstyle" /> + + <target name="test" depends="checkstyle" /> + +</project> diff --git a/uitest/src/com/vaadin/tests/components/tabsheet/TabSheetErrorTooltip.java b/uitest/src/com/vaadin/tests/components/tabsheet/TabSheetErrorTooltip.java new file mode 100644 index 0000000000..02482b7049 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/tabsheet/TabSheetErrorTooltip.java @@ -0,0 +1,60 @@ +/* + * Copyright 2000-2013 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.components.tabsheet; + +import com.vaadin.server.UserError; +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.ui.Label; +import com.vaadin.ui.TabSheet; +import com.vaadin.ui.TabSheet.Tab; + +public class TabSheetErrorTooltip extends AbstractTestUI { + + private TabSheet tabSheet = new TabSheet(); + private int tabCount = 0; + + @Override + protected void setup(VaadinRequest request) { + + addTab(); + addTab().setComponentError(new UserError("Error!")); + addTab().setDescription("This is a tab"); + + Tab t = addTab(); + t.setComponentError(new UserError("Error!")); + t.setDescription("This tab has both an error and a description"); + + setContent(tabSheet); + } + + private Tab addTab() { + tabCount++; + Label contents = new Label("Contents for tab " + tabCount); + return tabSheet.addTab(contents, "Tab " + tabCount); + } + + @Override + protected String getTestDescription() { + return "TabSheet Tabs should display component error tooltips when expected"; + } + + @Override + protected Integer getTicketNumber() { + return 12802; + } + +} diff --git a/uitest/src/com/vaadin/tests/components/tabsheet/TabSheetErrorTooltipTest.java b/uitest/src/com/vaadin/tests/components/tabsheet/TabSheetErrorTooltipTest.java new file mode 100644 index 0000000000..88bc23d12b --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/tabsheet/TabSheetErrorTooltipTest.java @@ -0,0 +1,81 @@ +/* + * Copyright 2000-2013 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.components.tabsheet; + +import java.io.IOException; + +import org.junit.Assert; +import org.junit.Test; +import org.openqa.selenium.By; +import org.openqa.selenium.NoSuchElementException; +import org.openqa.selenium.WebElement; + +import com.vaadin.tests.tb3.MultiBrowserTest; + +public class TabSheetErrorTooltipTest extends MultiBrowserTest { + + @Test + public void checkTooltips() throws IOException { + openTestURL(); + + testBenchElement(getTab(0)).showTooltip(); + assertNoTooltip(); + + testBenchElement(getTab(1)).showTooltip(); + assertErrorMessage("Error!"); + assertTooltip(""); + + testBenchElement(getTab(2)).showTooltip(); + assertErrorMessage(""); + assertTooltip("This is a tab"); + + testBenchElement(getTab(3)).showTooltip(); + assertErrorMessage("Error!"); + assertTooltip("This tab has both an error and a description"); + } + + private WebElement getTab(int index) { + return vaadinElement("/VTabsheet[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[" + + index + "]/domChild[0]"); + } + + private WebElement getTooltip() { + return getDriver().findElement( + By.xpath("//div[@class='v-tooltip-text']")); + } + + private WebElement getErrorMessage() { + return getDriver().findElement( + By.xpath("//div[@class='v-errormessage']")); + } + + private void assertTooltip(String tooltip) { + Assert.assertEquals(tooltip, getTooltip().getText()); + } + + private void assertErrorMessage(String message) { + Assert.assertEquals(message, getErrorMessage().getText()); + } + + private void assertNoTooltip() { + try { + getTooltip(); + } catch (NoSuchElementException e) { + return; + } + Assert.fail("Tooltip exists"); + } +} diff --git a/uitest/src/com/vaadin/tests/components/window/ComboboxScrollableWindow.java b/uitest/src/com/vaadin/tests/components/window/ComboboxScrollableWindow.java new file mode 100644 index 0000000000..6347ff9a76 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/window/ComboboxScrollableWindow.java @@ -0,0 +1,66 @@ +/* + * Copyright 2000-2013 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.components.window; + +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.ui.Alignment; +import com.vaadin.ui.ComboBox; +import com.vaadin.ui.VerticalLayout; +import com.vaadin.ui.Window; + +/** + * + * @since + * @author Vaadin Ltd + */ +public class ComboboxScrollableWindow extends AbstractTestUI { + + static final String WINDOW_ID = "window"; + static final String COMBOBOX_ID = "combobox"; + + @Override + protected void setup(VaadinRequest request) { + + Window w = new Window(); + w.setId(WINDOW_ID); + w.setWidth("300px"); + w.setHeight("300px"); + w.center(); + + VerticalLayout content = new VerticalLayout(); + w.setContent(content); + content.setHeight("1000px"); + ComboBox cb = new ComboBox(); + cb.setId(COMBOBOX_ID); + content.addComponent(cb); + content.setComponentAlignment(cb, Alignment.BOTTOM_CENTER); + + addWindow(w); + + } + + @Override + protected String getTestDescription() { + return "The combo box in the bottom of the scrollable window should remain visible when it is clicked."; + } + + @Override + protected Integer getTicketNumber() { + return 12736; + } + +} diff --git a/uitest/src/com/vaadin/tests/components/window/ComboboxScrollableWindowTest.java b/uitest/src/com/vaadin/tests/components/window/ComboboxScrollableWindowTest.java new file mode 100644 index 0000000000..665e175f2c --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/window/ComboboxScrollableWindowTest.java @@ -0,0 +1,57 @@ +/* + * Copyright 2000-2013 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.components.window; + +import static com.vaadin.tests.components.window.ComboboxScrollableWindow.COMBOBOX_ID; +import static com.vaadin.tests.components.window.ComboboxScrollableWindow.WINDOW_ID; + +import org.junit.Test; +import org.openqa.selenium.WebElement; + +import com.vaadin.testbench.By; +import com.vaadin.testbench.commands.TestBenchElementCommands; +import com.vaadin.tests.tb3.MultiBrowserTest; + +/** + * + * @since + * @author Vaadin Ltd + */ +public class ComboboxScrollableWindowTest extends MultiBrowserTest { + + @Test + public void testWindowScrollbars() throws Exception { + openTestURL(); + com.vaadin.testbench.Parameters + .setScreenshotComparisonCursorDetection(true); + + WebElement window = driver.findElement(By.id(WINDOW_ID)); + WebElement scrollableElement = window.findElement(By + .className("v-scrollable")); + TestBenchElementCommands scrollable = testBenchElement(scrollableElement); + scrollable.scroll(1000); + WebElement comboBox = driver.findElement(By.id(COMBOBOX_ID)); + WebElement selectButton = driver.findElement(By + .className("v-filterselect-button")); + selectButton.click(); + + // Wait for the browser before taking a screenshot + Thread.sleep(1000); + compareScreen(getScreenshotBaseName()); + + } + +} diff --git a/uitest/src/com/vaadin/tests/tb3/ScreenshotTB3Test.java b/uitest/src/com/vaadin/tests/tb3/ScreenshotTB3Test.java index cbdae1a6c1..a51421d3d5 100644 --- a/uitest/src/com/vaadin/tests/tb3/ScreenshotTB3Test.java +++ b/uitest/src/com/vaadin/tests/tb3/ScreenshotTB3Test.java @@ -31,7 +31,6 @@ import org.junit.Before; import org.junit.Rule; import org.junit.rules.TestRule; import org.junit.rules.TestWatcher; -import org.junit.runner.Description; import org.openqa.selenium.OutputType; import org.openqa.selenium.TakesScreenshot; import org.openqa.selenium.remote.DesiredCapabilities; @@ -62,18 +61,7 @@ public abstract class ScreenshotTB3Test extends AbstractTB3Test { String className = testClass.getSimpleName(); screenshotBaseName = className + "-" + testMethod; - } - - @Override - protected void failed(Throwable e, Description description) { - - // Notify Teamcity of failed test - if (!System.getProperty("teamcity.version", "").equals("")) { - System.out.print("##teamcity[publishArtifacts '"); - System.out.println(getScreenshotErrorBaseName() - + "* => screenshot-errors']"); - } - } + }; }; /** @@ -129,9 +117,28 @@ public abstract class ScreenshotTB3Test extends AbstractTB3Test { // Matched one comparison but not all, remove all error images + // HTML files } else { - // All comparisons failed, keep the main error image + HTML - screenshotFailures.add(mainReference.getName()); - referenceToKeep = mainReference; + // Ensure we use the correct browser version (e.g. if running IE11 + // and only an IE 10 reference was available, then mainReference + // will be for IE 10, not 11) + String originalName = getScreenshotReferenceName(identifier); + File exactVersionFile = new File(originalName); + + if (!exactVersionFile.equals(mainReference)) { + // Rename png+html to have the correct version + File correctPng = getErrorFileFromReference(exactVersionFile); + File producedPng = getErrorFileFromReference(mainReference); + File correctHtml = htmlFromPng(correctPng); + File producedHtml = htmlFromPng(producedPng); + + producedPng.renameTo(correctPng); + producedHtml.renameTo(correctHtml); + referenceToKeep = exactVersionFile; + screenshotFailures.add(exactVersionFile.getName()); + } else { + // All comparisons failed, keep the main error image + HTML + screenshotFailures.add(mainReference.getName()); + referenceToKeep = mainReference; + } } // Remove all PNG/HTML files we no longer need (failed alternative @@ -140,10 +147,7 @@ public abstract class ScreenshotTB3Test extends AbstractTB3Test { File failurePng = getErrorFileFromReference(failedAlternative); if (failedAlternative != referenceToKeep) { // Delete png + HTML - String htmlFileName = failurePng.getName().replace(".png", - ".html"); - File failureHtml = new File(failurePng.getParentFile(), - htmlFileName); + File failureHtml = htmlFromPng(failurePng); failurePng.delete(); failureHtml.delete(); @@ -152,6 +156,18 @@ 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 + */ + private static File htmlFromPng(File png) { + return new File(png.getParentFile(), png.getName().replaceAll( + "\\.png$", ".png.html")); + } + + /** * * @param referenceFile * The reference image file (in the directory defined by diff --git a/uitest/tb3test.xml b/uitest/tb3test.xml index 5285280608..dd0c12db91 100644 --- a/uitest/tb3test.xml +++ b/uitest/tb3test.xml @@ -19,21 +19,12 @@ <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" /> - - <!-- Ensure teamcity.version is set to something --> - <condition property="teamcity.version" value=""> - <not> - <isset property="teamcity.version" /> - </not> - </condition> - <junit printsummary="withOutAndErr" fork="yes"> <formatter usefile="false" type="plain" /> <classpath refid="classpath.tb3" /> <jvmarg value="-Dcom.vaadin.testbench.screenshot.directory=${com.vaadin.testbench.screenshot.directory}" /> <jvmarg value="-Djava.awt.headless=true" /> - <jvmarg value="-Dteamcity.version=${teamcity.version}" /> <test name="${junit.test.suite}" /> </junit> diff --git a/uitest/test.xml b/uitest/test.xml index 3bfeb66c05..b0db8d47f4 100644 --- a/uitest/test.xml +++ b/uitest/test.xml @@ -134,18 +134,8 @@ </batchtest> </junit> - <antcall target="notify-teamcity-of-build-artifact"> - <param name="file" value="${target}" /> - </antcall> - </target> - <!-- Have teamcity publish each test error artifact immediatly if there are any --> - <target name="notify-teamcity-of-build-artifact" if="teamcity.version"> - <basename property="basename" file="${file}" suffix="java" /> - <echo>##teamcity[publishArtifacts '${com.vaadin.testbench.screenshot.directory}/errors/${basename}* => screenshot-errors']</echo> - </target> - <!-- Remove temporary source and compiled java files --> <target name="remove-temp-testclasses"> <delete failonerror="false"> |