diff options
author | Patrik Lindström <patrik@vaadin.com> | 2013-10-11 14:23:52 +0300 |
---|---|---|
committer | Patrik Lindström <patrik@vaadin.com> | 2013-10-11 14:27:29 +0300 |
commit | df9a1192efeb49285cb1c4fc100bb60b5a77ac14 (patch) | |
tree | a89aea53ffd89943f8672a5ef8943da6579bdb92 | |
parent | c2b81b20ca3a981b775ac5f16506861724119df4 (diff) | |
parent | 4cb304d8eb63ce0045a2742bd9c945af4f12aa66 (diff) | |
download | vaadin-framework-df9a1192efeb49285cb1c4fc100bb60b5a77ac14.tar.gz vaadin-framework-df9a1192efeb49285cb1c4fc100bb60b5a77ac14.zip |
Merge remote-tracking branch 'origin/7.1' into testbench4
Change-Id: I58fe3b4126b61ec342ee06c18ce49a7fa7d4fd3d
121 files changed, 5316 insertions, 1739 deletions
diff --git a/.settings/org.eclipse.jdt.ui.prefs b/.settings/org.eclipse.jdt.ui.prefs index 31240a63bd..4f3b6f7ed3 100644 --- a/.settings/org.eclipse.jdt.ui.prefs +++ b/.settings/org.eclipse.jdt.ui.prefs @@ -3,7 +3,7 @@ editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true formatter_profile=_Vaadin Java Conventions 20110923 formatter_settings_version=12 org.eclipse.jdt.ui.javadoc=true -org.eclipse.jdt.ui.text.custom_code_templates=<?xml version\="1.0" encoding\="UTF-8" standalone\="no"?><templates><template autoinsert\="true" context\="gettercomment_context" deleted\="false" description\="Comment for getter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.gettercomment" name\="gettercomment">/**\n * @return the ${bare_field_name}\n */</template><template autoinsert\="true" context\="settercomment_context" deleted\="false" description\="Comment for setter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.settercomment" name\="settercomment">/**\n * @param ${param} the ${bare_field_name} to set\n */</template><template autoinsert\="true" context\="constructorcomment_context" deleted\="false" description\="Comment for created constructors" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorcomment" name\="constructorcomment">/**\n * ${tags}\n */</template><template autoinsert\="false" context\="filecomment_context" deleted\="false" description\="Comment for created Java files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.filecomment" name\="filecomment">/**\n * \n */</template><template autoinsert\="false" context\="typecomment_context" deleted\="false" description\="Comment for created types" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.typecomment" name\="typecomment">/**\n * \n * @since \n * @author Vaadin Ltd\n * ${tags}\n */</template><template autoinsert\="true" context\="fieldcomment_context" deleted\="false" description\="Comment for fields" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.fieldcomment" name\="fieldcomment">/**\n * \n */</template><template autoinsert\="false" context\="methodcomment_context" deleted\="false" description\="Comment for non-overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodcomment" name\="methodcomment">/**\n * @since\n * ${tags}\n */</template><template autoinsert\="true" context\="overridecomment_context" deleted\="false" description\="Comment for overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.overridecomment" name\="overridecomment">/* (non-Javadoc)\n * ${see_to_overridden}\n */</template><template autoinsert\="true" context\="delegatecomment_context" deleted\="false" description\="Comment for delegate methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.delegatecomment" name\="delegatecomment">/**\n * ${tags}\n * ${see_to_target}\n */</template><template autoinsert\="false" context\="newtype_context" deleted\="false" description\="Newly created files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.newtype" name\="newtype">/*\n * Copyright 2000-2013 Vaadin Ltd.\n * \n * Licensed under the Apache License, Version 2.0 (the "License"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n * \n * http\://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\n${filecomment}\n${package_declaration}\n\n${typecomment}\n${type_declaration}</template><template autoinsert\="true" context\="classbody_context" deleted\="false" description\="Code in new class type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.classbody" name\="classbody">\n</template><template autoinsert\="true" context\="interfacebody_context" deleted\="false" description\="Code in new interface type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.interfacebody" name\="interfacebody">\n</template><template autoinsert\="true" context\="enumbody_context" deleted\="false" description\="Code in new enum type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.enumbody" name\="enumbody">\n</template><template autoinsert\="true" context\="annotationbody_context" deleted\="false" description\="Code in new annotation type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.annotationbody" name\="annotationbody">\n</template><template autoinsert\="true" context\="catchblock_context" deleted\="false" description\="Code in new catch blocks" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.catchblock" name\="catchblock">// ${todo} Auto-generated catch block\n${exception_var}.printStackTrace();</template><template autoinsert\="true" context\="methodbody_context" deleted\="false" description\="Code in created method stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodbody" name\="methodbody">// ${todo} Auto-generated method stub\n${body_statement}</template><template autoinsert\="true" context\="constructorbody_context" deleted\="false" description\="Code in created constructor stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorbody" name\="constructorbody">${body_statement}\n// ${todo} Auto-generated constructor stub</template><template autoinsert\="true" context\="getterbody_context" deleted\="false" description\="Code in created getters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.getterbody" name\="getterbody">return ${field};</template><template autoinsert\="true" context\="setterbody_context" deleted\="false" description\="Code in created setters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.setterbody" name\="setterbody">${field} \= ${param};</template></templates> +org.eclipse.jdt.ui.text.custom_code_templates=<?xml version\="1.0" encoding\="UTF-8" standalone\="no"?><templates><template autoinsert\="true" context\="gettercomment_context" deleted\="false" description\="Comment for getter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.gettercomment" name\="gettercomment">/**\n * @return the ${bare_field_name}\n */</template><template autoinsert\="true" context\="settercomment_context" deleted\="false" description\="Comment for setter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.settercomment" name\="settercomment">/**\n * @param ${param} the ${bare_field_name} to set\n */</template><template autoinsert\="true" context\="constructorcomment_context" deleted\="false" description\="Comment for created constructors" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorcomment" name\="constructorcomment">/**\n * ${tags}\n */</template><template autoinsert\="false" context\="filecomment_context" deleted\="false" description\="Comment for created Java files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.filecomment" name\="filecomment">/**\n * \n */</template><template autoinsert\="false" context\="typecomment_context" deleted\="false" description\="Comment for created types" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.typecomment" name\="typecomment">/**\n * \n * @since \n * @author Vaadin Ltd\n * ${tags}\n */</template><template autoinsert\="true" context\="fieldcomment_context" deleted\="false" description\="Comment for fields" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.fieldcomment" name\="fieldcomment">/**\n * \n */</template><template autoinsert\="false" context\="methodcomment_context" deleted\="false" description\="Comment for non-overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodcomment" name\="methodcomment">/**\n * @since\n * ${tags}\n */</template><template autoinsert\="true" context\="overridecomment_context" deleted\="false" description\="Comment for overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.overridecomment" name\="overridecomment">/* (non-Javadoc)\n * ${see_to_overridden}\n */</template><template autoinsert\="true" context\="delegatecomment_context" deleted\="false" description\="Comment for delegate methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.delegatecomment" name\="delegatecomment">/**\n * ${tags}\n * ${see_to_target}\n */</template><template autoinsert\="false" context\="newtype_context" deleted\="false" description\="Newly created files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.newtype" name\="newtype">/*\n * Copyright 2000-2013 Vaadin Ltd.\n * \n * Licensed under the Apache License, Version 2.0 (the "License"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n * \n * http\://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n${package_declaration}\n\n${typecomment}\n${type_declaration}</template><template autoinsert\="true" context\="classbody_context" deleted\="false" description\="Code in new class type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.classbody" name\="classbody">\n</template><template autoinsert\="true" context\="interfacebody_context" deleted\="false" description\="Code in new interface type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.interfacebody" name\="interfacebody">\n</template><template autoinsert\="true" context\="enumbody_context" deleted\="false" description\="Code in new enum type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.enumbody" name\="enumbody">\n</template><template autoinsert\="true" context\="annotationbody_context" deleted\="false" description\="Code in new annotation type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.annotationbody" name\="annotationbody">\n</template><template autoinsert\="true" context\="catchblock_context" deleted\="false" description\="Code in new catch blocks" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.catchblock" name\="catchblock">// ${todo} Auto-generated catch block\n${exception_var}.printStackTrace();</template><template autoinsert\="true" context\="methodbody_context" deleted\="false" description\="Code in created method stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodbody" name\="methodbody">// ${todo} Auto-generated method stub\n${body_statement}</template><template autoinsert\="true" context\="constructorbody_context" deleted\="false" description\="Code in created constructor stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorbody" name\="constructorbody">${body_statement}\n// ${todo} Auto-generated constructor stub</template><template autoinsert\="true" context\="getterbody_context" deleted\="false" description\="Code in created getters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.getterbody" name\="getterbody">return ${field};</template><template autoinsert\="true" context\="setterbody_context" deleted\="false" description\="Code in created setters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.setterbody" name\="setterbody">${field} \= ${param};</template></templates> sp_cleanup.add_default_serial_version_id=true sp_cleanup.add_generated_serial_version_id=false sp_cleanup.add_missing_annotations=true diff --git a/WebContent/VAADIN/themes/base/common/common.scss b/WebContent/VAADIN/themes/base/common/common.scss index cb3645c9d8..07e244a76f 100644 --- a/WebContent/VAADIN/themes/base/common/common.scss +++ b/WebContent/VAADIN/themes/base/common/common.scss @@ -227,11 +227,13 @@ input::-ms-clear { font-size: 0; line-height: normal; } - -/* Enable kinetic scrolling on iOS 6 */ -.v-ios6.v-webkit & .v-scrollable { +.v-ios.v-webkit & .v-scrollable { -webkit-overflow-scrolling: touch; } +/* Disable native scrolling on iOS 5 due to #8792 */ +.v-ios5.v-webkit & .v-scrollable { + -webkit-overflow-scrolling: none; +} &.v-overlay-container { width: 0; diff --git a/WebContent/WEB-INF/web.xml b/WebContent/WEB-INF/web.xml index ba948968e2..8a917966a1 100644 --- a/WebContent/WEB-INF/web.xml +++ b/WebContent/WEB-INF/web.xml @@ -24,6 +24,7 @@ <param-name>application</param-name> <param-value>com.vaadin.tests.components.button.Buttons</param-value> </init-param> + <async-supported>true</async-supported> </servlet> <servlet> <servlet-name>Embed App 2</servlet-name> @@ -32,6 +33,7 @@ <param-name>UI</param-name> <param-value>com.vaadin.tests.components.label.MarginsInLabels</param-value> </init-param> + <async-supported>true</async-supported> </servlet> <servlet> <servlet-name>UI provider app</servlet-name> @@ -44,6 +46,7 @@ <param-name>UI</param-name> <param-value>com.vaadin.tests.VerifyAssertionsEnabled</param-value> </init-param> + <async-supported>true</async-supported> </servlet> <servlet> @@ -70,6 +73,7 @@ <param-name>testParam</param-name> <param-value>42</param-value> </init-param> + <async-supported>true</async-supported> </servlet> <servlet> @@ -88,7 +92,7 @@ <servlet-class>com.vaadin.server.VaadinServlet</servlet-class> <init-param> <param-name>UI</param-name> - <param-value>com.vaadin.tests.integration.IntegrationTestUI</param-value> + <param-value>com.vaadin.tests.integration.ServletIntegrationUI</param-value> </init-param> <async-supported>true</async-supported> </servlet> diff --git a/WebContent/WEB-INF/web.xml.2.4 b/WebContent/WEB-INF/web.xml.2.4 index bcc5f3a651..96144b8036 100644 --- a/WebContent/WEB-INF/web.xml.2.4 +++ b/WebContent/WEB-INF/web.xml.2.4 @@ -86,7 +86,7 @@ <servlet-class>com.vaadin.server.VaadinServlet</servlet-class> <init-param> <param-name>UI</param-name> - <param-value>com.vaadin.tests.integration.IntegrationTestUI</param-value> + <param-value>com.vaadin.tests.integration.ServletIntegrationUI</param-value> </init-param> </servlet> <servlet-mapping> diff --git a/WebContent/release-notes.html b/WebContent/release-notes.html index 387a5121cb..a11e526c3f 100644 --- a/WebContent/release-notes.html +++ b/WebContent/release-notes.html @@ -41,10 +41,10 @@ <ul> <li><a href="#overview">Overview of Vaadin @version@ Release</a></li> + <li><a href="#changelog">Change log for Vaadin + @version@</a></li> <li><a href="#enhancements">Enhancements in Vaadin @version-minor@</a></li> - <li><a href="#changelog">Complete change log for - Vaadin @version@</a></li> <li><a href="#limitations">Limitations in @version-minor@</a></li> <li><a href="#vaadin">Vaadin Installation</a></li> @@ -63,11 +63,30 @@ <h2 id="overview">Overview of Vaadin @version@ Release</h2> <p> - Vaadin @version@ is a maintenance release that includes a number - of important bug fixes, as listed in the <a href="#changelog">change - log</a> below. You can also view the <a - href="http://dev.vaadin.com/query?status=closed&resolution=fixed&milestone=Vaadin+@version@&order=priority">list - of the closed issues</a> at the Vaadin developer's site. + Vaadin @version@ is a maintenance release that includes a + number of important bug fixes, as listed in the <a + href="#changelog">change log</a> below. + </p> + + <p> + For a list of enhancements in the last feature release, see + <a href="#enhancements">Enhancements in Vaadin + @version-minor@</a> and the <a + href="http://vaadin.com/download/release/@version-minor@/@version-minor@.0/release-notes.html">Release + Notes for Vaadin @version-minor@.0</a>. + </p> + + <h3 id="changelog">Change log for Vaadin @version@</h3> + + <p>This release includes the following closed issues:</p> + + <ul>@release-notes-tickets@ + </ul> + + <p> + You can also view the <a + href="http://dev.vaadin.com/query?status=closed&resolution=fixed&milestone=Vaadin+@version@&order=id">list + of the closed issues</a> at the Vaadin developer's site. . </p> <h2 id="enhancements">Enhancements in Vaadin @@ -191,21 +210,6 @@ streaming to work.</li> </ul> - <h3 id="changelog">ChangeLog</h3> - - <p>This release includes the following closed issues:</p> - - <ul>@release-notes-tickets@ - </ul> - - <p> - The <a - href="http://dev.vaadin.com/query?status=closed&resolution=fixed&milestone=Vaadin+7.1.0.beta1&milestone=Vaadin+7.1.0&order=id">full - list of the closed issues</a> can also be found at - <tt>dev.vaadin.com</tt> - . - </p> - <h2 id="vaadin">Vaadin Installation</h2> <p> @@ -573,11 +577,11 @@ </p> <ul> - <li>Mozilla Firefox 18-23</li> + <li>Mozilla Firefox 18-24</li> <li>Mozilla Firefox 17 ESR</li> <li>Internet Explorer 8-10</li> <li>Safari 6</li> - <li>Opera 12</li> + <li>Opera 12,16</li> <li>Google Chrome 23-29</li> </ul> @@ -587,7 +591,7 @@ </p> <ul> - <li>iOS 5-6</li> + <li>iOS 5-7</li> <li>Android 2.3-4</li> </ul> @@ -43,19 +43,16 @@ <target name="test" depends="buildorder"> <subant buildpathref="build-path" target="test" /> </target> + <target name="test-all" depends="buildorder"> <property name="war.file" location="result/artifacts/${vaadin.version}/vaadin-uitest/vaadin-uitest-${vaadin.version}.war" /> + <parallel> - <sequential> - <!-- Sleep before running integration tests so testbench - tests have time to compile and start --> - <sleep minutes="4" /> - <ant antfile="uitest/integration_tests.xml" target="integration-test-all" inheritall="false" inheritrefs="false"> - <property name="demo.war" value="${war.file}" /> - </ant> - </sequential> + <!-- JUnit tests, can be run without a server --> <subant buildpathref="build-path" target="test" /> - <ant antfile="uitest/test.xml" target="test-package"> + + <!-- Server deployment + TestBench tests --> + <ant antfile="uitest/build.xml" target="test-testbench"> <property name="war.file" location="${war.file}" /> </ant> </parallel> diff --git a/client/ivy.xml b/client/ivy.xml index 5d079537b9..ccc304be3d 100644 --- a/client/ivy.xml +++ b/client/ivy.xml @@ -32,7 +32,7 @@ <!-- gwt-user dependencies --> <dependency org="org.w3c.css" name="sac" rev="1.3" /> - <dependency org="junit" name="junit" rev="4.5" + <dependency org="junit" name="junit" rev="4.11" conf="test->default" /> <dependency org="javax.validation" name="validation-api" diff --git a/client/src/com/vaadin/client/ApplicationConfiguration.java b/client/src/com/vaadin/client/ApplicationConfiguration.java index f27f9d65d2..a8ae47385a 100644 --- a/client/src/com/vaadin/client/ApplicationConfiguration.java +++ b/client/src/com/vaadin/client/ApplicationConfiguration.java @@ -247,6 +247,23 @@ public class ApplicationConfiguration implements EntryPoint { ApplicationConstants.SERVICE_URL_PATH_AS_PARAMETER) == Boolean.TRUE; } + /** + * Return the name of the parameter used to to send data to the service url. + * This method should only be called if {@link #useServiceUrlPathParam()} is + * true. + * + * @since 7.1.6 + * @return The parameter name, by default <code>v-resourcePath</code> + */ + public String getServiceUrlParameterName() { + String prefix = getJsoConfiguration(id).getConfigString( + ApplicationConstants.SERVICE_URL_PARAMETER_NAMESPACE); + if (prefix == null) { + prefix = ""; + } + return prefix + ApplicationConstants.V_RESOURCE_PATH; + } + public String getRootPanelId() { return id; } diff --git a/client/src/com/vaadin/client/ApplicationConnection.java b/client/src/com/vaadin/client/ApplicationConnection.java index e038f37689..21f6ce8a31 100644 --- a/client/src/com/vaadin/client/ApplicationConnection.java +++ b/client/src/com/vaadin/client/ApplicationConnection.java @@ -2998,7 +2998,7 @@ public class ApplicationConnection { if (!path.startsWith("/")) { path = '/' + path; } - String pathParam = ApplicationConstants.V_RESOURCE_PATH + "=" + String pathParam = conf.getServiceUrlParameterName() + "=" + URL.encodeQueryString(path); serviceUrl = addGetParameters(serviceUrl, pathParam); uidlUri = serviceUrl; diff --git a/client/src/com/vaadin/client/BrowserInfo.java b/client/src/com/vaadin/client/BrowserInfo.java index 5d588f6f8b..273964c889 100644 --- a/client/src/com/vaadin/client/BrowserInfo.java +++ b/client/src/com/vaadin/client/BrowserInfo.java @@ -207,10 +207,7 @@ public class BrowserInfo { return prefix + OS_ANDROID; } else if (browserDetails.isIOS()) { String iosClass = prefix + OS_IOS; - if (isIOS6()) { - iosClass += " " + prefix + OS_IOS + "6"; - } - return iosClass; + return iosClass + " " + iosClass + getOperatingSystemMajorVersion(); } else if (browserDetails.isWindows()) { return prefix + OS_WINDOWS; } else if (browserDetails.isLinux()) { @@ -392,9 +389,9 @@ public class BrowserInfo { if (isAndroid() && isWebkit() && getWebkitVersion() >= 534) { return false; } - // iOS 6 Safari supports native scrolling; iOS 5 suffers from #8792 + // iOS 6+ Safari supports native scrolling; iOS 5 suffers from #8792 // TODO Should test other iOS browsers - if (isIOS6() && isWebkit()) { + if (isIOS() && isWebkit() && getOperatingSystemMajorVersion() >= 6) { return false; } return true; diff --git a/client/src/com/vaadin/client/VConsole.java b/client/src/com/vaadin/client/VConsole.java index 37ed8e6370..32eb206a70 100644 --- a/client/src/com/vaadin/client/VConsole.java +++ b/client/src/com/vaadin/client/VConsole.java @@ -41,25 +41,35 @@ public class VConsole { public static void log(String msg) { if (LogConfiguration.loggingIsEnabled(Level.INFO)) { - getLogger().log(Level.INFO, msg); + // Check for null, so no NullPointerException is generated when + // formatting (#12588) + getLogger().log(Level.INFO, msg == null ? "null" : msg); } } public static void log(Throwable e) { if (LogConfiguration.loggingIsEnabled(Level.INFO)) { - getLogger().log(Level.INFO, e.getMessage(), e); + // Check for null, so no NullPointerException is generated when + // formatting (#12588) + getLogger().log(Level.INFO, + e.getMessage() == null ? "" : e.getMessage(), e); } } public static void error(Throwable e) { if (LogConfiguration.loggingIsEnabled(Level.SEVERE)) { - getLogger().log(Level.SEVERE, e.getMessage(), e); + // Check for null, so no NullPointerException is generated when + // formatting (#12588) + getLogger().log(Level.SEVERE, + e.getMessage() == null ? "" : e.getMessage(), e); } } public static void error(String msg) { if (LogConfiguration.loggingIsEnabled(Level.SEVERE)) { - getLogger().log(Level.SEVERE, msg); + // Check for null, so no NullPointerException is generated when + // formatting (#12588) + getLogger().log(Level.SEVERE, msg == null ? "null" : msg); } } diff --git a/client/src/com/vaadin/client/communication/AtmospherePushConnection.java b/client/src/com/vaadin/client/communication/AtmospherePushConnection.java index 3cecb09dc1..4bf12ca1f3 100644 --- a/client/src/com/vaadin/client/communication/AtmospherePushConnection.java +++ b/client/src/com/vaadin/client/communication/AtmospherePushConnection.java @@ -228,10 +228,28 @@ public class AtmospherePushConnection implements PushConnection { return config; } + protected void onReopen(AtmosphereResponse response) { + VConsole.log("Push connection re-established using " + + response.getTransport()); + onConnect(response); + } + protected void onOpen(AtmosphereResponse response) { - transport = response.getTransport(); + VConsole.log("Push connection established using " + + response.getTransport()); + onConnect(response); + } - VConsole.log("Push connection established using " + transport); + /** + * Called whenever a server push connection is established (or + * re-established). + * + * @param response + * + * @since 7.2 + */ + protected void onConnect(AtmosphereResponse response) { + transport = response.getTransport(); switch (state) { case CONNECT_PENDING: @@ -422,6 +440,7 @@ public class AtmospherePushConnection implements PushConnection { reconnectInterval: 5000, maxReconnectOnClose: 10000000, trackMessageLength: true, + enableProtocol: false, messageDelimiter: String.fromCharCode(@com.vaadin.shared.communication.PushConstants::MESSAGE_DELIMITER) }; }-*/; @@ -435,6 +454,9 @@ public class AtmospherePushConnection implements PushConnection { config.onOpen = $entry(function(response) { self.@com.vaadin.client.communication.AtmospherePushConnection::onOpen(*)(response); }); + config.onReopen = $entry(function(response) { + self.@com.vaadin.client.communication.AtmospherePushConnection::onReopen(*)(response); + }); config.onMessage = $entry(function(response) { self.@com.vaadin.client.communication.AtmospherePushConnection::onMessage(*)(response); }); diff --git a/client/src/com/vaadin/client/debug/internal/LogSection.java b/client/src/com/vaadin/client/debug/internal/LogSection.java index 1e7524b56d..f792ec95be 100644 --- a/client/src/com/vaadin/client/debug/internal/LogSection.java +++ b/client/src/com/vaadin/client/debug/internal/LogSection.java @@ -73,6 +73,12 @@ public class LogSection implements Section { return; } + // If no message is provided, record.getMessage will be null and so + // the formatter.format will fail with NullPointerException (#12588) + if (record.getMessage() == null) { + record.setMessage(""); + } + Formatter formatter = getFormatter(); String msg = formatter.format(record); diff --git a/client/src/com/vaadin/client/ui/PostLayoutListener.java b/client/src/com/vaadin/client/ui/PostLayoutListener.java index d60360747c..3da2358b0c 100644 --- a/client/src/com/vaadin/client/ui/PostLayoutListener.java +++ b/client/src/com/vaadin/client/ui/PostLayoutListener.java @@ -15,6 +15,24 @@ */ package com.vaadin.client.ui; +import com.vaadin.client.ComponentConnector; +import com.vaadin.client.LayoutManager; + +/** + * Interface implemented by {@link ComponentConnector} implementations that want + * to know whenever a layout phase has ended. At the end of each layout phase, + * {@link LayoutManager} invokes the {@link #postLayout()} method for all + * registered component connectors implementing this interface. + * + * @since 7.0 + * @author Vaadin Ltd + */ public interface PostLayoutListener { + /** + * Method invoked by {@link LayoutManager} to notify the connector that a + * layout phase has ended. This method can be used to finalize internal + * layouting, but it is not allowed to change the its own external size or + * modify the conditions for any children. + */ public void postLayout(); } diff --git a/client/src/com/vaadin/client/ui/VCalendarPanel.java b/client/src/com/vaadin/client/ui/VCalendarPanel.java index 1f40298760..58e0448b5f 100644 --- a/client/src/com/vaadin/client/ui/VCalendarPanel.java +++ b/client/src/com/vaadin/client/ui/VCalendarPanel.java @@ -2215,11 +2215,13 @@ public class VCalendarPanel extends FocusableFlexTable implements * - the allowed range's start date */ public void setRangeStart(Date rangeStart) { - this.rangeStart = rangeStart; - if (initialRenderDone) { - // Dynamic updates to the range needs to render the calendar to - // update the element stylenames - renderCalendar(); + if (this.rangeStart != rangeStart) { + this.rangeStart = rangeStart; + if (initialRenderDone) { + // Dynamic updates to the range needs to render the calendar to + // update the element stylenames + renderCalendar(); + } } } @@ -2232,11 +2234,13 @@ public class VCalendarPanel extends FocusableFlexTable implements * - the allowed range's end date */ public void setRangeEnd(Date rangeEnd) { - this.rangeEnd = rangeEnd; - if (initialRenderDone) { - // Dynamic updates to the range needs to render the calendar to - // update the element stylenames - renderCalendar(); + if (this.rangeEnd != rangeEnd) { + this.rangeEnd = rangeEnd; + if (initialRenderDone) { + // Dynamic updates to the range needs to render the calendar to + // update the element stylenames + renderCalendar(); + } } } } diff --git a/client/src/com/vaadin/client/ui/VDragAndDropWrapper.java b/client/src/com/vaadin/client/ui/VDragAndDropWrapper.java index 1c1173c295..ccd7e2758e 100644 --- a/client/src/com/vaadin/client/ui/VDragAndDropWrapper.java +++ b/client/src/com/vaadin/client/ui/VDragAndDropWrapper.java @@ -332,11 +332,16 @@ public class VDragAndDropWrapper extends VCustomComponent implements vaadinDragEvent.setCurrentGwtEvent(event); getDropHandler().dragOver(vaadinDragEvent); - String s = event.getEffectAllowed(); - if ("all".equals(s) || s.contains("opy")) { - event.setDropEffect("copy"); - } else { - event.setDropEffect(s); + try { + String s = event.getEffectAllowed(); + if ("all".equals(s) || s.contains("opy")) { + event.setDropEffect("copy"); + } else { + event.setDropEffect(s); + } + } catch (Exception e) { + // IE10 throws exception here in getEffectAllowed, ignore it, let + // drop effect be whatever it is } try { diff --git a/client/src/com/vaadin/client/ui/VOptionGroup.java b/client/src/com/vaadin/client/ui/VOptionGroup.java index a4c8b6733c..fee1c313f5 100644 --- a/client/src/com/vaadin/client/ui/VOptionGroup.java +++ b/client/src/com/vaadin/client/ui/VOptionGroup.java @@ -87,19 +87,42 @@ public class VOptionGroup extends VOptionGroupBase implements FocusHandler, /** For internal use only. May be removed or replaced in the future. */ public boolean htmlContentAllowed = false; + private boolean wasHtmlContentAllowed = false; + private boolean wasMultiselect = false; + public VOptionGroup() { super(CLASSNAME); panel = (Panel) optionsContainer; optionsToKeys = new HashMap<CheckBox, String>(); optionsEnabled = new ArrayList<Boolean>(); + + wasMultiselect = isMultiselect(); } /* - * Return true if no elements were changed, false otherwise. + * Try to update content of existing elements, rebuild panel entirely + * otherwise */ @Override public void buildOptions(UIDL uidl) { - panel.clear(); + /* + * In order to retain focus, we need to update values rather than + * recreate panel from scratch (#10451). However, the panel will be + * rebuilt (losing focus) if number of elements or their order is + * changed. + */ + HashMap<String, CheckBox> keysToOptions = new HashMap<String, CheckBox>(); + for (Map.Entry<CheckBox, String> entry : optionsToKeys.entrySet()) { + keysToOptions.put(entry.getValue(), entry.getKey()); + } + ArrayList<Widget> existingwidgets = new ArrayList<Widget>(); + ArrayList<Widget> newwidgets = new ArrayList<Widget>(); + + // Get current order of elements + for (Widget wid : panel) { + existingwidgets.add(wid); + } + optionsEnabled.clear(); if (isMultiselect()) { @@ -110,7 +133,6 @@ public class VOptionGroup extends VOptionGroupBase implements FocusHandler, for (final Iterator<?> it = uidl.getChildIterator(); it.hasNext();) { final UIDL opUidl = (UIDL) it.next(); - CheckBox op; String itemHtml = opUidl.getStringAttribute("caption"); if (!htmlContentAllowed) { @@ -124,33 +146,56 @@ public class VOptionGroup extends VOptionGroupBase implements FocusHandler, + Icon.CLASSNAME + "\" alt=\"\" />" + itemHtml; } - if (isMultiselect()) { - op = new VCheckBox(); - op.setHTML(itemHtml); - } else { - op = new RadioButton(paintableId, itemHtml, true); - op.setStyleName("v-radiobutton"); - } + String key = opUidl.getStringAttribute("key"); + CheckBox op = keysToOptions.get(key); - if (icon != null && icon.length() != 0) { - Util.sinkOnloadForImages(op.getElement()); - op.addHandler(iconLoadHandler, LoadEvent.getType()); + // Need to recreate object if isMultiselect is changed (#10451) + // OR if htmlContentAllowed changed due to Safari 5 issue + if ((op == null) || (htmlContentAllowed != wasHtmlContentAllowed) + || (isMultiselect() != wasMultiselect)) { + // Create a new element + if (isMultiselect()) { + op = new VCheckBox(); + } else { + op = new RadioButton(paintableId); + op.setStyleName("v-radiobutton"); + } + if (icon != null && icon.length() != 0) { + Util.sinkOnloadForImages(op.getElement()); + op.addHandler(iconLoadHandler, LoadEvent.getType()); + } + + op.addStyleName(CLASSNAME_OPTION); + op.addClickHandler(this); + + optionsToKeys.put(op, key); } - op.addStyleName(CLASSNAME_OPTION); + op.setHTML(itemHtml); op.setValue(opUidl.getBooleanAttribute("selected")); boolean optionEnabled = !opUidl .getBooleanAttribute(OptionGroupConstants.ATTRIBUTE_OPTION_DISABLED); boolean enabled = optionEnabled && !isReadonly() && isEnabled(); op.setEnabled(enabled); optionsEnabled.add(optionEnabled); + setStyleName(op.getElement(), ApplicationConnection.DISABLED_CLASSNAME, !(optionEnabled && isEnabled())); - op.addClickHandler(this); - optionsToKeys.put(op, opUidl.getStringAttribute("key")); - panel.add(op); + + newwidgets.add(op); } + + if (!newwidgets.equals(existingwidgets)) { + // Rebuild the panel, losing focus + panel.clear(); + for (Widget wid : newwidgets) { + panel.add(wid); + } + } + + wasHtmlContentAllowed = htmlContentAllowed; + wasMultiselect = isMultiselect(); } @Override diff --git a/client/src/com/vaadin/client/ui/VOverlay.java b/client/src/com/vaadin/client/ui/VOverlay.java index ced476f9dd..0e031e3d0d 100644 --- a/client/src/com/vaadin/client/ui/VOverlay.java +++ b/client/src/com/vaadin/client/ui/VOverlay.java @@ -248,10 +248,6 @@ public class VOverlay extends PopupPanel implements CloseHandler<PopupPanel> { return isShadowEnabled() && shadow.getParentElement() != null; } - private boolean isShimElementAttached() { - return shimElement != null && shimElement.hasParentElement(); - } - private void adjustZIndex() { setZIndex(Z_INDEX); } @@ -469,36 +465,51 @@ public class VOverlay extends PopupPanel implements CloseHandler<PopupPanel> { getOffsetWidth(); } - PositionAndSize positionAndSize = new PositionAndSize(getActualLeft(), - getActualTop(), getOffsetWidth(), getOffsetHeight()); + if (isShadowEnabled() || needsShimElement()) { + + PositionAndSize positionAndSize = new PositionAndSize( + getActualLeft(), getActualTop(), getOffsetWidth(), + getOffsetHeight()); + + // Animate the size + positionAndSize.setAnimationFromCenterProgress(progress); + + Element container = getElement().getParentElement().cast(); - // Animate the size - positionAndSize.setAnimationFromCenterProgress(progress); + if (isShadowEnabled()) { + updateShadowPosition(progress, zIndex, positionAndSize); + if (shadow.getParentElement() == null) { + container.insertBefore(shadow, getElement()); + sinkShadowEvents(); + } + } + + if (needsShimElement()) { + updateShimPosition(positionAndSize); + if (shimElement.getParentElement() == null) { + container.insertBefore(shimElement, getElement()); + } + } + } + } + private void updateShadowPosition(final double progress, String zIndex, + PositionAndSize positionAndSize) { // Opera needs some shaking to get parts of the shadow showing - // properly - // (ticket #2704) - if (BrowserInfo.get().isOpera() && isShadowEnabled()) { + // properly (ticket #2704) + if (BrowserInfo.get().isOpera()) { // Clear the height of all middle elements DOM.getChild(shadow, 3).getStyle().setProperty("height", "auto"); DOM.getChild(shadow, 4).getStyle().setProperty("height", "auto"); DOM.getChild(shadow, 5).getStyle().setProperty("height", "auto"); } - // Update correct values - if (isShadowEnabled()) { - updatePositionAndSize(shadow, positionAndSize); - DOM.setStyleAttribute(shadow, "zIndex", zIndex); - DOM.setStyleAttribute(shadow, "display", progress < 0.9 ? "none" - : ""); - } - if (needsShimElement()) { - updatePositionAndSize((Element) Element.as(getShimElement()), - positionAndSize); - } + updatePositionAndSize(shadow, positionAndSize); + DOM.setStyleAttribute(shadow, "zIndex", zIndex); + DOM.setStyleAttribute(shadow, "display", progress < 0.9 ? "none" : ""); // Opera fix, part 2 (ticket #2704) - if (BrowserInfo.get().isOpera() && isShadowEnabled()) { + if (BrowserInfo.get().isOpera()) { // We'll fix the height of all the middle elements DOM.getChild(shadow, 3) .getStyle() @@ -513,17 +524,11 @@ public class VOverlay extends PopupPanel implements CloseHandler<PopupPanel> { .setPropertyPx("height", DOM.getChild(shadow, 5).getOffsetHeight()); } + } - Element container = getElement().getParentElement().cast(); - // Attach to dom if not there already - if (isShadowEnabled() && !isShadowAttached()) { - container.insertBefore(shadow, getElement()); - sinkShadowEvents(); - } - if (needsShimElement() && !isShimElementAttached()) { - container.insertBefore(getShimElement(), getElement()); - } - + private void updateShimPosition(PositionAndSize positionAndSize) { + updatePositionAndSize((Element) Element.as(getShimElement()), + positionAndSize); } /** diff --git a/client/src/com/vaadin/client/ui/VScrollTable.java b/client/src/com/vaadin/client/ui/VScrollTable.java index fe2e99a28f..ab3a41402d 100644 --- a/client/src/com/vaadin/client/ui/VScrollTable.java +++ b/client/src/com/vaadin/client/ui/VScrollTable.java @@ -178,6 +178,8 @@ public class VScrollTable extends FlowPanel implements HasWidgets, private int firstRowInViewPort = 0; private int pageLength = 15; private int lastRequestedFirstvisible = 0; // to detect "serverside scroll" + private int firstvisibleOnLastPage = -1; // To detect if the first visible + // is on the last page /** For internal use only. May be removed or replaced in the future. */ public boolean showRowHeaders = false; @@ -1072,6 +1074,17 @@ public class VScrollTable extends FlowPanel implements HasWidgets, } if (selected != row.isSelected()) { row.toggleSelection(); + + if (selected) { + if (focusedRow == null + || !selectedRowKeys.contains(focusedRow + .getKey())) { + // The focus is no longer on a selected row, + // move focus to first selected row + setRowFocus(row); + } + } + if (!isSingleSelectMode() && !selected) { // Update selection range in case a row is // unselected from the middle of a range - #8076 @@ -1113,8 +1126,16 @@ public class VScrollTable extends FlowPanel implements HasWidgets, private ScheduledCommand lazyScroller = new ScheduledCommand() { @Override public void execute() { - int offsetTop = measureRowHeightOffset(firstvisible); - scrollBodyPanel.setScrollPosition(offsetTop); + if (firstvisible > 0) { + firstRowInViewPort = firstvisible; + if (firstvisibleOnLastPage > -1) { + scrollBodyPanel + .setScrollPosition(measureRowHeightOffset(firstvisibleOnLastPage)); + } else { + scrollBodyPanel + .setScrollPosition(measureRowHeightOffset(firstvisible)); + } + } } }; @@ -1122,18 +1143,18 @@ public class VScrollTable extends FlowPanel implements HasWidgets, public void updateFirstVisibleAndScrollIfNeeded(UIDL uidl) { firstvisible = uidl.hasVariable("firstvisible") ? uidl .getIntVariable("firstvisible") : 0; + firstvisibleOnLastPage = uidl.hasVariable("firstvisibleonlastpage") ? uidl + .getIntVariable("firstvisibleonlastpage") : -1; if (firstvisible != lastRequestedFirstvisible && scrollBody != null) { - // received 'surprising' firstvisible from server: scroll there - firstRowInViewPort = firstvisible; + // Update lastRequestedFirstvisible right away here // (don't rely on update in the timer which could be cancelled). lastRequestedFirstvisible = firstRowInViewPort; - /* - * Schedule the scrolling to be executed last so no updates to the - * rows affect scrolling measurements. - */ - Scheduler.get().scheduleFinally(lazyScroller); + // Only scroll if the first visible changes from the server side. + // Else we might unintentionally scroll even when the scroll + // position has not changed. + Scheduler.get().scheduleDeferred(lazyScroller); } } @@ -2153,16 +2174,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets, isNewBody = false; if (firstvisible > 0) { - // Deferred due to some Firefox oddities - Scheduler.get().scheduleDeferred(new Command() { - - @Override - public void execute() { - scrollBodyPanel - .setScrollPosition(measureRowHeightOffset(firstvisible)); - firstRowInViewPort = firstvisible; - } - }); + Scheduler.get().scheduleDeferred(lazyScroller); } if (enabled) { @@ -6125,7 +6137,13 @@ public class VScrollTable extends FlowPanel implements HasWidgets, .next(); setRowFocus(endRow); } + } else if (!startRow.isSelected()) { + // The start row is no longer selected (probably removed) + // and so we select from above + startRow = (VScrollTableRow) scrollBody.iterator().next(); + setRowFocus(endRow); } + // Deselect previous items if so desired if (deselectPrevious) { deselectAll(); @@ -6911,6 +6929,11 @@ public class VScrollTable extends FlowPanel implements HasWidgets, // fix footers horizontal scrolling tFoot.setHorizontalScrollPosition(scrollLeft); + if (totalRows == 0) { + // No rows, no need to fetch new rows + return; + } + firstRowInViewPort = calcFirstRowInViewPort(); if (firstRowInViewPort > totalRows - pageLength) { firstRowInViewPort = totalRows - pageLength; diff --git a/client/src/com/vaadin/client/ui/VTabsheet.java b/client/src/com/vaadin/client/ui/VTabsheet.java index fe29e2ebc0..7dec62bde0 100644 --- a/client/src/com/vaadin/client/ui/VTabsheet.java +++ b/client/src/com/vaadin/client/ui/VTabsheet.java @@ -1115,14 +1115,16 @@ public class VTabsheet extends VTabsheetBase implements Focusable, if (event.getSource() instanceof Tab) { int keycode = event.getNativeEvent().getKeyCode(); - if (keycode == getPreviousTabKey()) { - selectPreviousTab(); - } else if (keycode == getNextTabKey()) { - selectNextTab(); - } else if (keycode == getCloseTabKey()) { - Tab tab = tb.getTab(activeTabIndex); - if (tab.isClosable()) { - tab.onClose(); + if (!event.isAnyModifierKeyDown()) { + if (keycode == getPreviousTabKey()) { + selectPreviousTab(); + } else if (keycode == getNextTabKey()) { + selectNextTab(); + } else if (keycode == getCloseTabKey()) { + Tab tab = tb.getTab(activeTabIndex); + if (tab.isClosable()) { + tab.onClose(); + } } } } diff --git a/client/src/com/vaadin/client/ui/datefield/PopupDateFieldConnector.java b/client/src/com/vaadin/client/ui/datefield/PopupDateFieldConnector.java index 627478ebe5..f018caefa5 100644 --- a/client/src/com/vaadin/client/ui/datefield/PopupDateFieldConnector.java +++ b/client/src/com/vaadin/client/ui/datefield/PopupDateFieldConnector.java @@ -77,9 +77,6 @@ public class PopupDateFieldConnector extends TextualDateConnector { String oldLocale = getWidget().getCurrentLocale(); - boolean lastReadOnlyState = getWidget().isReadonly(); - boolean lastEnabledState = getWidget().isEnabled(); - getWidget().parsable = uidl.getBooleanAttribute("parsable"); super.updateFromUIDL(uidl, client); @@ -92,7 +89,8 @@ public class PopupDateFieldConnector extends TextualDateConnector { .getCurrentResolution()) { getWidget().calendar.setResolution(getWidget() .getCurrentResolution()); - if (getWidget().calendar.getDate() != null) { + if (getWidget().calendar.getDate() != null + && getWidget().getCurrentDate() != null) { getWidget().calendar.setDate((Date) getWidget() .getCurrentDate().clone()); // force re-render when changing resolution only @@ -101,7 +99,7 @@ public class PopupDateFieldConnector extends TextualDateConnector { } // Force re-render of calendar if locale has changed (#12153) - if (getWidget().getCurrentLocale() != oldLocale) { + if (!getWidget().getCurrentLocale().equals(oldLocale)) { getWidget().calendar.renderCalendar(); } @@ -113,6 +111,7 @@ public class PopupDateFieldConnector extends TextualDateConnector { .setFocusChangeListener(new FocusChangeListener() { @Override public void focusChanged(Date date) { + getWidget().updateValue(date); getWidget().buildDate(); Date date2 = getWidget().calendar.getDate(); diff --git a/client/src/com/vaadin/client/ui/dd/VDragAndDropManager.java b/client/src/com/vaadin/client/ui/dd/VDragAndDropManager.java index b4cf008a38..b911c28a07 100644 --- a/client/src/com/vaadin/client/ui/dd/VDragAndDropManager.java +++ b/client/src/com/vaadin/client/ui/dd/VDragAndDropManager.java @@ -374,6 +374,17 @@ public class VDragAndDropManager { public void onPreviewNativeEvent( NativePreviewEvent event) { int typeInt = event.getTypeInt(); + if (typeInt == -1 + && event.getNativeEvent().getType() + .contains("MSPointer")) { + /* + * Ignore MSPointer events, until they are + * properly used (might improve usability on + * touch devices). + */ + return; + } + switch (typeInt) { case Event.ONMOUSEOVER: if (dragElement == null) { diff --git a/client/src/com/vaadin/client/ui/dd/VTargetInSubtree.java b/client/src/com/vaadin/client/ui/dd/VTargetInSubtree.java index e9061114aa..c3f56b410d 100644 --- a/client/src/com/vaadin/client/ui/dd/VTargetInSubtree.java +++ b/client/src/com/vaadin/client/ui/dd/VTargetInSubtree.java @@ -32,7 +32,7 @@ final public class VTargetInSubtree extends VAcceptCriterion { protected boolean accept(VDragEvent drag, UIDL configuration) { VTree tree = (VTree) VDragAndDropManager.get().getCurrentDropHandler() - .getConnector(); + .getConnector().getWidget(); TreeNode treeNode = tree.getNodeByKey((String) drag.getDropDetails() .get("itemIdOver")); if (treeNode != null) { @@ -53,4 +53,4 @@ final public class VTargetInSubtree extends VAcceptCriterion { return false; } -}
\ No newline at end of file +} diff --git a/client/src/com/vaadin/client/ui/orderedlayout/AbstractOrderedLayoutConnector.java b/client/src/com/vaadin/client/ui/orderedlayout/AbstractOrderedLayoutConnector.java index e0dc0d51df..ec4307e50b 100644 --- a/client/src/com/vaadin/client/ui/orderedlayout/AbstractOrderedLayoutConnector.java +++ b/client/src/com/vaadin/client/ui/orderedlayout/AbstractOrderedLayoutConnector.java @@ -19,6 +19,7 @@ import java.util.List; import com.google.gwt.dom.client.Style.Unit; import com.google.gwt.user.client.Element; +import com.google.gwt.user.client.ui.Widget; import com.vaadin.client.ApplicationConnection; import com.vaadin.client.ComponentConnector; import com.vaadin.client.ConnectorHierarchyChangeEvent; @@ -611,13 +612,14 @@ public abstract class AbstractOrderedLayoutConnector extends LayoutManager layoutManager = getLayoutManager(); for (ComponentConnector child : getChildComponents()) { - Slot slot = getWidget().getSlot(child.getWidget()); + Widget childWidget = child.getWidget(); + Slot slot = getWidget().getSlot(childWidget); Element captionElement = slot.getCaptionElement(); - CaptionPosition pos = slot.getCaptionPosition(); + CaptionPosition captionPosition = slot.getCaptionPosition(); - Element childElement = child.getWidget().getElement(); - int h = layoutManager.getOuterHeight(childElement); - if (h == -1) { + int pixelHeight = layoutManager.getOuterHeight(childWidget + .getElement()); + if (pixelHeight == -1) { // Height has not yet been measured -> postpone actions that // depend on the max height return -1; @@ -625,14 +627,10 @@ public abstract class AbstractOrderedLayoutConnector extends boolean hasRelativeHeight = slot.hasRelativeHeight(); + boolean captionSizeShouldBeAddedtoComponentHeight = captionPosition == CaptionPosition.TOP + || captionPosition == CaptionPosition.BOTTOM; boolean includeCaptionHeight = captionElement != null - && (pos == CaptionPosition.TOP || pos == CaptionPosition.BOTTOM); - if (!hasRelativeHeight && !includeCaptionHeight - && captionElement != null) { - String sHeight = childElement.getStyle().getHeight(); - includeCaptionHeight = (sHeight == null || !sHeight - .endsWith("%")); - } + && captionSizeShouldBeAddedtoComponentHeight; if (includeCaptionHeight) { int captionHeight = layoutManager @@ -643,16 +641,16 @@ public abstract class AbstractOrderedLayoutConnector extends // depend on the max height return -1; } - h += captionHeight; + pixelHeight += captionHeight; } if (!hasRelativeHeight) { - if (h > highestNonRelative) { - highestNonRelative = h; + if (pixelHeight > highestNonRelative) { + highestNonRelative = pixelHeight; } } else { - if (h > highestRelative) { - highestRelative = h; + if (pixelHeight > highestRelative) { + highestRelative = pixelHeight; } } } diff --git a/client/src/com/vaadin/client/ui/slider/SliderConnector.java b/client/src/com/vaadin/client/ui/slider/SliderConnector.java index e6e3e0467d..71462d69f0 100644 --- a/client/src/com/vaadin/client/ui/slider/SliderConnector.java +++ b/client/src/com/vaadin/client/ui/slider/SliderConnector.java @@ -52,6 +52,7 @@ public class SliderConnector extends AbstractFieldConnector implements @Override public void onValueChange(ValueChangeEvent<Double> event) { + getState().value = event.getValue(); rpc.valueChanged(event.getValue()); } diff --git a/client/src/com/vaadin/client/ui/ui/UIConnector.java b/client/src/com/vaadin/client/ui/ui/UIConnector.java index c6d2e1436b..46b5f63180 100644 --- a/client/src/com/vaadin/client/ui/ui/UIConnector.java +++ b/client/src/com/vaadin/client/ui/ui/UIConnector.java @@ -319,6 +319,11 @@ public class UIConnector extends AbstractSingleComponentContainerConnector ComponentConnector paintable = (ComponentConnector) uidl .getPaintableAttribute("focused", getConnection()); + if (paintable == null) { + // Do not try to focus invisible components which not present in UIDL + return; + } + final Widget toBeFocused = paintable.getWidget(); /* * Two types of Widgets can be focused, either implementing diff --git a/client/tests/src/com/vaadin/client/TestVBrowserDetailsUserAgentParser.java b/client/tests/src/com/vaadin/client/TestVBrowserDetailsUserAgentParser.java index 7d5911f5a0..5b428574e2 100644 --- a/client/tests/src/com/vaadin/client/TestVBrowserDetailsUserAgentParser.java +++ b/client/tests/src/com/vaadin/client/TestVBrowserDetailsUserAgentParser.java @@ -27,6 +27,7 @@ public class TestVBrowserDetailsUserAgentParser extends TestCase { private static final String IE9_BETA_WINDOWS_7 = "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)"; private static final String IE10_WINDOWS_8 = "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)"; + private static final String IE11_WINDOWS_7 = "Mozilla/5.0 (Windows NT 6.1; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; rv:11.0) like Gecko"; // "Version/" was added in 10.00 private static final String OPERA964_WINDOWS = "Opera/9.64(Windows NT 5.1; U; en) Presto/2.1.1"; @@ -314,6 +315,7 @@ public class TestVBrowserDetailsUserAgentParser extends TestCase { public void testIE8() { VBrowserDetails bd = new VBrowserDetails(IE8_WINDOWS); + assertTrident(bd); assertEngineVersion(bd, 4); assertIE(bd); assertBrowserMajorVersion(bd, 8); @@ -325,6 +327,7 @@ public class TestVBrowserDetailsUserAgentParser extends TestCase { VBrowserDetails bd = new VBrowserDetails(IE8_IN_IE7_MODE_WINDOWS); bd.setIEMode(7); + assertTrident(bd); assertEngineVersion(bd, 4); assertIE(bd); assertBrowserMajorVersion(bd, 7); @@ -335,6 +338,7 @@ public class TestVBrowserDetailsUserAgentParser extends TestCase { public void testIE9() { VBrowserDetails bd = new VBrowserDetails(IE9_BETA_WINDOWS_7); + assertTrident(bd); assertEngineVersion(bd, 5); assertIE(bd); assertBrowserMajorVersion(bd, 9); @@ -346,6 +350,7 @@ public class TestVBrowserDetailsUserAgentParser extends TestCase { VBrowserDetails bd = new VBrowserDetails(IE9_IN_IE7_MODE_WINDOWS_7); // bd.setIE8InCompatibilityMode(); + assertTrident(bd); assertEngineVersion(bd, 5); assertIE(bd); assertBrowserMajorVersion(bd, 7); @@ -362,6 +367,7 @@ public class TestVBrowserDetailsUserAgentParser extends TestCase { * Trident/4.0 in example user agent string based on beta even though it * should be Trident/5.0 in real (non-beta) user agent strings */ + assertTrident(bd); assertEngineVersion(bd, 4); assertIE(bd); assertBrowserMajorVersion(bd, 8); @@ -372,6 +378,7 @@ public class TestVBrowserDetailsUserAgentParser extends TestCase { public void testIE10() { VBrowserDetails bd = new VBrowserDetails(IE10_WINDOWS_8); + assertTrident(bd); assertEngineVersion(bd, 6); assertIE(bd); assertBrowserMajorVersion(bd, 10); @@ -379,6 +386,16 @@ public class TestVBrowserDetailsUserAgentParser extends TestCase { assertWindows(bd); } + public void testIE11() { + VBrowserDetails bd = new VBrowserDetails(IE11_WINDOWS_7); + assertTrident(bd); + assertEngineVersion(bd, 7); + assertIE(bd); + assertBrowserMajorVersion(bd, 11); + assertBrowserMinorVersion(bd, 0); + assertWindows(bd); + } + /* * Helper methods below */ @@ -406,6 +423,7 @@ public class TestVBrowserDetailsUserAgentParser extends TestCase { assertTrue(browserDetails.isGecko()); assertFalse(browserDetails.isWebKit()); assertFalse(browserDetails.isPresto()); + assertFalse(browserDetails.isTrident()); } private void assertPresto(VBrowserDetails browserDetails) { @@ -413,6 +431,15 @@ public class TestVBrowserDetailsUserAgentParser extends TestCase { assertFalse(browserDetails.isGecko()); assertFalse(browserDetails.isWebKit()); assertTrue(browserDetails.isPresto()); + assertFalse(browserDetails.isTrident()); + } + + private void assertTrident(VBrowserDetails browserDetails) { + // Engine + assertFalse(browserDetails.isGecko()); + assertFalse(browserDetails.isWebKit()); + assertFalse(browserDetails.isPresto()); + assertTrue(browserDetails.isTrident()); } private void assertWebKit(VBrowserDetails browserDetails) { @@ -420,6 +447,7 @@ public class TestVBrowserDetailsUserAgentParser extends TestCase { assertFalse(browserDetails.isGecko()); assertTrue(browserDetails.isWebKit()); assertFalse(browserDetails.isPresto()); + assertFalse(browserDetails.isTrident()); } private void assertFirefox(VBrowserDetails browserDetails) { diff --git a/ivysettings.xml b/ivysettings.xml index fa08f3d0bb..e18b2233d1 100644 --- a/ivysettings.xml +++ b/ivysettings.xml @@ -11,6 +11,8 @@ <settings defaultResolver="public" /> <resolvers> <ibiblio name="public" m2compatible="true" /> + <ibiblio name="vaadin-addons" usepoms="true" + m2compatible="true" root="http://maven.vaadin.com/vaadin-addons" /> <filesystem name="local-maven" m2compatible="true"> <artifact pattern="${user.home}/.m2/repository/[organisation]/[module]/[revision]/[artifact]-[revision](-[classifier]).[ext]" /> @@ -23,6 +25,8 @@ </filesystem> </resolvers> <modules> + <module organisation="com.vaadin" name="vaadin-testbench" + resolver="vaadin-addons" /> <module organisation="com.vaadin" name="vaadin-buildhelpers" resolver="build-temp" /> <module organisation="com.vaadin" name="vaadin-shared" diff --git a/server/ivy.xml b/server/ivy.xml index b78541c52f..ba859b08ee 100644 --- a/server/ivy.xml +++ b/server/ivy.xml @@ -58,7 +58,7 @@ <!-- TESTING DEPENDENCIES --> <!-- Test frameworks & related --> - <dependency org="junit" name="junit" rev="4.5" + <dependency org="junit" name="junit" rev="4.11" conf="test,ide -> default" /> <dependency org="org.easymock" name="easymock" rev="3.0" conf="test,ide-> default" transitive="true" /> diff --git a/server/src/com/vaadin/server/VaadinPortlet.java b/server/src/com/vaadin/server/VaadinPortlet.java index d86e5e6507..093a1c9152 100644 --- a/server/src/com/vaadin/server/VaadinPortlet.java +++ b/server/src/com/vaadin/server/VaadinPortlet.java @@ -422,16 +422,37 @@ public class VaadinPortlet extends GenericPortlet implements Constants, * @return A wrapped version of the PorletRequest */ protected VaadinPortletRequest createVaadinRequest(PortletRequest request) { - String portalInfo = request.getPortalContext().getPortalInfo() - .toLowerCase(); - if (portalInfo.contains("liferay")) { + if (isLiferay(request)) { return new VaadinLiferayRequest(request, getService()); - } else if (portalInfo.contains("gatein")) { + } else if (isGateIn(request)) { return new VaadinGateinRequest(request, getService()); } else { return new VaadinPortletRequest(request, getService()); } + } + /** + * Returns true if the portlet request is from Liferay. + * + * @param request + * @return True if Liferay, false otherwise + */ + private static boolean isLiferay(PortletRequest request) { + String portalInfo = request.getPortalContext().getPortalInfo() + .toLowerCase(); + return portalInfo.contains("liferay"); + } + + /** + * Returns true if the portlet request if from GateIn + * + * @param request + * @return True if GateIn, false otherwise + */ + private static boolean isGateIn(PortletRequest request) { + String portalInfo = request.getPortalContext().getPortalInfo() + .toLowerCase(); + return portalInfo.contains("gatein"); } private VaadinPortletResponse createVaadinResponse(PortletResponse response) { diff --git a/server/src/com/vaadin/server/VaadinSession.java b/server/src/com/vaadin/server/VaadinSession.java index 1f7a577a42..c73ac8b686 100644 --- a/server/src/com/vaadin/server/VaadinSession.java +++ b/server/src/com/vaadin/server/VaadinSession.java @@ -16,6 +16,8 @@ package com.vaadin.server; +import java.io.IOException; +import java.io.ObjectInputStream; import java.io.Serializable; import java.lang.reflect.Method; import java.util.Collection; @@ -203,10 +205,10 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { * session is serialized as long as it doesn't happen while some other * thread has the lock. */ - private transient ConcurrentLinkedQueue<FutureAccess> pendingAccessQueue; + private transient ConcurrentLinkedQueue<FutureAccess> pendingAccessQueue = new ConcurrentLinkedQueue<FutureAccess>(); /** - * Create a new service session tied to a Vaadin service + * Creates a new VaadinSession tied to a VaadinService. * * @param service * the Vaadin service for the new session @@ -1272,18 +1274,15 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { } /** - * Gets the queue of tasks submitted using {@link #access(Runnable)}. + * Gets the queue of tasks submitted using {@link #access(Runnable)}. It is + * safe to call this method and access the returned queue without holding + * the {@link #lock() session lock}. * * @since 7.1 * - * @return the pending access queue + * @return the queue of pending access tasks */ public Queue<FutureAccess> getPendingAccessQueue() { - if (pendingAccessQueue == null) { - // pendingAccessQueue is transient, so will be null after - // deserialization - pendingAccessQueue = new ConcurrentLinkedQueue<FutureAccess>(); - } return pendingAccessQueue; } @@ -1299,4 +1298,13 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { return csrfToken; } + /** + * Override default deserialization logic to account for transient + * {@link #pendingAccessQueue}. + */ + private void readObject(ObjectInputStream stream) throws IOException, + ClassNotFoundException { + stream.defaultReadObject(); + pendingAccessQueue = new ConcurrentLinkedQueue<FutureAccess>(); + } } diff --git a/server/src/com/vaadin/server/communication/PortletBootstrapHandler.java b/server/src/com/vaadin/server/communication/PortletBootstrapHandler.java index 2458951ada..dd6d3c9283 100644 --- a/server/src/com/vaadin/server/communication/PortletBootstrapHandler.java +++ b/server/src/com/vaadin/server/communication/PortletBootstrapHandler.java @@ -31,6 +31,7 @@ import org.json.JSONObject; import com.vaadin.server.BootstrapHandler; import com.vaadin.server.PaintException; import com.vaadin.server.VaadinPortlet; +import com.vaadin.server.VaadinPortlet.VaadinLiferayRequest; import com.vaadin.server.VaadinPortletRequest; import com.vaadin.server.VaadinPortletResponse; import com.vaadin.server.VaadinRequest; @@ -98,6 +99,8 @@ public class PortletBootstrapHandler extends BootstrapHandler { JSONObject parameters = super.getApplicationParameters(context); VaadinPortletResponse response = (VaadinPortletResponse) context .getResponse(); + VaadinPortletRequest request = (VaadinPortletRequest) context + .getRequest(); MimeResponse portletResponse = (MimeResponse) response .getPortletResponse(); ResourceURL resourceURL = portletResponse.createResourceURL(); @@ -108,6 +111,14 @@ public class PortletBootstrapHandler extends BootstrapHandler { parameters .put(ApplicationConstants.SERVICE_URL_PATH_AS_PARAMETER, true); + // If we are running in Liferay then we need to prefix all parameters + // with the portlet namespace + if (request instanceof VaadinLiferayRequest) { + parameters.put( + ApplicationConstants.SERVICE_URL_PARAMETER_NAMESPACE, + response.getPortletResponse().getNamespace()); + } + return parameters; } }
\ No newline at end of file diff --git a/server/src/com/vaadin/server/communication/UidlRequestHandler.java b/server/src/com/vaadin/server/communication/UidlRequestHandler.java index d52c5e9fe0..f13199e9ae 100644 --- a/server/src/com/vaadin/server/communication/UidlRequestHandler.java +++ b/server/src/com/vaadin/server/communication/UidlRequestHandler.java @@ -56,8 +56,7 @@ public class UidlRequestHandler extends SynchronizedRequestHandler implements private ServerRpcHandler rpcHandler = new ServerRpcHandler(); - public UidlRequestHandler() { - } + private UidlWriter uidlWriter = new UidlWriter(); @Override public boolean synchronizedHandleRequest(VaadinSession session, @@ -146,7 +145,7 @@ public class UidlRequestHandler extends SynchronizedRequestHandler implements JSONException { openJsonMessage(writer, response); - new UidlWriter().write(ui, writer, repaintAll, false); + uidlWriter.write(ui, writer, repaintAll, false); closeJsonMessage(writer); } diff --git a/server/src/com/vaadin/server/communication/UidlWriter.java b/server/src/com/vaadin/server/communication/UidlWriter.java index 60933a75c2..fe7a7d42bf 100644 --- a/server/src/com/vaadin/server/communication/UidlWriter.java +++ b/server/src/com/vaadin/server/communication/UidlWriter.java @@ -51,6 +51,14 @@ import com.vaadin.ui.UI; */ public class UidlWriter implements Serializable { + private LegacyUidlWriter legacyUidlWriter = new LegacyUidlWriter(); + private SharedStateWriter sharedStateWriter = new SharedStateWriter(); + private ConnectorTypeWriter connectorTypeWriter = new ConnectorTypeWriter(); + private ConnectorHierarchyWriter connectorHierarchyWriter = new ConnectorHierarchyWriter(); + private ClientRpcWriter clientRpcWriter = new ClientRpcWriter(); + private MetadataWriter metadataWriter = new MetadataWriter(); + private ResourceWriter resourceWriter = new ResourceWriter(); + /** * Writes a JSON object containing all pending changes to the given UI. * @@ -79,13 +87,12 @@ public class UidlWriter implements Serializable { // to write out session.getService().runPendingAccessTasks(session); - ArrayList<ClientConnector> dirtyVisibleConnectors = ui - .getConnectorTracker().getDirtyVisibleConnectors(); - LegacyCommunicationManager manager = session.getCommunicationManager(); // Paints components - ConnectorTracker uiConnectorTracker = ui.getConnectorTracker(); getLogger().log(Level.FINE, "* Creating response to client"); + ConnectorTracker uiConnectorTracker = ui.getConnectorTracker(); + ArrayList<ClientConnector> dirtyVisibleConnectors = uiConnectorTracker + .getDirtyVisibleConnectors(); getLogger().log( Level.FINE, "Found " + dirtyVisibleConnectors.size() @@ -100,10 +107,13 @@ public class UidlWriter implements Serializable { try { writer.write("\"changes\" : "); + LegacyCommunicationManager manager = session + .getCommunicationManager(); + JsonPaintTarget paintTarget = new JsonPaintTarget(manager, writer, !repaintAll); - new LegacyUidlWriter().write(ui, writer, paintTarget); + legacyUidlWriter.write(ui, writer, paintTarget); paintTarget.close(); writer.write(", "); // close changes @@ -120,7 +130,7 @@ public class UidlWriter implements Serializable { // processing. writer.write("\"state\":"); - new SharedStateWriter().write(ui, writer); + sharedStateWriter.write(ui, writer); writer.write(", "); // close states // TODO This should be optimized. The type only needs to be @@ -129,7 +139,7 @@ public class UidlWriter implements Serializable { // widget mapping writer.write("\"types\":"); - new ConnectorTypeWriter().write(ui, writer, paintTarget); + connectorTypeWriter.write(ui, writer, paintTarget); writer.write(", "); // close states // Send update hierarchy information to the client. @@ -140,7 +150,7 @@ public class UidlWriter implements Serializable { // child to 0 children) writer.write("\"hierarchy\":"); - new ConnectorHierarchyWriter().write(ui, writer); + connectorHierarchyWriter.write(ui, writer); writer.write(", "); // close hierarchy // send server to client RPC calls for components in the UI, in call @@ -150,7 +160,7 @@ public class UidlWriter implements Serializable { // which they were performed, remove the calls from components writer.write("\"rpc\" : "); - new ClientRpcWriter().write(ui, writer); + clientRpcWriter.write(ui, writer); writer.write(", "); // close rpc uiConnectorTracker.markAllConnectorsClean(); @@ -160,11 +170,11 @@ public class UidlWriter implements Serializable { SystemMessages messages = ui.getSession().getService() .getSystemMessages(ui.getLocale(), null); // TODO hilightedConnector - new MetadataWriter().write(ui, writer, repaintAll, async, messages); + metadataWriter.write(ui, writer, repaintAll, async, messages); writer.write(", "); writer.write("\"resources\" : "); - new ResourceWriter().write(ui, writer, paintTarget); + resourceWriter.write(ui, writer, paintTarget); Collection<Class<? extends ClientConnector>> usedClientConnectors = paintTarget .getUsedClientConnectors(); diff --git a/server/src/com/vaadin/ui/Table.java b/server/src/com/vaadin/ui/Table.java index bd2b7828de..32ed738697 100644 --- a/server/src/com/vaadin/ui/Table.java +++ b/server/src/com/vaadin/ui/Table.java @@ -427,6 +427,12 @@ public class Table extends AbstractSelect implements Action.Container, private int currentPageFirstItemIndex = 0; /** + * Index of the "first" item on the last page if a user has used + * setCurrentPageFirstItemIndex to scroll down. -1 if not set. + */ + private int currentPageFirstItemIndexOnLastPage = -1; + + /** * Holds value of property selectable. */ private boolean selectable = false; @@ -1477,12 +1483,14 @@ public class Table extends AbstractSelect implements Action.Container, } /* - * FIXME #7607 Take somehow into account the case where we want to - * scroll to the bottom so that the last row is completely visible even - * if (table height) / (row height) is not an integer. Reverted the - * original fix because of #8662 regression. + * If the new index is on the last page we set the index to be the first + * item on that last page and make a note of the real index for the + * client side to be able to move the scroll position to the correct + * position. */ + int indexOnLastPage = -1; if (newIndex > maxIndex) { + indexOnLastPage = newIndex; newIndex = maxIndex; } @@ -1494,6 +1502,20 @@ public class Table extends AbstractSelect implements Action.Container, currentPageFirstItemId = null; } currentPageFirstItemIndex = newIndex; + + if (needsPageBufferReset) { + /* + * The flag currentPageFirstItemIndexOnLastPage denotes a user + * set scrolling position on the last page via + * setCurrentPageFirstItemIndex() and shouldn't be changed by + * the table component internally changing the firstvisible item + * on lazy row fetching. Doing so would make the scrolling + * position not be updated correctly when the lazy rows are + * finally rendered. + */ + currentPageFirstItemIndexOnLastPage = indexOnLastPage; + } + } else { // For containers not supporting indexes, we must iterate the @@ -3447,6 +3469,8 @@ public class Table extends AbstractSelect implements Action.Container, if (getCurrentPageFirstItemIndex() != 0 || getPageLength() > 0) { target.addVariable(this, "firstvisible", getCurrentPageFirstItemIndex()); + target.addVariable(this, "firstvisibleonlastpage", + currentPageFirstItemIndexOnLastPage); } } diff --git a/server/src/com/vaadin/ui/UI.java b/server/src/com/vaadin/ui/UI.java index 0746431302..27f04c39e1 100644 --- a/server/src/com/vaadin/ui/UI.java +++ b/server/src/com/vaadin/ui/UI.java @@ -402,9 +402,12 @@ public abstract class UI extends AbstractSingleComponentContainer implements * @see #getSession() */ public void setSession(VaadinSession session) { - if ((session == null) == (this.session == null)) { + if (session == null && this.session == null) { throw new IllegalStateException( - "VaadinServiceSession has already been set. Old session: " + "Session should never be set to null when UI.session is already null"); + } else if (session != null && this.session != null) { + throw new IllegalStateException( + "Session has already been set. Old session: " + getSessionDetails(this.session) + ". New session: " + getSessionDetails(session) + "."); diff --git a/server/tests/src/com/vaadin/server/communication/UidlWriterTest.java b/server/tests/src/com/vaadin/server/communication/UidlWriterTest.java new file mode 100644 index 0000000000..8dcd6cbdf4 --- /dev/null +++ b/server/tests/src/com/vaadin/server/communication/UidlWriterTest.java @@ -0,0 +1,125 @@ +/* + * 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.server.communication; + +import java.io.IOException; +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.Locale; + +import org.easymock.EasyMock; +import org.json.JSONException; +import org.json.JSONObject; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import com.vaadin.server.ClientConnector; +import com.vaadin.server.LegacyCommunicationManager; +import com.vaadin.server.SystemMessages; +import com.vaadin.server.VaadinRequest; +import com.vaadin.server.VaadinService; +import com.vaadin.server.VaadinSession; +import com.vaadin.server.WrappedSession; +import com.vaadin.ui.ConnectorTracker; +import com.vaadin.ui.UI; + +/** + * + * @since + * @author Vaadin Ltd + */ +public class UidlWriterTest { + + private UI ui; + private UidlWriter uidlWriter; + + @Before + public void setUp() { + SystemMessages messages = EasyMock.createNiceMock(SystemMessages.class); + EasyMock.expect(messages.isSessionExpiredNotificationEnabled()) + .andReturn(true).anyTimes(); + EasyMock.replay(messages); + + VaadinService service = EasyMock.createNiceMock(VaadinService.class); + EasyMock.expect( + service.getSystemMessages(EasyMock.anyObject(Locale.class), + EasyMock.anyObject(VaadinRequest.class))) + .andReturn(messages).anyTimes(); + EasyMock.replay(service); + + LegacyCommunicationManager manager = EasyMock + .createNiceMock(LegacyCommunicationManager.class); + EasyMock.replay(manager); + + WrappedSession wrappedSession = EasyMock + .createNiceMock(WrappedSession.class); + EasyMock.expect(wrappedSession.getMaxInactiveInterval()).andReturn(100) + .times(3).andReturn(200); + + EasyMock.replay(wrappedSession); + + VaadinSession session = EasyMock.createNiceMock(VaadinSession.class); + EasyMock.expect(session.getService()).andReturn(service).anyTimes(); + EasyMock.expect(session.getCommunicationManager()).andReturn(manager) + .anyTimes(); + EasyMock.expect(session.getSession()).andReturn(wrappedSession) + .anyTimes(); + EasyMock.replay(session); + + ConnectorTracker tracker = EasyMock + .createNiceMock(ConnectorTracker.class); + EasyMock.expect(tracker.getDirtyVisibleConnectors()) + .andReturn(new ArrayList<ClientConnector>()).anyTimes(); + EasyMock.replay(tracker); + + ui = EasyMock.createNiceMock(UI.class); + EasyMock.expect(ui.getSession()).andReturn(session).anyTimes(); + EasyMock.expect(ui.getConnectorTracker()).andReturn(tracker).anyTimes(); + EasyMock.replay(ui); + + uidlWriter = new UidlWriter(); + } + + @Test + public void testMetadataWriterState() throws IOException, JSONException { + + Assert.assertEquals( + "Metadata should contain redirect interval on first write", + 115, getRedirect(uidl(false, false)).optInt("interval")); + Assert.assertNull( + "Metadata should not contain redirect interval on second write", + getRedirect(uidl(false, false))); + Assert.assertEquals( + "Metadata should contain redirect interval on repaintAll", 115, + getRedirect(uidl(true, false)).optInt("interval")); + Assert.assertEquals( + "Metadata should contain redirect interval when changed in session", + 215, getRedirect(uidl(false, false)).optInt("interval")); + } + + private JSONObject uidl(boolean repaintAll, boolean async) + throws IOException, JSONException { + StringWriter writer = new StringWriter(); + uidlWriter.write(ui, writer, repaintAll, async); + return new JSONObject("{" + writer.toString() + "}"); + } + + private JSONObject getRedirect(JSONObject json) throws JSONException { + return json.getJSONObject("meta").optJSONObject("timedRedirect"); + + } +} diff --git a/server/tests/src/com/vaadin/tests/server/TestSerialization.java b/server/tests/src/com/vaadin/tests/server/TestSerialization.java index 84ff5ad6fa..a52821a919 100644 --- a/server/tests/src/com/vaadin/tests/server/TestSerialization.java +++ b/server/tests/src/com/vaadin/tests/server/TestSerialization.java @@ -14,6 +14,7 @@ import com.vaadin.data.Property; import com.vaadin.data.util.IndexedContainer; import com.vaadin.data.util.MethodProperty; import com.vaadin.data.validator.RegexpValidator; +import com.vaadin.server.VaadinSession; import com.vaadin.ui.Form; public class TestSerialization extends TestCase { @@ -21,7 +22,7 @@ public class TestSerialization extends TestCase { public void testValidators() throws Exception { RegexpValidator validator = new RegexpValidator(".*", "Error"); validator.validate("aaa"); - RegexpValidator validator2 = (RegexpValidator) serializeAndDeserialize(validator); + RegexpValidator validator2 = serializeAndDeserialize(validator); validator2.validate("aaa"); } @@ -67,7 +68,17 @@ public class TestSerialization extends TestCase { serializeAndDeserialize(mp); } - private static Serializable serializeAndDeserialize(Serializable s) + public void testVaadinSession() throws Exception { + VaadinSession session = new VaadinSession(null); + + session = serializeAndDeserialize(session); + + assertNotNull( + "Pending access queue was not recreated after deserialization", + session.getPendingAccessQueue()); + } + + private static <S extends Serializable> S serializeAndDeserialize(S s) throws IOException, ClassNotFoundException { // Serialize and deserialize @@ -77,10 +88,12 @@ public class TestSerialization extends TestCase { byte[] data = bs.toByteArray(); ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream( data)); - Serializable s2 = (Serializable) in.readObject(); + @SuppressWarnings("unchecked") + S s2 = (S) in.readObject(); // using special toString(Object) method to avoid calling // Property.toString(), which will be temporarily disabled + // TODO This is hilariously broken (#12723) if (s.equals(s2)) { System.out.println(toString(s) + " equals " + toString(s2)); } else { diff --git a/server/tests/src/com/vaadin/tests/server/component/abstractfield/AbsFieldValueConversions.java b/server/tests/src/com/vaadin/tests/server/component/abstractfield/AbsFieldValueConversions.java index 9854296538..a5e825bddb 100644 --- a/server/tests/src/com/vaadin/tests/server/component/abstractfield/AbsFieldValueConversions.java +++ b/server/tests/src/com/vaadin/tests/server/component/abstractfield/AbsFieldValueConversions.java @@ -249,6 +249,7 @@ public class AbsFieldValueConversions extends TestCase { @Test public void testNullConverter() { TextField tf = new TextField("foo"); + tf.setConverter(new StringToIntegerConverter()); tf.setPropertyDataSource(new ObjectProperty<Integer>(12)); tf.setConverter((Converter) null); try { diff --git a/shared/src/com/vaadin/shared/ApplicationConstants.java b/shared/src/com/vaadin/shared/ApplicationConstants.java index 104f3047a8..4b5dc9140b 100644 --- a/shared/src/com/vaadin/shared/ApplicationConstants.java +++ b/shared/src/com/vaadin/shared/ApplicationConstants.java @@ -49,6 +49,10 @@ public class ApplicationConstants implements Serializable { public static final String SERVICE_URL_PATH_AS_PARAMETER = "usePathParameter"; + // Denotes the namespace which parameters should be prefixed with when + // passed as GET parameters. Currently only used by Liferay. + public static final String SERVICE_URL_PARAMETER_NAMESPACE = "pathParameterNS"; + // Javadocs in ApplicationConfiguration should be updated if this is changed public static final String V_RESOURCE_PATH = "v-resourcePath"; diff --git a/shared/src/com/vaadin/shared/VBrowserDetails.java b/shared/src/com/vaadin/shared/VBrowserDetails.java index f31f5f3c04..a745a212b0 100644 --- a/shared/src/com/vaadin/shared/VBrowserDetails.java +++ b/shared/src/com/vaadin/shared/VBrowserDetails.java @@ -31,6 +31,7 @@ public class VBrowserDetails implements Serializable { private boolean isGecko = false; private boolean isWebKit = false; private boolean isPresto = false; + private boolean isTrident = false; private boolean isChromeFrameCapable = false; private boolean isChromeFrame = false; @@ -65,9 +66,11 @@ public class VBrowserDetails implements Serializable { // browser engine name isGecko = userAgent.indexOf("gecko") != -1 - && userAgent.indexOf("webkit") == -1; + && userAgent.indexOf("webkit") == -1 + && userAgent.indexOf("trident/") == -1; isWebKit = userAgent.indexOf("applewebkit") != -1; isPresto = userAgent.indexOf(" presto/") != -1; + isTrident = userAgent.indexOf("trident/") != -1; // browser name isChrome = userAgent.indexOf(" chrome/") != -1; @@ -75,6 +78,9 @@ public class VBrowserDetails implements Serializable { isOpera = userAgent.indexOf("opera") != -1; isIE = userAgent.indexOf("msie") != -1 && !isOpera && (userAgent.indexOf("webtv") == -1); + // IE 11 no longer contains MSIE in the user agent + isIE = isIE || isTrident; + isFirefox = userAgent.indexOf(" firefox/") != -1; // chromeframe @@ -113,11 +119,21 @@ public class VBrowserDetails implements Serializable { // Browser version try { if (isIE) { - String ieVersionString = userAgent.substring(userAgent - .indexOf("msie ") + 5); - ieVersionString = safeSubstring(ieVersionString, 0, - ieVersionString.indexOf(";")); - parseVersionString(ieVersionString); + if (userAgent.indexOf("msie") == -1) { + // IE 11+ + int rvPos = userAgent.indexOf("rv:"); + if (rvPos >= 0) { + String tmp = userAgent.substring(rvPos + 3); + tmp = tmp.replaceFirst("(\\.[0-9]+).+", "$1"); + parseVersionString(tmp); + } + } else { + String ieVersionString = userAgent.substring(userAgent + .indexOf("msie ") + 5); + ieVersionString = safeSubstring(ieVersionString, 0, + ieVersionString.indexOf(";")); + parseVersionString(ieVersionString); + } } else if (isFirefox) { int i = userAgent.indexOf(" firefox/") + 9; parseVersionString(safeSubstring(userAgent, i, i + 5)); @@ -288,6 +304,16 @@ public class VBrowserDetails implements Serializable { } /** + * Tests if the browser is using the Trident engine + * + * @since 7.1.7 + * @return true if it is Trident, false otherwise + */ + public boolean isTrident() { + return isTrident; + } + + /** * Tests if the browser is Safari. * * @return true if it is Safari, false otherwise diff --git a/theme-compiler/ivy.xml b/theme-compiler/ivy.xml index 5bcdbb54cb..7b99b2cdaa 100644 --- a/theme-compiler/ivy.xml +++ b/theme-compiler/ivy.xml @@ -40,7 +40,7 @@ rev="2.4" conf="build-provided->default" /> <!-- Testing libs --> - <dependency org="junit" name="junit" rev="4.5" + <dependency org="junit" name="junit" rev="4.11" conf="ide,test -> default" /> <!-- Internally used, for now --> diff --git a/uitest/build.xml b/uitest/build.xml index bd0f49ae1e..76b75e9203 100644 --- a/uitest/build.xml +++ b/uitest/build.xml @@ -9,6 +9,7 @@ <!-- global properties --> <property name="module.name" value="vaadin-uitest" /> + <property name="uitest.dir" location="${vaadin.basedir}/uitest" /> <property name="result.dir" value="result" /> <property name="result.war" location="${result.dir}/lib/${module.name}-${vaadin.version}.war" /> @@ -107,6 +108,11 @@ <path refid="classpath.runtime.dependencies" /> </copy> + <delete> + <!-- Avoid including some potentially conflicting jars in the war --> + <fileset dir="${deps.dir}" includes="jetty-*.jar" /> + <fileset dir="${deps.dir}" includes="servlet-api-*.jar" /> + </delete> <!-- Ensure filtered webcontent files are available --> <antcall target="common.filter.webcontent" /> @@ -148,4 +154,53 @@ <echo>WHAT? No JUnit tests for ${module.name}!</echo> </target> + <target name="test-testbench" depends="clean-testbench-errors" description="Run all TestBench based tests, including server tests"> + <parallel> + <daemons> + <!-- Start server --> + <ant antfile="${uitest.dir}/vaadin-server.xml" inheritall="true" inheritrefs="true" target="deploy-and-start" /> + </daemons> + <sequential> + <!-- Server tests --> + + <!-- Sleep before running integration tests so testbench 2 + tests have time to compile and start --> + <sleep minutes="4" /> + <ant antfile="${uitest.dir}/integration_tests.xml" target="integration-test-all" inheritall="false" inheritrefs="false"> + <property name="demo.war" value="${war.file}" /> + </ant> + </sequential> + <sequential> + <!-- Wait for server to start --> + <ant antfile="${uitest.dir}/vaadin-server.xml" target="wait-for-startup" /> + + <!-- Run all different kinds of TestBench tests in parallel --> + <parallel> + + <!-- Legacy TestBench 2 tests --> + <sequential> + <ant antfile="${uitest.dir}/test.xml" target="tb2-tests" /> + <echo message="TestBench 2 tests complete" /> + </sequential> + + <!-- TestBench 3 tests --> + <sequential> + <ant antfile="${uitest.dir}/tb3test.xml" target="run-all-tb3-tests" inheritall="true" /> + <echo message="TestBench 3 tests complete" /> + </sequential> + </parallel> + </sequential> + </parallel> + </target> + + <target name="clean-testbench-errors"> + <fail unless="com.vaadin.testbench.screenshot.directory" message="Define screenshot directory using -Dcom.vaadin.testbench.screenshot.directory" /> + <mkdir dir="${com.vaadin.testbench.screenshot.directory}/errors" /> + <delete> + <fileset dir="${com.vaadin.testbench.screenshot.directory}/errors"> + <include name="*" /> + </fileset> + </delete> + </target> + </project> diff --git a/uitest/eclipse-run-selected-test.properties b/uitest/eclipse-run-selected-test.properties index f6cb2551e9..cbd1ab1cef 100644 --- a/uitest/eclipse-run-selected-test.properties +++ b/uitest/eclipse-run-selected-test.properties @@ -1,14 +1,23 @@ -; Location where vaadin-testbench jar can be found -com.vaadin.testbench.lib.dir=<enter location of testbench here> - -; Deployment url to use for testing. Context path must be / -com.vaadin.testbench.deployment.url=http://<enter your ip here>:8888/ +; +; For both TestBench 2 and 3 +; ; Location of the screenshot directory. ; This is the directory that contains the "references" directory com.vaadin.testbench.screenshot.directory=<enter the full path to the screenshots directory, parent of "references" directory> -; Run the whole test even if + +; +; For only TestBench 2 +; + +; Location where TestBench 2 jar can be found +com.vaadin.testbench.lib.dir=<enter location of testbench here> + +; Deployment url to use for testing. Context path must be / +com.vaadin.testbench.deployment.url=http://<enter your ip here>:8888/ + +; Run the whole test even if a screenshot comparison fails com.vaadin.testbench.screenshot.softfail=true ; Screen capture at the end if the test fails @@ -23,7 +32,8 @@ com.vaadin.testbench.screenshot.cursor=true ; Uncomment to limit to certain browsers or override in launch configuration ; browsers=winxp-opera10 -; Claim that the server has started succesfully. Needed for the tests to run +; Claim that the server has started succesfully. Needed for TB2 tests to be executed server.start.succeeded=1 -test-output-dir=../build/test-output
\ No newline at end of file +; Directory where temporary Java classes are created +test-output-dir=../build/test-output diff --git a/uitest/integration_tests.xml b/uitest/integration_tests.xml index 78e053991e..1c9c2b1f8f 100644 --- a/uitest/integration_tests.xml +++ b/uitest/integration_tests.xml @@ -1,6 +1,6 @@ <?xml version="1.0"?> -<project xmlns:antcontrib="antlib:net.sf.antcontrib" name="Vaadin Integration Tests" basedir="." default="integration-test-all"> +<project xmlns:antcontrib="antlib:net.sf.antcontrib" xmlns:ivy="antlib:org.apache.ivy.ant" name="Vaadin Integration Tests" basedir="." default="integration-test-all"> <!-- Import common targets --> <import file="../common.xml" /> @@ -32,33 +32,22 @@ <property name="user" value="${test.integration.user}" /> <property name="passphrase" value="" /> + <ivy:resolve file="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="result/classes" /> + </path> + <!-- Upload war to deploy to ssh host --> <target name="integration-test-upload-demo"> <scp file="${demo.war}" todir="${user}@${test.integration.server}:integration-tests/servers/demo.war" keyfile="${sshkey.file}" passphrase="${passphrase}" /> </target> <!-- Run basic integration test test --> - <target name="integration-test-servlet"> - <fileset dir="integration-testscripts" id="html-test-files" includes="integration-test-${server-name}-servlet.html" /> - <pathconvert pathsep=" " property="testfiles" refid="html-test-files" /> - <subant target="run-tests" failonerror="false" antfile="test.xml"> - <property name="com.vaadin.testbench.lib.dir" value="${com.vaadin.testbench.lib.dir}" /> - <property name="com.vaadin.testbench.tester.host" value="${com.vaadin.testbench.tester.host}" /> - <property name="com.vaadin.testbench.deployment.url" value="${deployment.url}" /> - <property name="server.start.succeeded" value="1" /> - <property name="browsers" value="${test_browsers}" /> - <property name="testfiles" value="${testfiles}" /> - <property name="test-output-dir" value="${integration_test.dir}/result/integration-test-output/${server-name}" /> - <property name="retries" value="0" /> - - <fileset dir="." includes="test.xml" /> - </subant> - </target> - - <target name="integration-test-push-servlet"> - <fileset dir="integration-testscripts" id="html-test-files" includes="integration-test-${server-name}-push-servlet.html" /> - <pathconvert pathsep=" " property="testfiles" refid="html-test-files" /> - <subant target="run-tests" failonerror="false" antfile="test.xml"> + <target name="legacy-integration-test"> + <fail unless="testfiles" message="You need to specify the files to run using the 'testfiles' property" /> + <subant target="run-tb2-tests" failonerror="false" antfile="test.xml"> <property name="com.vaadin.testbench.lib.dir" value="${com.vaadin.testbench.lib.dir}" /> <property name="com.vaadin.testbench.tester.host" value="${com.vaadin.testbench.tester.host}" /> <property name="com.vaadin.testbench.deployment.url" value="${deployment.url}" /> @@ -73,7 +62,7 @@ </target> <target name="integration-test-theme"> - <subant target="run-tests" failonerror="false" antfile="test.xml"> + <subant target="run-tb2-tests" failonerror="false" antfile="test.xml"> <property name="com.vaadin.testbench.lib.dir" value="${com.vaadin.testbench.lib.dir}" /> <property name="com.vaadin.testbench.tester.host" value="${com.vaadin.testbench.tester.host}" /> <property name="com.vaadin.testbench.deployment.url" value="${deployment.url}" /> @@ -90,7 +79,7 @@ <fileset dir="integration-testscripts" id="html-test-files" includes="GoogleAppEngine/integration-test-GAE.html" /> <pathconvert pathsep=" " property="test-GAE" refid="html-test-files" /> - <subant target="run-tests" failonerror="false" antfile="test.xml"> + <subant target="run-tb2-tests" failonerror="false" antfile="test.xml"> <property name="com.vaadin.testbench.lib.dir" value="${com.vaadin.testbench.lib.dir}" /> <property name="com.vaadin.testbench.tester.host" value="${com.vaadin.testbench.tester.host}" /> <property name="com.vaadin.testbench.deployment.url" value="http://vaadin-integration-test.appspot.com/" /> @@ -107,6 +96,27 @@ <sshexec host="${test.integration.server}" username="${user}" keyfile="${sshkey.file}" command="ant -f ${ant.hub} deploy-to-GAE" /> </target> + <target name="run-tb3-servlet-test"> + <antcall target="run-tb3-test" inheritall="true"> + <param name="junit.test.suite" value="com.vaadin.tests.tb3.ServletIntegrationTests" /> + </antcall> + </target> + <target name="run-tb3-test"> + <fail unless="server-name" message="Server name must be defined in server-name" /> + <fail unless="deployment.url" message="Deplyoment url must be defined in deployment.url" /> + <fail unless="com.vaadin.testbench.screenshot.directory" message="Screenshot directory must be defined in com.vaadin.testbench.screenshot.directory" /> + + <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="-Ddeployment.url=${deployment.url}" /> + <jvmarg value="-Dserver-name=${server-name}" /> + <jvmarg value="-Djava.awt.headless=true" /> + <test name="${junit.test.suite}" /> + </junit> + </target> <target name="integration-test-tomcat7"> <antcall target="run-generic-integration-test"> @@ -114,6 +124,12 @@ <param name="target-server" value="tomcat7" /> </antcall> </target> + <target name="integration-test-tomcat8"> + <antcall target="run-generic-integration-test"> + <param name="startDelay" value="10" /> + <param name="target-server" value="tomcat8" /> + </antcall> + </target> <target name="integration-test-tomcat5"> <antcall target="run-generic-integration-test"> <param name="startDelay" value="10" /> @@ -333,7 +349,7 @@ <!-- Upload demo, clean error screenshots and test deployment on all servers --> - <target name="integration-test-all"> + <target name="integration-test-all" unless="tests.integration.skip"> <property name="passphrase" value="${passphrase}" /> <fail unless="sshkey.file" message="You must define an ssh.keyfile parameter" /> <fail unless="com.vaadin.testbench.screenshot.directory" message="You must define a com.vaadin.testbench.screenshot.directory parameter" /> @@ -341,7 +357,8 @@ <antcontrib:trycatch property="tried"> <try> <!-- Still running GAE test from the old server which - requires its own lock --> + requires its own lock --> + <echo message="Getting lock" /> <antcall target="integration-test-get-lock" /> <echo message="Got lock" /> @@ -386,8 +403,8 @@ <antcall target="integration-test-tomcat5" /> <antcall target="integration-test-tomcat6" /> <antcall target="integration-test-tomcat7" /> + <antcall target="integration-test-tomcat8" /> <antcall target="integration-test-websphere8" /> - </parallel> </target> @@ -446,31 +463,24 @@ </condition> </fail> - <copy file="integration-testscripts/common/integration_test.tpl" tofile="integration-testscripts/integration-test-${target-server}-servlet.html" overwrite="true" /> - <antcall target="integration-test-servlet"> - <param name="server-name" value="${target-server}" /> - <param name="deployment.url" value="http://${target-host}:${target-port}" /> - </antcall> - - <!-- Run theme tests in all browsers if there's a property - with the test files --> <antcontrib:if> - <isset property="testfiles-theme" /> + <isset property="testfiles" /> <antcontrib:then> - <antcall target="integration-test-theme"> + <echo>Starting legacy (TB2) test for ${target-server}</echo> + <antcall target="legacy-integration-test"> <param name="server-name" value="${target-server}" /> <param name="deployment.url" value="http://${target-host}:${target-port}" /> </antcall> </antcontrib:then> + <antcontrib:else> + <echo>Starting TB3 test for ${target-server}</echo> + <antcall target="run-tb3-servlet-test"> + <param name="server-name" value="${target-server}" /> + <param name="deployment.url" value="http://${target-host}:${target-port}" /> + </antcall> + </antcontrib:else> </antcontrib:if> - <!-- Run integration tests with push --> - <copy file="integration-testscripts/common/integration_push_test.tpl" tofile="integration-testscripts/integration-test-${target-server}-push-servlet.html" overwrite="true" /> - <antcall target="integration-test-push-servlet"> - <param name="server-name" value="${target-server}" /> - <param name="deployment.url" value="http://${target-host}:${target-port}" /> - </antcall> - <!-- Run theme tests in all browsers if there's a property with the test files --> <antcontrib:if> diff --git a/uitest/ivy.xml b/uitest/ivy.xml index 7ff83324ae..d75a591f94 100644 --- a/uitest/ivy.xml +++ b/uitest/ivy.xml @@ -1,4 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE ivy-module [ + <!ENTITY jetty.version "8.1.9.v20130131"> +]> <ivy-module version="2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://ant.apache.org/ivy/schemas/ivy.xsd" @@ -11,7 +14,7 @@ <conf name="build" /> <conf name="build-provided" visibility="private" /> <conf name="ide" visibility="private" /> - <conf name="jetty-run" extends="build" visibility="private" /> + <conf name="jetty-run" visibility="private" /> </configurations> <publications> <artifact type="war" ext="war" /> @@ -23,9 +26,6 @@ <dependency org="javax.validation" name="validation-api" rev="1.0.0.GA" conf="build,ide -> default,sources" /> - <!-- Servlet API --> - <dependency org="javax.servlet" name="servlet-api" - rev="2.4" conf="build-provided,ide -> default" /> <!-- Google App Engine --> <dependency org="com.google.appengine" name="appengine-api-1.0-sdk" rev="1.2.1" conf="build-provided,ide -> default" /> @@ -33,7 +33,9 @@ <!-- LIBRARY DEPENDENCIES (compile time) --> <!-- Project modules --> <dependency org="com.vaadin" name="vaadin-server" - rev="${vaadin.version}" conf="build->build"></dependency> + rev="${vaadin.version}" conf="build->build"> + <exclude org="javax.servlet"></exclude> + </dependency> <dependency org="com.vaadin" name="vaadin-client" rev="${vaadin.version}" conf="build->build"></dependency> <dependency org="com.vaadin" name="vaadin-client-compiled" @@ -41,27 +43,35 @@ <dependency org="com.vaadin" name="vaadin-themes" rev="${vaadin.version}" conf="build->build"></dependency> <dependency org="com.vaadin" name="vaadin-push" rev="${vaadin.version}" - conf="build->build"></dependency> + conf="build->build"> + <exclude org="javax.servlet"></exclude> + </dependency> <!-- For compiling TestingWidgetSet --> <dependency org="com.vaadin" name="vaadin-client-compiler" rev="${vaadin.version}" conf="build-provided-> build"></dependency> - <!-- Newest Jetty does not work with Ivy currently (orbit -> jar - mapping problem) --> + <!-- Servlet 3.0 API --> + <dependency org="javax.servlet" name="javax.servlet-api" + rev="3.0.1" conf="build-provided,ide -> default" /> + <dependency org="org.eclipse.jetty" name="jetty-server" - rev="7.5.0.v20110901" 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> <!-- jetty-servlets needed by ProxyTest, but not by jetty-runner --> <dependency org="org.eclipse.jetty" name="jetty-servlets" - rev="7.5.0.v20110901" conf="ide, build-provided, jetty-run->default" /> + rev="&jetty.version;" conf="ide, build-provided, jetty-run->default" /> <dependency org="org.eclipse.jetty" name="jetty-websocket" - rev="7.5.0.v20110901" conf="ide, jetty-run->default" /> + rev="&jetty.version;" conf="ide, jetty-run->default" /> <dependency org="org.eclipse.jetty" name="jetty-webapp" - rev="7.5.0.v20110901" conf="ide, build-provided, jetty-run->default" /> + rev="&jetty.version;" conf="ide, build-provided, jetty-run->default" /> <dependency org="org.mortbay.jetty" name="jetty-runner" - rev="7.5.0.v20110901" conf="jetty-run->default" /> + rev="&jetty.version;" conf="ide, jetty-run->default"> + <exclude org="org.eclipse.jetty.orbit"></exclude> + </dependency> - <dependency org="junit" name="junit" rev="4.5" + <dependency org="junit" name="junit" rev="4.11" conf="build,ide -> default" /> <dependency org="commons-codec" name="commons-codec" @@ -71,6 +81,8 @@ <!-- Mainly for SQLContainer tests --> <dependency org="org.hsqldb" name="hsqldb" rev="2.2.6" conf="build,ide -> default" /> + <dependency org="com.vaadin" name="vaadin-testbench" + rev="3.1.1" conf="build-provided,ide -> default" /> </dependencies> </ivy-module> diff --git a/uitest/src/com/vaadin/launcher/DevelopmentServerLauncher.java b/uitest/src/com/vaadin/launcher/DevelopmentServerLauncher.java index 5ab2134cdb..a8d639cbc8 100644 --- a/uitest/src/com/vaadin/launcher/DevelopmentServerLauncher.java +++ b/uitest/src/com/vaadin/launcher/DevelopmentServerLauncher.java @@ -24,10 +24,12 @@ import java.net.ServerSocket; import java.net.Socket; import java.text.SimpleDateFormat; import java.util.Calendar; +import java.util.EnumSet; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; +import javax.servlet.DispatcherType; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; @@ -181,7 +183,8 @@ public class DevelopmentServerLauncher { String[] paths = serverArgs.get("slowdown").split(","); for (String p : paths) { System.out.println("Slowing down: " + p); - webappcontext.addFilter(SlowFilter.class, p, 1); + webappcontext.addFilter(SlowFilter.class, p, + EnumSet.of(DispatcherType.REQUEST)); } } // --cache=/run/APP/PUBLISHED/*,/other/path/asd.jpg @@ -190,7 +193,8 @@ public class DevelopmentServerLauncher { String[] paths = serverArgs.get("cache").split(","); for (String p : paths) { System.out.println("Enabling cache for: " + p); - webappcontext.addFilter(CacheFilter.class, p, 1); + webappcontext.addFilter(CacheFilter.class, p, + EnumSet.of(DispatcherType.REQUEST)); } } diff --git a/uitest/src/com/vaadin/tests/VerifyBrowserVersion.java b/uitest/src/com/vaadin/tests/VerifyBrowserVersion.java index 022a343196..1b21f08aa7 100644 --- a/uitest/src/com/vaadin/tests/VerifyBrowserVersion.java +++ b/uitest/src/com/vaadin/tests/VerifyBrowserVersion.java @@ -9,9 +9,13 @@ public class VerifyBrowserVersion extends TestBase { @Override protected void setup() { WebBrowser browser = getBrowser(); - addComponent(new Label(browser.getBrowserApplication())); - addComponent(new Label("Touch device? " - + (browser.isTouchDevice() ? "YES" : "No"))); + Label userAgent = new Label(browser.getBrowserApplication()); + userAgent.setId("userAgent"); + addComponent(userAgent); + Label touchDevice = new Label("Touch device? " + + (browser.isTouchDevice() ? "YES" : "No")); + touchDevice.setId("touchDevice"); + addComponent(touchDevice); } @Override diff --git a/uitest/src/com/vaadin/tests/VerifyBrowserVersionTest.java b/uitest/src/com/vaadin/tests/VerifyBrowserVersionTest.java new file mode 100644 index 0000000000..6704f55226 --- /dev/null +++ b/uitest/src/com/vaadin/tests/VerifyBrowserVersionTest.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; + +import java.util.HashMap; +import java.util.Map; + +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.AbstractTB3Test.BrowserUtil; + +public class VerifyBrowserVersionTest extends MultiBrowserTest { + + private Map<DesiredCapabilities, String> expectedUserAgent = new HashMap<DesiredCapabilities, String>(); + + { + expectedUserAgent + .put(BrowserUtil.firefox(24), + "Mozilla/5.0 (Windows NT 6.1; rv:24.0) Gecko/20100101 Firefox/24.0"); + expectedUserAgent + .put(BrowserUtil.ie(8), + "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)"); + expectedUserAgent + .put(BrowserUtil.ie(9), + "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)"); + expectedUserAgent + .put(BrowserUtil.ie(10), + "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)"); + expectedUserAgent + .put(BrowserUtil.ie(11), + "Mozilla/5.0 (Windows NT 6.1; Trident/7.0; rv:11.0) like Gecko"); + expectedUserAgent + .put(BrowserUtil.chrome(29), + "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.76 Safari/537.36"); + expectedUserAgent + .put(BrowserUtil.opera(12), + "Opera/9.80 (Windows NT 5.1) Presto/2.12.388 Version/12.15"); + + } + + @Test + public void verifyUserAgent() { + openTestURL(); + Assert.assertEquals( + expectedUserAgent.get(getDesiredCapabilities()), + vaadinElementById("userAgent").getText()); + Assert.assertEquals("Touch device? No", + vaadinElementById("touchDevice").getText()); + } +}
\ No newline at end of file diff --git a/uitest/src/com/vaadin/tests/components/datefield/DateFieldTestTest.java b/uitest/src/com/vaadin/tests/components/datefield/DateFieldTestTest.java new file mode 100644 index 0000000000..557201e803 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/datefield/DateFieldTestTest.java @@ -0,0 +1,118 @@ +/* + * 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.datefield; + +import org.junit.Assert; +import org.junit.Test; +import org.openqa.selenium.By; +import org.openqa.selenium.Dimension; +import org.openqa.selenium.NoSuchElementException; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.interactions.Actions; + +import com.vaadin.tests.tb3.MultiBrowserTest; + +public class DateFieldTestTest extends MultiBrowserTest { + + @Test + public void testMakingRequired() throws InterruptedException { + setDebug(true); + openTestURL(); + Thread.sleep(1000); + menu("Component"); + menuSub("State"); + menu("Required"); + assertNoErrorNotification(); + } + + private void assertNoErrorNotification() { + try { + getDriver().findElement( + By.xpath("//div[contains(@class, 'v-Notification') ]")); + Assert.fail("Error notification shown!"); + } catch (NoSuchElementException e) { + // As expected + } + } + + @Test + public void testValueAfterOpeningPopupInRequiredField() + throws InterruptedException { + setDebug(true); + openTestURL(); + Thread.sleep(1000); + menu("Component"); + menuSub("State"); + menu("Required"); + + menu("Component"); + menuSub("Features"); + menuSub("Resolution"); + menu("Month"); + + menu("Component"); + menuSub("Listeners"); + menu("Value change listener"); + + String inputtedValue = "2/12"; + getInput().sendKeys(inputtedValue); + + openPopup(); + closePopup(); + String actual = getInput().getAttribute("value"); + Assert.assertEquals(inputtedValue, actual); + assertNoErrorNotification(); + + } + + private void openPopup() throws InterruptedException { + Dimension size = getInput().getSize(); + new Actions(getDriver()).moveToElement(getInput(), 0, 0) + .moveByOffset(size.getWidth() + 5, size.getHeight() / 2) + .click(); + // This fails in Opera for some weird reason + // getDriver().findElement(By.className("v-datefield-button")).click(); + } + + private WebElement getInput() { + return getDriver().findElement(By.xpath("//input")); + } + + private void closePopup() { + getDriver().findElement(By.tagName("body")).click(); + } + + /** + * @since + * @param string + */ + private void menuSub(String string) { + getDriver().findElement( + By.xpath("//span[text() = '" + string + "']")).click(); + new Actions(getDriver()).moveByOffset(100, 0).build().perform(); + } + + /** + * @since + * @param string + */ + private void menu(String string) { + getDriver().findElement( + By.xpath("//span[text() = '" + string + "']")).click(); + + } + +}
\ No newline at end of file diff --git a/uitest/src/com/vaadin/tests/components/datefield/DynamicallyChangeDateRange.html b/uitest/src/com/vaadin/tests/components/datefield/DynamicallyChangeDateRange.html index 77c610f211..75c19945b0 100644 --- a/uitest/src/com/vaadin/tests/components/datefield/DynamicallyChangeDateRange.html +++ b/uitest/src/com/vaadin/tests/components/datefield/DynamicallyChangeDateRange.html @@ -52,6 +52,11 @@ <td></td> </tr> <tr> + <td>pause</td> + <td>300</td> + <td></td> +</tr> +<tr> <td>mouseClick</td> <td>vaadin=runcomvaadintestscomponentsdatefieldDynamicallyChangeDateRange::/VVerticalLayout[0]/Slot[0]/VPopupCalendar[0]#popupButton</td> <td>14,16</td> @@ -87,6 +92,11 @@ <td></td> </tr> <tr> + <td>pause</td> + <td>300</td> + <td></td> +</tr> +<tr> <td>mouseClick</td> <td>vaadin=runcomvaadintestscomponentsdatefieldDynamicallyChangeDateRange::/VVerticalLayout[0]/Slot[0]/VPopupCalendar[0]#popupButton</td> <td>14,15</td> diff --git a/uitest/src/com/vaadin/tests/components/label/LabelModes.html b/uitest/src/com/vaadin/tests/components/label/LabelModes.html deleted file mode 100644 index 356688b456..0000000000 --- a/uitest/src/com/vaadin/tests/components/label/LabelModes.html +++ /dev/null @@ -1,27 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> -<head profile="http://selenium-ide.openqa.org/profiles/test-case"> -<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> -<link rel="selenium.base" href="" /> -<title>New Test</title> -</head> -<body> -<table cellpadding="1" cellspacing="1" border="1"> -<thead> -<tr><td rowspan="1" colspan="3">New Test</td></tr> -</thead><tbody> -<tr> - <td>open</td> - <td>/run/com.vaadin.tests.components.label.LabelModes?restartApplication</td> - <td></td> -</tr> -<tr> - <td>screenCapture</td> - <td></td> - <td>labelmodes</td> -</tr> - -</tbody></table> -</body> -</html> diff --git a/uitest/src/com/vaadin/tests/components/label/LabelModesTest.java b/uitest/src/com/vaadin/tests/components/label/LabelModesTest.java new file mode 100644 index 0000000000..efad615510 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/label/LabelModesTest.java @@ -0,0 +1,30 @@ +/* + * 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.label; + +import org.junit.Test; + +import com.vaadin.tests.tb3.MultiBrowserTest; + +public class LabelModesTest extends MultiBrowserTest { + + @Test + public void testLabelModes() throws Exception { + openTestURL(); + compareScreen("labelmodes"); + } + +}
\ No newline at end of file diff --git a/uitest/src/com/vaadin/tests/components/optiongroup/OptionGroupRetainFocusKeyboardValueChange.html b/uitest/src/com/vaadin/tests/components/optiongroup/OptionGroupRetainFocusKeyboardValueChange.html new file mode 100644 index 0000000000..046cac0e30 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/optiongroup/OptionGroupRetainFocusKeyboardValueChange.html @@ -0,0 +1,54 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> +<head profile="http://selenium-ide.openqa.org/profiles/test-case"> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> +<link rel="selenium.base" href="" /> +<title>OptionGroupRetainFocusKeyboardValueChange</title> +</head> +<body> +<table cellpadding="1" cellspacing="1" border="1"> +<thead> +<tr><td rowspan="1" colspan="3">OptionGroupRetainFocusKeyboardValueChange</td></tr> +</thead><tbody> +<tr> + <td>open</td> + <td>/run/OptionGroupRetainFocusKeyboardValueChange?restartApplication</td> + <td></td> +</tr> +<tr> + <td>pressSpecialKey</td> + <td>vaadin=runOptionGroupRetainFocusKeyboardValueChange::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VOptionGroup[0]/domChild[0]/domChild[0]</td> + <td>space</td> +</tr> +<!-- The element 'A' should be selected and focused --> +<tr> + <td>screenCapture</td> + <td></td> + <td></td> +</tr> +<tr> + <td>pressSpecialKey</td> + <td>vaadin=runOptionGroupRetainFocusKeyboardValueChange::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VOptionGroup[0]/domChild[0]/domChild[0]</td> + <td>down</td> +</tr> +<!-- The element 'B' should be selected and focused, the caption of first element is changed from 'A' to 'A+' --> +<tr> + <td>screenCapture</td> + <td></td> + <td></td> +</tr> +<tr> + <td>pressSpecialKey</td> + <td>vaadin=runOptionGroupRetainFocusKeyboardValueChange::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VOptionGroup[0]/domChild[1]/domChild[0]</td> + <td>down</td> +</tr> +<!-- Elements 'B' and 'C' should be swapped; 'C' selected but not focused --> +<tr> + <td>screenCapture</td> + <td></td> + <td></td> +</tr> +</tbody></table> +</body> +</html> diff --git a/uitest/src/com/vaadin/tests/components/optiongroup/OptionGroupRetainFocusKeyboardValueChange.java b/uitest/src/com/vaadin/tests/components/optiongroup/OptionGroupRetainFocusKeyboardValueChange.java new file mode 100644 index 0000000000..570a300cb3 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/optiongroup/OptionGroupRetainFocusKeyboardValueChange.java @@ -0,0 +1,70 @@ +/* + * 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.optiongroup; + +import com.vaadin.data.Property.ValueChangeEvent; +import com.vaadin.data.Property.ValueChangeListener; +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.ui.OptionGroup; + +/** + * Testcase for #10451 + * + * @author Vaadin Ltd + */ +public class OptionGroupRetainFocusKeyboardValueChange extends AbstractTestUI { + + @Override + protected void setup(VaadinRequest request) { + final OptionGroup optiongroup = new OptionGroup(); + optiongroup.addItem(1); + optiongroup.addItem(2); + optiongroup.addItem(3); + optiongroup.setItemCaption(1, "A"); + optiongroup.setItemCaption(2, "B"); + optiongroup.setItemCaption(3, "C"); + optiongroup.setImmediate(true); + + optiongroup.addValueChangeListener(new ValueChangeListener() { + + @Override + public void valueChange(ValueChangeEvent event) { + if (optiongroup.isSelected(2)) { + optiongroup.setItemCaption(1, "A+"); + } else if (optiongroup.isSelected(3)) { + optiongroup.removeItem(2); + optiongroup.addItem(2); + optiongroup.setItemCaption(2, "B"); + } + } + }); + + addComponent(optiongroup); + + optiongroup.focus(); + } + + @Override + protected String getTestDescription() { + return "OptionGroup should retain focus after it's value being changed with keyboard"; + } + + @Override + protected Integer getTicketNumber() { + return 10451; + } +} diff --git a/uitest/src/com/vaadin/tests/components/orderedlayout/HorizontalLayoutFullsizeContentWithErrorMsg.java b/uitest/src/com/vaadin/tests/components/orderedlayout/HorizontalLayoutFullsizeContentWithErrorMsg.java new file mode 100644 index 0000000000..030bfa693e --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/orderedlayout/HorizontalLayoutFullsizeContentWithErrorMsg.java @@ -0,0 +1,66 @@ +package com.vaadin.tests.components.orderedlayout; + +import com.vaadin.server.UserError; +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.ui.Alignment; +import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.Button.ClickListener; +import com.vaadin.ui.HorizontalLayout; +import com.vaadin.ui.TextField; + +public class HorizontalLayoutFullsizeContentWithErrorMsg extends AbstractTestUI { + + static final String FIELD_ID = "f"; + static final String BUTTON_ID = "b"; + private TextField tf; + + @Override + protected Integer getTicketNumber() { + return 12564; + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.tests.components.AbstractTestUI#setup(com.vaadin.server. + * VaadinRequest) + */ + @Override + protected void setup(VaadinRequest request) { + HorizontalLayout hl = new HorizontalLayout(); + hl.setWidth("500px"); + + tf = new TextField(); + tf.setId(FIELD_ID); + tf.setWidth("100%"); + hl.addComponent(tf); + hl.setExpandRatio(tf, 1); + hl.setComponentAlignment(tf, Alignment.MIDDLE_CENTER); + + Button toggleError = new Button("Toggle error"); + toggleError.setId(BUTTON_ID); + toggleError.addClickListener(new ClickListener() { + @Override + public void buttonClick(ClickEvent event) { + tf.setComponentError(tf.getComponentError() == null ? new UserError( + "foo") : null); + } + }); + hl.addComponent(toggleError); + + addComponent(hl); + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.tests.components.AbstractTestUI#getTestDescription() + */ + @Override + protected String getTestDescription() { + return "TextField should remain at same level vertically, horizontally width should adjust to fit error indicator."; + } + +} diff --git a/uitest/src/com/vaadin/tests/components/orderedlayout/HorizontalLayoutFullsizeContentWithErrorMsgTest.java b/uitest/src/com/vaadin/tests/components/orderedlayout/HorizontalLayoutFullsizeContentWithErrorMsgTest.java new file mode 100644 index 0000000000..24ebf24688 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/orderedlayout/HorizontalLayoutFullsizeContentWithErrorMsgTest.java @@ -0,0 +1,49 @@ +/* + * 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.orderedlayout; + +import org.junit.Assert; +import org.junit.Test; +import org.openqa.selenium.By; +import org.openqa.selenium.Point; +import org.openqa.selenium.WebElement; + +import com.vaadin.tests.tb3.MultiBrowserTest; + +public class HorizontalLayoutFullsizeContentWithErrorMsgTest extends + MultiBrowserTest { + + @Test + public void test() { + openTestURL(); + WebElement element = getDriver().findElement( + By.id(HorizontalLayoutFullsizeContentWithErrorMsg.FIELD_ID)); + Point location = element.getLocation(); + + WebElement errorToggleButton = getDriver().findElement( + By.id(HorizontalLayoutFullsizeContentWithErrorMsg.BUTTON_ID)); + + errorToggleButton.click(); + + Assert.assertEquals(location, element.getLocation()); + + errorToggleButton.click(); + + Assert.assertEquals(location, element.getLocation()); + + } + +}
\ No newline at end of file diff --git a/uitest/src/com/vaadin/tests/components/panel/PanelChangeContentsTest.java b/uitest/src/com/vaadin/tests/components/panel/PanelChangeContentsTest.java new file mode 100644 index 0000000000..5bc505dbc8 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/panel/PanelChangeContentsTest.java @@ -0,0 +1,53 @@ +/* + * 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.panel; + +import org.junit.Assert; +import org.junit.Test; + +import com.vaadin.tests.tb3.MultiBrowserTest; + +public class PanelChangeContentsTest extends MultiBrowserTest { + + @Test + public void testReattachComponentUsingPush() { + setPush(true); + openTestURL(); + + Assert.assertEquals( + "stats", + vaadinElement( + "/VVerticalLayout[0]/Slot[1]/VPanel[0]/VVerticalLayout[0]/Slot[0]/VLabel[0]") + .getText()); + vaadinElement( + "/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[1]/VButton[0]/domChild[0]/domChild[0]") + .click(); + Assert.assertEquals( + "companies", + vaadinElement( + "/VVerticalLayout[0]/Slot[1]/VPanel[0]/VVerticalLayout[0]/Slot[0]/VLabel[0]") + .getText()); + vaadinElement( + "/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[0]/VButton[0]/domChild[0]/domChild[0]") + .click(); + Assert.assertEquals( + "stats", + vaadinElement( + "/VVerticalLayout[0]/Slot[1]/VPanel[0]/VVerticalLayout[0]/Slot[0]/VLabel[0]") + .getText()); + + } +} diff --git a/uitest/src/com/vaadin/tests/components/slider/SliderDisable.java b/uitest/src/com/vaadin/tests/components/slider/SliderDisable.java new file mode 100644 index 0000000000..bd1d175119 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/slider/SliderDisable.java @@ -0,0 +1,62 @@ +/* + * 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.slider; + +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.Button.ClickListener; +import com.vaadin.ui.Slider; +import com.vaadin.ui.VerticalLayout; + +public class SliderDisable extends AbstractTestUI { + + @Override + protected void setup(VaadinRequest request) { + VerticalLayout content = new VerticalLayout(); + content.setMargin(true); + content.setSpacing(true); + + final Slider slider = new Slider(0, 5); + slider.setWidth(200, Unit.PIXELS); + slider.setValue(1.0D); + + Button disableButton = new Button("Disable slider"); + disableButton.setId("disableButton"); + disableButton.addClickListener(new ClickListener() { + @Override + public void buttonClick(ClickEvent event) { + slider.setEnabled(false); + } + }); + + content.addComponent(slider); + content.addComponent(disableButton); + setContent(content); + } + + @Override + protected String getTestDescription() { + return "The apparent value of the slider should not change when the slider is disabled"; + } + + @Override + protected Integer getTicketNumber() { + return 12676; + } + +} diff --git a/uitest/src/com/vaadin/tests/components/slider/SliderDisableTest.java b/uitest/src/com/vaadin/tests/components/slider/SliderDisableTest.java new file mode 100644 index 0000000000..f6ec3dac3b --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/slider/SliderDisableTest.java @@ -0,0 +1,36 @@ +/* + * 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.slider; + +import java.io.IOException; + +import org.junit.Test; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.interactions.Actions; + +import com.vaadin.tests.tb3.MultiBrowserTest; + +public class SliderDisableTest extends MultiBrowserTest { + @Test + public void disableSlider() throws IOException { + openTestURL(); + WebElement element = vaadinElement("/VVerticalLayout[0]/Slot[0]/VSlider[0]/domChild[2]/domChild[0]"); + new Actions(driver).dragAndDropBy(element, 112, 0).perform(); + compareScreen("enabled"); + vaadinElementById("disableButton").click(); + compareScreen("disabled"); + } +}
\ No newline at end of file diff --git a/uitest/src/com/vaadin/tests/components/table/EmptyTable.java b/uitest/src/com/vaadin/tests/components/table/EmptyTable.java new file mode 100644 index 0000000000..d6c30efa5a --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/table/EmptyTable.java @@ -0,0 +1,58 @@ +/* + * 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.table; + +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.ui.Table; + +public class EmptyTable extends AbstractTestUI { + + /* + * (non-Javadoc) + * + * @see com.vaadin.tests.components.AbstractTestUI#setup(com.vaadin.server. + * VaadinRequest) + */ + @Override + protected void setup(VaadinRequest request) { + Table table = new Table("Table"); + table.addContainerProperty("testColumn", String.class, null); + table.setPageLength(0); // disable paging + addComponent(table); + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.tests.components.AbstractTestUI#getTestDescription() + */ + @Override + protected String getTestDescription() { + return "Empty Table should not cause JS exception"; + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.tests.components.AbstractTestUI#getTicketNumber() + */ + @Override + protected Integer getTicketNumber() { + return 11189; + } + +} diff --git a/uitest/src/com/vaadin/tests/components/table/EmptyTableTest.java b/uitest/src/com/vaadin/tests/components/table/EmptyTableTest.java new file mode 100644 index 0000000000..229dc23b9a --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/table/EmptyTableTest.java @@ -0,0 +1,44 @@ +/* + * 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.table; + +import org.junit.Assert; +import org.junit.Test; +import org.openqa.selenium.By; +import org.openqa.selenium.NoSuchElementException; + +import com.vaadin.tests.tb3.MultiBrowserTest; + +public class EmptyTableTest extends MultiBrowserTest { + + @Test + public void test() { + setDebug(true); + openTestURL(); + + ensureNoErrors(); + } + + private void ensureNoErrors() { + try { + getDriver().findElement(By.className("v-Notification")); + } catch (NoSuchElementException e) { + return; + } + Assert.fail("Error notification was shown!"); + } + +}
\ No newline at end of file diff --git a/uitest/src/com/vaadin/tests/push/PushFromInit.html b/uitest/src/com/vaadin/tests/components/table/ShowLastItem.html index d009eb3baf..c9c93198fa 100644 --- a/uitest/src/com/vaadin/tests/push/PushFromInit.html +++ b/uitest/src/com/vaadin/tests/components/table/ShowLastItem.html @@ -3,7 +3,6 @@ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head profile="http://selenium-ide.openqa.org/profiles/test-case"> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> -<link rel="selenium.base" href="" /> <title>New Test</title> </head> <body> @@ -12,19 +11,24 @@ <tr><td rowspan="1" colspan="3">New Test</td></tr> </thead><tbody> <tr> - <td>open</td> - <td>/run-push/com.vaadin.tests.push.PushFromInit?debug&restartApplication</td> - <td></td> + <td>open</td> + <td>/run/com.vaadin.tests.components.table.ShowLastItem?restartApplication</td> + <td></td> </tr> <tr> - <td>waitForText</td> - <td>vaadin=runpushcomvaadintestspushPushFromInit::PID_SLog_row_1</td> - <td>1. Logged in init</td> + <td>click</td> + <td>vaadin=runcomvaadintestscomponentstableShowLastItem::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VButton[0]/domChild[0]/domChild[0]</td> + <td></td> </tr> <tr> - <td>assertText</td> - <td>vaadin=runpushcomvaadintestspushPushFromInit::PID_SLog_row_0</td> - <td>2. Logged from background thread started in init</td> + <td>pause</td> + <td>1000</td> + <td></td> +</tr> +<tr> + <td>screenCapture</td> + <td></td> + <td>row-20-fully-visible</td> </tr> </tbody></table> diff --git a/uitest/src/com/vaadin/tests/components/table/ShowLastItem.java b/uitest/src/com/vaadin/tests/components/table/ShowLastItem.java new file mode 100644 index 0000000000..6d6f744918 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/table/ShowLastItem.java @@ -0,0 +1,66 @@ +package com.vaadin.tests.components.table; + +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.Table; + +public class ShowLastItem extends AbstractTestUI { + + /* + * (non-Javadoc) + * + * @see com.vaadin.tests.components.AbstractTestUI#setup(com.vaadin.server. + * VaadinRequest) + */ + @Override + protected void setup(VaadinRequest request) { + final Table table = new Table(); + table.setHeight("210px"); + + table.addContainerProperty("Col", String.class, ""); + + for (int i = 0; i < 20; i++) { + table.addItem(i).getItemProperty("Col") + .setValue("row " + String.valueOf(i)); + } + + Button addItemBtn = new Button("Add item", new Button.ClickListener() { + + @Override + public void buttonClick(ClickEvent event) { + Object itemId = "row " + table.getItemIds().size(); + + table.addItem(itemId).getItemProperty("Col") + .setValue(String.valueOf(itemId)); + + table.setCurrentPageFirstItemIndex(table.getItemIds().size() - 1); + } + }); + + addComponent(table); + addComponent(addItemBtn); + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.tests.components.AbstractTestUI#getTestDescription() + */ + @Override + protected String getTestDescription() { + return "Show last item in Table by using setCurrentPageFirstItemId"; + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.tests.components.AbstractTestUI#getTicketNumber() + */ + @Override + protected Integer getTicketNumber() { + return 12407; + } + +} diff --git a/uitest/src/com/vaadin/tests/components/table/TableMoveFocusWithSelection.java b/uitest/src/com/vaadin/tests/components/table/TableMoveFocusWithSelection.java new file mode 100644 index 0000000000..20170efa13 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/table/TableMoveFocusWithSelection.java @@ -0,0 +1,125 @@ +/* + * 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.table; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +import com.vaadin.event.LayoutEvents.LayoutClickEvent; +import com.vaadin.event.LayoutEvents.LayoutClickListener; +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.Button.ClickListener; +import com.vaadin.ui.Table; +import com.vaadin.ui.VerticalLayout; + +public class TableMoveFocusWithSelection extends AbstractTestUI { + + /* + * (non-Javadoc) + * + * @see com.vaadin.tests.components.AbstractTestUI#setup(com.vaadin.server. + * VaadinRequest) + */ + @Override + protected void setup(VaadinRequest request) { + final Table t = new Table(); + t.setImmediate(true); + t.setId("test-table"); + t.setSizeFull(); + t.setSelectable(true); + t.addContainerProperty("layout", VerticalLayout.class, null); + t.addContainerProperty("string", String.class, null); + + for (int i = 0; i < 100; i++) { + t.addItem(i); + final VerticalLayout l = new VerticalLayout(); + l.setId("row-" + i); + l.setHeight(20, Unit.PIXELS); + l.setData(i); + l.addLayoutClickListener(new LayoutClickListener() { + @Override + public void layoutClick(LayoutClickEvent event) { + if (t.isMultiSelect()) { + Set<Object> values = new HashSet<Object>( + (Set<Object>) t.getValue()); + values.add(l.getData()); + t.setValue(values); + } else { + t.setValue(l.getData()); + } + } + }); + t.getContainerProperty(i, "layout").setValue(l); + t.getContainerProperty(i, "string").setValue("Item #" + i); + } + addComponent(t); + + // Select mode + Button toggleSelectMode = new Button( + t.isMultiSelect() ? "Press to use single select" + : "Press to use multi select"); + toggleSelectMode.setId("toggle-mode"); + toggleSelectMode.addClickListener(new ClickListener() { + + @Override + public void buttonClick(ClickEvent event) { + t.setMultiSelect(!t.isMultiSelect()); + + event.getButton().setCaption( + t.isMultiSelect() ? "Press to use single select" + : "Press to use multi select"); + } + }); + + addComponent(toggleSelectMode); + + Button select5210 = new Button("Select row 5-10", + new Button.ClickListener() { + + @Override + public void buttonClick(ClickEvent event) { + t.setValue(Arrays.asList(5, 6, 7, 8, 9, 10)); + } + }); + select5210.setId("select-510"); + addComponent(select5210); + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.tests.components.AbstractTestUI#getTestDescription() + */ + @Override + protected String getTestDescription() { + return "Changing selection in single select mode should move focus"; + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.tests.components.AbstractTestUI#getTicketNumber() + */ + @Override + protected Integer getTicketNumber() { + return 12540; + } + +} diff --git a/uitest/src/com/vaadin/tests/components/table/TableMoveFocusWithSelectionTest.java b/uitest/src/com/vaadin/tests/components/table/TableMoveFocusWithSelectionTest.java new file mode 100644 index 0000000000..b38705eeb6 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/table/TableMoveFocusWithSelectionTest.java @@ -0,0 +1,75 @@ +/* + * 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.table; + +import static org.junit.Assert.assertTrue; + +import org.junit.Test; +import org.openqa.selenium.WebElement; + +import com.vaadin.testbench.By; +import com.vaadin.tests.tb3.MultiBrowserTest; + +/** + * Tests if table focus is moved correctly to the selected item + * + * @since + * @author Vaadin Ltd + */ +public class TableMoveFocusWithSelectionTest extends MultiBrowserTest { + + @Test + public void selectUnfocusedTableAndAssumeSelectionGetsFocus() { + + openTestURL(); + + // Click on row 5 + getDriver().findElement(By.id("row-5")).click(); + + // Ensure row 5 gets focused + WebElement row5TableRow = getDriver().findElement( + By.xpath("//div[@id='row-5']/../../..")); + String row5StyleName = row5TableRow.getAttribute("class"); + assertTrue(row5StyleName.contains("v-table-focus")); + } + + @Test + public void focusShouldStayOnUserSelectedRowIfSelectionChangesServerSide() { + + openTestURL(); + + // Select multiselect + getDriver().findElement(By.id("toggle-mode")).click(); + + // Click on row 7 + getDriver().findElement(By.id("row-7")).click(); + + // Select row 5-10 server side + getDriver().findElement(By.id("select-510")).click(); + + // Ensure row 7 is still focused + WebElement row7TableRow = getDriver().findElement( + By.xpath("//div[@id='row-7']/../../..")); + String row7StyleName = row7TableRow.getAttribute("class"); + assertTrue(row7StyleName.contains("v-table-focus")); + } + + @Override + protected Class<?> getUIClass() { + // FIXME Remove when this is done automatically + return TableMoveFocusWithSelection.class; + } +} diff --git a/uitest/src/com/vaadin/tests/components/tabsheet/TabSheetHotKeysWithModifiers.java b/uitest/src/com/vaadin/tests/components/tabsheet/TabSheetHotKeysWithModifiers.java new file mode 100644 index 0000000000..c0b30ff68d --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/tabsheet/TabSheetHotKeysWithModifiers.java @@ -0,0 +1,50 @@ +/* + * 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.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.ui.Label; +import com.vaadin.ui.TabSheet; + +public class TabSheetHotKeysWithModifiers extends AbstractTestUI { + + @Override + protected void setup(VaadinRequest request) { + TabSheet tabSheet = new TabSheet(); + tabSheet.setWidth("500px"); + tabSheet.setHeight("500px"); + tabSheet.addTab(new Label("Tab 1"), "Tab 1").setClosable(true); + tabSheet.addTab(new Label("Tab 2"), "Tab 2").setClosable(true); + tabSheet.addTab(new Label("Tab 3"), "Tab 3").setClosable(true); + setContent(tabSheet); + } + + @Override + protected String getTestDescription() { + return "Hot keys (left and right arrow keys and the delete key) should be ignored when they are pressed simultaneously with modifier keys"; + } + + @Override + protected Integer getTicketNumber() { + return 12178; + } + +} diff --git a/uitest/src/com/vaadin/tests/components/ui/UIAccessTest.java b/uitest/src/com/vaadin/tests/components/ui/UIAccessTest.java new file mode 100644 index 0000000000..9db2c2f0d3 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/ui/UIAccessTest.java @@ -0,0 +1,204 @@ +/* + * 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.ui; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import org.junit.Assert; +import org.junit.Test; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.support.ui.ExpectedConditions; + +import com.vaadin.testbench.By; +import com.vaadin.tests.tb3.MultiBrowserTest; + +public class UIAccessTest extends MultiBrowserTest { + @Test + public void testThreadLocals() { + setPush(true); + openTestURL(); + getCurrentInstanceWhenPushingButton().click(); + waitUntil(ExpectedConditions.textToBePresentInElement( + vaadinLocatorById("Log_row_0"), "1.")); + Assert.assertEquals("0. Current UI matches in beforeResponse? true", + vaadinElementById("Log_row_1").getText()); + Assert.assertEquals( + "1. Current session matches in beforeResponse? true", + vaadinElementById("Log_row_0").getText()); + + } + + @Test + public void testAccessMethod() throws Exception { + openTestURL(); + + vaadinElement( + "/VVerticalLayout[0]/Slot[2]/VVerticalLayout[0]/Slot[0]/VButton[0]/domChild[0]/domChild[0]") + .click(); + driver.findElement( + By.vaadin("runcomvaadintestscomponentsuiUIAccess::/VVerticalLayout[0]/Slot[2]/VVerticalLayout[0]/Slot[0]/VButton[0]/domChild[0]/domChild[0]")) + .click(); + assertTrue(driver + .findElement( + By.vaadin("runcomvaadintestscomponentsuiUIAccess::PID_SLog_row_2")) + .getText() + .matches( + "^0\\. Access from UI thread future is done[\\s\\S] false$")); + assertEquals( + "1. Access from UI thread is run", + driver.findElement( + By.vaadin("runcomvaadintestscomponentsuiUIAccess::PID_SLog_row_1")) + .getText()); + assertTrue(driver + .findElement( + By.vaadin("runcomvaadintestscomponentsuiUIAccess::PID_SLog_row_0")) + .getText() + .matches( + "^2\\. beforeClientResponse future is done[\\s\\S] true$")); + driver.findElement( + By.vaadin("runcomvaadintestscomponentsuiUIAccess::/VVerticalLayout[0]/Slot[2]/VVerticalLayout[0]/Slot[1]/VButton[0]/domChild[0]/domChild[0]")) + .click(); + assertEquals( + "0. Initial background message", + driver.findElement( + By.vaadin("runcomvaadintestscomponentsuiUIAccess::PID_SLog_row_1")) + .getText()); + assertTrue(driver + .findElement( + By.vaadin("runcomvaadintestscomponentsuiUIAccess::PID_SLog_row_0")) + .getText() + .matches("^1\\. Thread has current response[\\s\\S] false$")); + for (int second = 0;; second++) { + if (second >= 30) { + fail("timeout"); + } + try { + if ("0. Initial background message" + .equals(driver + .findElement( + By.vaadin("runcomvaadintestscomponentsuiUIAccess::PID_SLog_row_2")) + .getText())) { + break; + } + } catch (Exception e) { + } + Thread.sleep(1000); + } + + assertTrue(driver + .findElement( + By.vaadin("runcomvaadintestscomponentsuiUIAccess::PID_SLog_row_0")) + .getText() + .matches( + "^2\\. Thread got lock, inital future done[\\s\\S] true$")); + driver.findElement( + By.vaadin("runcomvaadintestscomponentsuiUIAccess::/VVerticalLayout[0]/Slot[2]/VVerticalLayout[0]/Slot[2]/VButton[0]/domChild[0]/domChild[0]")) + .click(); + assertEquals( + "0. Throwing exception in access", + driver.findElement( + By.vaadin("runcomvaadintestscomponentsuiUIAccess::PID_SLog_row_2")) + .getText()); + assertTrue(driver + .findElement( + By.vaadin("runcomvaadintestscomponentsuiUIAccess::PID_SLog_row_1")) + .getText().matches("^1\\. firstFuture is done[\\s\\S] true$")); + assertEquals( + "2. Got exception from firstFuture: java.lang.RuntimeException: Catch me if you can", + driver.findElement( + By.vaadin("runcomvaadintestscomponentsuiUIAccess::PID_SLog_row_0")) + .getText()); + driver.findElement( + By.vaadin("runcomvaadintestscomponentsuiUIAccess::/VVerticalLayout[0]/Slot[2]/VVerticalLayout[0]/Slot[3]/VButton[0]/domChild[0]/domChild[0]")) + .click(); + assertEquals( + "0. future was cancled, should not start", + driver.findElement( + By.vaadin("runcomvaadintestscomponentsuiUIAccess::PID_SLog_row_0")) + .getText()); + driver.findElement( + By.vaadin("runcomvaadintestscomponentsuiUIAccess::/VVerticalLayout[0]/Slot[2]/VVerticalLayout[0]/Slot[4]/VButton[0]/domChild[0]/domChild[0]")) + .click(); + assertEquals( + "0. Waiting for thread to start", + driver.findElement( + By.vaadin("runcomvaadintestscomponentsuiUIAccess::PID_SLog_row_2")) + .getText()); + assertEquals( + "1. Thread started, waiting for interruption", + driver.findElement( + By.vaadin("runcomvaadintestscomponentsuiUIAccess::PID_SLog_row_1")) + .getText()); + assertEquals( + "2. I was interrupted", + driver.findElement( + By.vaadin("runcomvaadintestscomponentsuiUIAccess::PID_SLog_row_0")) + .getText()); + driver.findElement( + By.vaadin("runcomvaadintestscomponentsuiUIAccess::/VVerticalLayout[0]/Slot[2]/VVerticalLayout[0]/Slot[5]/VButton[0]/domChild[0]/domChild[0]")) + .click(); + assertTrue(driver + .findElement( + By.vaadin("runcomvaadintestscomponentsuiUIAccess::PID_SLog_row_3")) + .getText() + .matches("^0\\. accessSynchronously has request[\\s\\S] true$")); + assertEquals( + "1. Test value in accessSynchronously: Set before accessSynchronosly", + driver.findElement( + By.vaadin("runcomvaadintestscomponentsuiUIAccess::PID_SLog_row_2")) + .getText()); + assertTrue(driver + .findElement( + By.vaadin("runcomvaadintestscomponentsuiUIAccess::PID_SLog_row_1")) + .getText() + .matches( + "^2\\. has request after accessSynchronously[\\s\\S] true$")); + assertEquals( + "3. Test value after accessSynchornously: Set in accessSynchronosly", + driver.findElement( + By.vaadin("runcomvaadintestscomponentsuiUIAccess::PID_SLog_row_0")) + .getText()); + driver.findElement( + By.vaadin("runcomvaadintestscomponentsuiUIAccess::/VVerticalLayout[0]/Slot[2]/VVerticalLayout[0]/Slot[6]/VButton[0]/domChild[0]/domChild[0]")) + .click(); + assertTrue(driver + .findElement( + By.vaadin("runcomvaadintestscomponentsuiUIAccess::PID_SLog_row_3")) + .getText().matches("^0\\. access has request[\\s\\S] false$")); + assertEquals( + "1. Test value in access: Set before access", + driver.findElement( + By.vaadin("runcomvaadintestscomponentsuiUIAccess::PID_SLog_row_2")) + .getText()); + assertTrue(driver + .findElement( + By.vaadin("runcomvaadintestscomponentsuiUIAccess::PID_SLog_row_1")) + .getText() + .matches("^2\\. has request after access[\\s\\S] true$")); + assertEquals( + "3. Test value after access: Set before run pending", + driver.findElement( + By.vaadin("runcomvaadintestscomponentsuiUIAccess::PID_SLog_row_0")) + .getText()); + + } + + private WebElement getCurrentInstanceWhenPushingButton() { + return vaadinElement("/VVerticalLayout[0]/Slot[2]/VVerticalLayout[0]/Slot[7]/VButton[0]"); + } +}
\ No newline at end of file diff --git a/uitest/src/com/vaadin/tests/components/ui/UiAccess.html b/uitest/src/com/vaadin/tests/components/ui/UiAccess.html deleted file mode 100644 index 613691623c..0000000000 --- a/uitest/src/com/vaadin/tests/components/ui/UiAccess.html +++ /dev/null @@ -1,166 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> -<head profile="http://selenium-ide.openqa.org/profiles/test-case"> -<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> -<link rel="selenium.base" href="" /> -<title>New Test</title> -</head> -<body> -<table cellpadding="1" cellspacing="1" border="1"> -<thead> -<tr><td rowspan="1" colspan="3">New Test</td></tr> -</thead><tbody> -<tr> - <td>open</td> - <td>/run/com.vaadin.tests.components.ui.UiAccess?restartApplication</td> - <td></td> -</tr> -<tr> - <td>click</td> - <td>vaadin=runcomvaadintestscomponentsuiUiAccess::/VVerticalLayout[0]/Slot[2]/VVerticalLayout[0]/Slot[0]/VButton[0]/domChild[0]/domChild[0]</td> - <td></td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runcomvaadintestscomponentsuiUiAccess::PID_SLog_row_2</td> - <td>exact:0. Access from UI thread future is done? false</td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runcomvaadintestscomponentsuiUiAccess::PID_SLog_row_1</td> - <td>1. Access from UI thread is run</td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runcomvaadintestscomponentsuiUiAccess::PID_SLog_row_0</td> - <td>exact:2. beforeClientResponse future is done? true</td> -</tr> -<tr> - <td>click</td> - <td>vaadin=runcomvaadintestscomponentsuiUiAccess::/VVerticalLayout[0]/Slot[2]/VVerticalLayout[0]/Slot[1]/VButton[0]/domChild[0]/domChild[0]</td> - <td></td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runcomvaadintestscomponentsuiUiAccess::PID_SLog_row_1</td> - <td>0. Initial background message</td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runcomvaadintestscomponentsuiUiAccess::PID_SLog_row_0</td> - <td>exact:1. Thread has current response? false</td> -</tr> -<tr> - <td>waitForText</td> - <td>vaadin=runcomvaadintestscomponentsuiUiAccess::PID_SLog_row_2</td> - <td>0. Initial background message</td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runcomvaadintestscomponentsuiUiAccess::PID_SLog_row_0</td> - <td>exact:2. Thread got lock, inital future done? true</td> -</tr> -<tr> - <td>click</td> - <td>vaadin=runcomvaadintestscomponentsuiUiAccess::/VVerticalLayout[0]/Slot[2]/VVerticalLayout[0]/Slot[2]/VButton[0]/domChild[0]/domChild[0]</td> - <td></td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runcomvaadintestscomponentsuiUiAccess::PID_SLog_row_2</td> - <td>0. Throwing exception in access</td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runcomvaadintestscomponentsuiUiAccess::PID_SLog_row_1</td> - <td>exact:1. firstFuture is done? true</td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runcomvaadintestscomponentsuiUiAccess::PID_SLog_row_0</td> - <td>2. Got exception from firstFuture: java.lang.RuntimeException: Catch me if you can</td> -</tr> -<tr> - <td>click</td> - <td>vaadin=runcomvaadintestscomponentsuiUiAccess::/VVerticalLayout[0]/Slot[2]/VVerticalLayout[0]/Slot[3]/VButton[0]/domChild[0]/domChild[0]</td> - <td></td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runcomvaadintestscomponentsuiUiAccess::PID_SLog_row_0</td> - <td>0. future was cancled, should not start</td> -</tr> -<tr> - <td>click</td> - <td>vaadin=runcomvaadintestscomponentsuiUiAccess::/VVerticalLayout[0]/Slot[2]/VVerticalLayout[0]/Slot[4]/VButton[0]/domChild[0]/domChild[0]</td> - <td></td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runcomvaadintestscomponentsuiUiAccess::PID_SLog_row_2</td> - <td>0. Waiting for thread to start</td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runcomvaadintestscomponentsuiUiAccess::PID_SLog_row_1</td> - <td>1. Thread started, waiting for interruption</td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runcomvaadintestscomponentsuiUiAccess::PID_SLog_row_0</td> - <td>2. I was interrupted</td> -</tr> -<tr> - <td>click</td> - <td>vaadin=runcomvaadintestscomponentsuiUiAccess::/VVerticalLayout[0]/Slot[2]/VVerticalLayout[0]/Slot[5]/VButton[0]/domChild[0]/domChild[0]</td> - <td></td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runcomvaadintestscomponentsuiUiAccess::PID_SLog_row_3</td> - <td>0. accessSynchronously has request? true</td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runcomvaadintestscomponentsuiUiAccess::PID_SLog_row_2</td> - <td>1. Test value in accessSynchronously: Set before accessSynchronosly</td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runcomvaadintestscomponentsuiUiAccess::PID_SLog_row_1</td> - <td>2. has request after accessSynchronously? true</td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runcomvaadintestscomponentsuiUiAccess::PID_SLog_row_0</td> - <td>3. Test value after accessSynchornously: Set in accessSynchronosly</td> -</tr> -<tr> - <td>click</td> - <td>vaadin=runcomvaadintestscomponentsuiUiAccess::/VVerticalLayout[0]/Slot[2]/VVerticalLayout[0]/Slot[6]/VButton[0]/domChild[0]/domChild[0]</td> - <td></td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runcomvaadintestscomponentsuiUiAccess::PID_SLog_row_3</td> - <td>0. access has request? false</td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runcomvaadintestscomponentsuiUiAccess::PID_SLog_row_2</td> - <td>1. Test value in access: Set before access</td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runcomvaadintestscomponentsuiUiAccess::PID_SLog_row_1</td> - <td>2. has request after access? true</td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runcomvaadintestscomponentsuiUiAccess::PID_SLog_row_0</td> - <td>3. Test value after access: Set before run pending</td> -</tr> -</tbody></table> -</body> -</html> diff --git a/uitest/src/com/vaadin/tests/components/ui/UiAccess.java b/uitest/src/com/vaadin/tests/components/ui/UiAccess.java deleted file mode 100644 index 09f2fd8816..0000000000 --- a/uitest/src/com/vaadin/tests/components/ui/UiAccess.java +++ /dev/null @@ -1,361 +0,0 @@ -/* - * 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.ui; - -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; -import java.util.concurrent.locks.ReentrantLock; - -import com.vaadin.server.VaadinRequest; -import com.vaadin.server.VaadinService; -import com.vaadin.server.VaadinSession; -import com.vaadin.shared.communication.PushMode; -import com.vaadin.tests.components.AbstractTestUIWithLog; -import com.vaadin.ui.Button; -import com.vaadin.ui.Button.ClickEvent; -import com.vaadin.ui.UI; -import com.vaadin.util.CurrentInstance; - -public class UiAccess extends AbstractTestUIWithLog { - - private volatile boolean checkCurrentInstancesBeforeResponse = false; - - private Future<Void> checkFromBeforeClientResponse; - - private class CurrentInstanceTestType { - private String value; - - public CurrentInstanceTestType(String value) { - this.value = value; - } - - @Override - public String toString() { - return value; - } - } - - @Override - protected void setup(VaadinRequest request) { - addComponent(new Button("Access from UI thread", - new Button.ClickListener() { - - @Override - public void buttonClick(ClickEvent event) { - log.clear(); - // Ensure beforeClientResponse is invoked - markAsDirty(); - checkFromBeforeClientResponse = access(new Runnable() { - @Override - public void run() { - log("Access from UI thread is run"); - } - }); - log("Access from UI thread future is done? " - + checkFromBeforeClientResponse.isDone()); - } - })); - addComponent(new Button("Access from background thread", - new Button.ClickListener() { - @Override - public void buttonClick(ClickEvent event) { - log.clear(); - final CountDownLatch latch = new CountDownLatch(1); - - new Thread() { - @Override - public void run() { - final boolean threadHasCurrentResponse = VaadinService - .getCurrentResponse() != null; - // session is locked by request thread at this - // point - final Future<Void> initialFuture = access(new Runnable() { - @Override - public void run() { - log("Initial background message"); - log("Thread has current response? " - + threadHasCurrentResponse); - } - }); - - // Let request thread continue - latch.countDown(); - - // Wait until thread can be locked - while (!getSession().getLockInstance() - .tryLock()) { - try { - Thread.sleep(100); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - } - try { - log("Thread got lock, inital future done? " - + initialFuture.isDone()); - setPollInterval(-1); - } finally { - getSession().unlock(); - } - } - }.start(); - - // Wait for thread to do initialize before continuing - try { - latch.await(); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - - setPollInterval(3000); - } - })); - addComponent(new Button("Access throwing exception", - new Button.ClickListener() { - @Override - public void buttonClick(ClickEvent event) { - log.clear(); - final Future<Void> firstFuture = access(new Runnable() { - @Override - public void run() { - log("Throwing exception in access"); - throw new RuntimeException( - "Catch me if you can"); - } - }); - access(new Runnable() { - @Override - public void run() { - log("firstFuture is done? " - + firstFuture.isDone()); - try { - firstFuture.get(); - log("Should not get here"); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } catch (ExecutionException e) { - log("Got exception from firstFuture: " - + e.getMessage()); - } - } - }); - } - })); - addComponent(new Button("Cancel future before started", - new Button.ClickListener() { - @Override - public void buttonClick(ClickEvent event) { - log.clear(); - Future<Void> future = access(new Runnable() { - @Override - public void run() { - log("Should not get here"); - } - }); - future.cancel(false); - log("future was cancled, should not start"); - } - })); - addComponent(new Button("Cancel running future", - new Button.ClickListener() { - @Override - public void buttonClick(ClickEvent event) { - log.clear(); - final ReentrantLock interruptLock = new ReentrantLock(); - - final Future<Void> future = access(new Runnable() { - @Override - public void run() { - log("Waiting for thread to start"); - while (!interruptLock.isLocked()) { - try { - Thread.sleep(100); - } catch (InterruptedException e) { - log("Premature interruption"); - throw new RuntimeException(e); - } - } - - log("Thread started, waiting for interruption"); - try { - interruptLock.lockInterruptibly(); - } catch (InterruptedException e) { - log("I was interrupted"); - } - } - }); - - new Thread() { - @Override - public void run() { - interruptLock.lock(); - // Wait until UI thread has started waiting for - // the lock - while (!interruptLock.hasQueuedThreads()) { - try { - Thread.sleep(100); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - } - - future.cancel(true); - } - }.start(); - } - })); - addComponent(new Button("CurrentInstance accessSynchronously values", - new Button.ClickListener() { - @Override - public void buttonClick(ClickEvent event) { - log.clear(); - // accessSynchronously should maintain values - CurrentInstance.set(CurrentInstanceTestType.class, - new CurrentInstanceTestType( - "Set before accessSynchronosly")); - accessSynchronously(new Runnable() { - @Override - public void run() { - log.log("accessSynchronously has request? " - + (VaadinService.getCurrentRequest() != null)); - log.log("Test value in accessSynchronously: " - + CurrentInstance - .get(CurrentInstanceTestType.class)); - CurrentInstance.set( - CurrentInstanceTestType.class, - new CurrentInstanceTestType( - "Set in accessSynchronosly")); - } - }); - log.log("has request after accessSynchronously? " - + (VaadinService.getCurrentRequest() != null)); - log("Test value after accessSynchornously: " - + CurrentInstance - .get(CurrentInstanceTestType.class)); - } - })); - addComponent(new Button("CurrentInstance access values", - new Button.ClickListener() { - @Override - public void buttonClick(ClickEvent event) { - log.clear(); - // accessSynchronously should maintain values - CurrentInstance - .setInheritable(CurrentInstanceTestType.class, - new CurrentInstanceTestType( - "Set before access")); - access(new Runnable() { - @Override - public void run() { - log.log("access has request? " - + (VaadinService.getCurrentRequest() != null)); - log.log("Test value in access: " - + CurrentInstance - .get(CurrentInstanceTestType.class)); - CurrentInstance.setInheritable( - CurrentInstanceTestType.class, - new CurrentInstanceTestType( - "Set in access")); - } - }); - CurrentInstance.setInheritable( - CurrentInstanceTestType.class, - new CurrentInstanceTestType( - "Set before run pending")); - - getSession().getService().runPendingAccessTasks( - getSession()); - - log.log("has request after access? " - + (VaadinService.getCurrentRequest() != null)); - log("Test value after access: " - + CurrentInstance - .get(CurrentInstanceTestType.class)); - } - })); - - addComponent(new Button("CurrentInstance when pushing", - new Button.ClickListener() { - @Override - public void buttonClick(ClickEvent event) { - log.clear(); - if (getPushConfiguration().getPushMode() != PushMode.AUTOMATIC) { - log("Can only test with automatic push enabled"); - return; - } - - final VaadinSession session = getSession(); - new Thread() { - @Override - public void run() { - // Pretend this isn't a Vaadin thread - CurrentInstance.clearAll(); - - /* - * Get explicit lock to ensure the (implicit) - * push does not happen during normal request - * handling. - */ - session.lock(); - try { - access(new Runnable() { - @Override - public void run() { - checkCurrentInstancesBeforeResponse = true; - // Trigger beforeClientResponse - markAsDirty(); - } - }); - } finally { - session.unlock(); - } - } - }.start(); - } - })); - } - - @Override - public void beforeClientResponse(boolean initial) { - if (checkFromBeforeClientResponse != null) { - log("beforeClientResponse future is done? " - + checkFromBeforeClientResponse.isDone()); - checkFromBeforeClientResponse = null; - } - if (checkCurrentInstancesBeforeResponse) { - UI currentUI = UI.getCurrent(); - VaadinSession currentSession = VaadinSession.getCurrent(); - - log("Current UI matches in beforeResponse? " + (currentUI == this)); - log("Current session matches in beforeResponse? " - + (currentSession == getSession())); - checkCurrentInstancesBeforeResponse = false; - } - } - - @Override - protected String getTestDescription() { - return "Test for various ways of using UI.access"; - } - - @Override - protected Integer getTicketNumber() { - return Integer.valueOf(11897); - } - -} diff --git a/uitest/src/com/vaadin/tests/components/ui/UiAccessPush.html b/uitest/src/com/vaadin/tests/components/ui/UiAccessPush.html deleted file mode 100644 index bc29534ee4..0000000000 --- a/uitest/src/com/vaadin/tests/components/ui/UiAccessPush.html +++ /dev/null @@ -1,41 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> -<head profile="http://selenium-ide.openqa.org/profiles/test-case"> -<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> -<link rel="selenium.base" href="" /> -<title>New Test</title> -</head> -<body> -<table cellpadding="1" cellspacing="1" border="1"> -<thead> -<tr><td rowspan="1" colspan="3">New Test</td></tr> -</thead><tbody> -<tr> - <td>open</td> - <td>/run/com.vaadin.tests.components.ui.UiAccess?restartApplication&transport=websocket</td> - <td></td> -</tr> -<tr> - <td>click</td> - <td>vaadin=runcomvaadintestscomponentsuiUiAccess::/VVerticalLayout[0]/Slot[2]/VVerticalLayout[0]/Slot[7]/VButton[0]/domChild[0]/domChild[0]</td> - <td></td> -</tr> -<tr> - <td>waitForNotText</td> - <td>vaadin=runcomvaadintestscomponentsuiUiAccess::PID_SLog_row_0</td> - <td></td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runcomvaadintestscomponentsuiUiAccess::PID_SLog_row_0</td> - <td>exact:1. Current session matches in beforeResponse? true</td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runcomvaadintestscomponentsuiUiAccess::PID_SLog_row_1</td> - <td>exact:0. Current UI matches in beforeResponse? true</td> -</tr> -</tbody></table> -</body> -</html> diff --git a/uitest/src/com/vaadin/tests/dd/DnDOnSubtree.html b/uitest/src/com/vaadin/tests/dd/DnDOnSubtree.html new file mode 100644 index 0000000000..844636cb02 --- /dev/null +++ b/uitest/src/com/vaadin/tests/dd/DnDOnSubtree.html @@ -0,0 +1,51 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> +<head profile="http://selenium-ide.openqa.org/profiles/test-case"> + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> + <link rel="selenium.base" href="http://localhost:8888/"/> + <title>DnDOnSubtree</title> +</head> +<body> +<table cellpadding="1" cellspacing="1" border="1"> + <thead> + <tr> + <td rowspan="1" colspan="3">New Test</td> + </tr> + </thead> + <tbody> + <tr> + <td>open</td> + <td>/run/com.vaadin.tests.dd.DDTest8?restartApplication</td> + <td></td> + </tr> + <tr> + <td>drag</td> + <td>vaadin=runcomvaadintestsddDDTest8::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VTree[0]#n[3]</td> + <td>11,8</td> + </tr> + <!-- Drop on Bar5, which is a subtree target --> + <tr> + <td>drop</td> + <td>vaadin=runcomvaadintestsddDDTest8::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VTree[0]#n[6]</td> + <td>34,9</td> + </tr> + <tr> + <td>mouseClick</td> + <td> + vaadin=runcomvaadintestsddDDTest8::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VTree[0]#n[5]/expand + </td> + <td>10,8</td> + </tr> + <!-- Assert that the dragged & dropped node is now a child of Bar5 --> + <tr> + <td>assertElementPresent</td> + <td> + vaadin=runcomvaadintestsddDDTest8::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VTree[0]#n[5]/n[0] + </td> + <td></td> + </tr> + </tbody> +</table> +</body> +</html> diff --git a/uitest/src/com/vaadin/tests/integration/AbstractIntegrationTest.java b/uitest/src/com/vaadin/tests/integration/AbstractIntegrationTest.java new file mode 100644 index 0000000000..5f4ae41361 --- /dev/null +++ b/uitest/src/com/vaadin/tests/integration/AbstractIntegrationTest.java @@ -0,0 +1,53 @@ +/* + * 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.integration; + +import java.util.Collection; +import java.util.Collections; + +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized.Parameters; +import org.openqa.selenium.remote.DesiredCapabilities; + +import com.vaadin.tests.tb3.PrivateTB3Configuration; + +/** + * 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 + */ +@RunWith(IntegrationTestRunner.class) +public abstract class AbstractIntegrationTest extends + PrivateTB3Configuration { + @Override + protected String getBaseURL() { + String deploymentUrl = System.getProperty("deployment.url"); + if (deploymentUrl == null || deploymentUrl.equals("")) { + throw new RuntimeException( + "Deployment url must be given as deployment.url"); + } + + return deploymentUrl; + } + + @Parameters + public static Collection<DesiredCapabilities> getBrowsersForTest() { + return Collections.singleton(BrowserUtil.firefox(17)); + } + +} diff --git a/uitest/src/com/vaadin/tests/integration/AbstractServletIntegrationTest.java b/uitest/src/com/vaadin/tests/integration/AbstractServletIntegrationTest.java new file mode 100644 index 0000000000..f736a126a5 --- /dev/null +++ b/uitest/src/com/vaadin/tests/integration/AbstractServletIntegrationTest.java @@ -0,0 +1,63 @@ +/* + * 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.integration; + +import java.io.IOException; + +import org.junit.Test; +import org.openqa.selenium.WebElement; + +/** + * Base class for servlet integration tests. Automatically prepends "/demo" to + * the deployment path + * + * @author Vaadin Ltd + */ +public abstract class AbstractServletIntegrationTest extends + AbstractIntegrationTest { + + @Test + public void runTest() throws IOException, AssertionError { + openTestURL(); + compareScreen("initial"); + + WebElement cell = vaadinElement(getTableCell(getTable(), 0, 1)); + testBenchElement(cell).click(51, 13); + + compareScreen("finland"); + } + + private String getTableCell(String tableLocator, int row, int col) { + return tableLocator + + "/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[" + + row + "]/domChild[" + col + "]/domChild[0]"; + } + + protected String getTable() { + return "/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]"; + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.tests.tb3.AbstractTB3Test#getDeploymentPath() + */ + @Override + protected String getDeploymentPath() { + return "/demo" + super.getDeploymentPath(); + } + +} diff --git a/uitest/src/com/vaadin/tests/integration/IntegrationTestRunner.java b/uitest/src/com/vaadin/tests/integration/IntegrationTestRunner.java new file mode 100644 index 0000000000..f5042b54b6 --- /dev/null +++ b/uitest/src/com/vaadin/tests/integration/IntegrationTestRunner.java @@ -0,0 +1,54 @@ +/* + * 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.integration; + +import org.junit.runners.model.FrameworkMethod; +import org.junit.runners.model.InitializationError; + +import com.vaadin.tests.tb3.TB3Runner; + +/** + * JUnit runner for integration tests. Replaces the actual method name with the + * server-name property when generating the test name. + * + * @author Vaadin Ltd + */ +public class IntegrationTestRunner extends TB3Runner { + + private Class<?> testClass; + + public IntegrationTestRunner(Class<?> klass) throws InitializationError { + super(klass); + testClass = klass; + } + + /* + * (non-Javadoc) + * + * @see + * org.junit.runners.BlockJUnit4ClassRunner#testName(org.junit.runners.model + * .FrameworkMethod) + */ + @Override + protected String testName(FrameworkMethod method) { + if (AbstractIntegrationTest.class.isAssignableFrom(testClass)) { + return System.getProperty("server-name"); + } else { + return super.testName(method); + } + } +} diff --git a/uitest/src/com/vaadin/tests/integration/ServletIntegrationStreamingUI.java b/uitest/src/com/vaadin/tests/integration/ServletIntegrationStreamingUI.java new file mode 100644 index 0000000000..0d92fb1bb8 --- /dev/null +++ b/uitest/src/com/vaadin/tests/integration/ServletIntegrationStreamingUI.java @@ -0,0 +1,30 @@ +/* + * 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.integration; + +import com.vaadin.annotations.Push; +import com.vaadin.shared.ui.ui.Transport; + +/** + * Server test which uses streaming + * + * @since 7.1 + * @author Vaadin Ltd + */ +@Push(transport = Transport.STREAMING) +public class ServletIntegrationStreamingUI extends ServletIntegrationUI { + +} diff --git a/uitest/src/com/vaadin/tests/integration/ServletIntegrationStreamingUITest.java b/uitest/src/com/vaadin/tests/integration/ServletIntegrationStreamingUITest.java new file mode 100644 index 0000000000..36a946bfa3 --- /dev/null +++ b/uitest/src/com/vaadin/tests/integration/ServletIntegrationStreamingUITest.java @@ -0,0 +1,21 @@ +/* + * 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.integration; + +public class ServletIntegrationStreamingUITest extends + AbstractServletIntegrationTest { + // Uses the test method declared in the super class +}
\ No newline at end of file diff --git a/uitest/src/com/vaadin/tests/integration/IntegrationTestUI.java b/uitest/src/com/vaadin/tests/integration/ServletIntegrationUI.java index 0e6cb19b30..6aec2c8e2a 100755 --- a/uitest/src/com/vaadin/tests/integration/IntegrationTestUI.java +++ b/uitest/src/com/vaadin/tests/integration/ServletIntegrationUI.java @@ -11,7 +11,8 @@ import com.vaadin.ui.Table; import com.vaadin.ui.UI; import com.vaadin.ui.VerticalLayout; -public class IntegrationTestUI extends UI { +public class ServletIntegrationUI extends UI { + @Override protected void init(VaadinRequest request) { VerticalLayout layout = new VerticalLayout(); diff --git a/uitest/src/com/vaadin/tests/integration/ServletIntegrationUITest.java b/uitest/src/com/vaadin/tests/integration/ServletIntegrationUITest.java new file mode 100644 index 0000000000..25ffdac4a2 --- /dev/null +++ b/uitest/src/com/vaadin/tests/integration/ServletIntegrationUITest.java @@ -0,0 +1,20 @@ +/* + * 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.integration; + +public class ServletIntegrationUITest extends AbstractServletIntegrationTest { + // Uses the test method declared in the super class +}
\ No newline at end of file diff --git a/uitest/src/com/vaadin/tests/integration/ServletIntegrationWebsocketUI.java b/uitest/src/com/vaadin/tests/integration/ServletIntegrationWebsocketUI.java new file mode 100644 index 0000000000..905b80fd85 --- /dev/null +++ b/uitest/src/com/vaadin/tests/integration/ServletIntegrationWebsocketUI.java @@ -0,0 +1,45 @@ +/* + * 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.integration; + +import com.vaadin.annotations.Push; +import com.vaadin.server.VaadinRequest; +import com.vaadin.shared.ui.ui.Transport; + +/** + * Server test which uses websockets + * + * @since 7.1 + * @author Vaadin Ltd + */ +@Push(transport = Transport.WEBSOCKET) +public class ServletIntegrationWebsocketUI extends ServletIntegrationUI { + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.tests.integration.IntegrationTestUI#init(com.vaadin.server + * .VaadinRequest) + */ + @Override + protected void init(VaadinRequest request) { + super.init(request); + // Ensure no fallback is used + getPushConfiguration().setFallbackTransport(Transport.WEBSOCKET); + } + +} diff --git a/uitest/src/com/vaadin/tests/integration/ServletIntegrationWebsocketUITest.java b/uitest/src/com/vaadin/tests/integration/ServletIntegrationWebsocketUITest.java new file mode 100644 index 0000000000..f2e7a6f2d0 --- /dev/null +++ b/uitest/src/com/vaadin/tests/integration/ServletIntegrationWebsocketUITest.java @@ -0,0 +1,21 @@ +/* + * 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.integration; + +public class ServletIntegrationWebsocketUITest extends + AbstractServletIntegrationTest { + // Uses the test method declared in the super class +}
\ No newline at end of file diff --git a/uitest/src/com/vaadin/tests/push/BarInUIDL.html b/uitest/src/com/vaadin/tests/push/BarInUIDL.html deleted file mode 100644 index 66f03158b6..0000000000 --- a/uitest/src/com/vaadin/tests/push/BarInUIDL.html +++ /dev/null @@ -1,42 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> -<head profile="http://selenium-ide.openqa.org/profiles/test-case"> -<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> -<link rel="selenium.base" href="http://localhost:8888/" /> -<title>New Test</title> -</head> -<body> -<table cellpadding="1" cellspacing="1" border="1"> -<thead> -<tr><td rowspan="1" colspan="3">New Test</td></tr> -</thead><tbody> -<tr> - <td>open</td> - <td>/run-push/com.vaadin.tests.push.BarInUIDL?restartApplication</td> - <td></td> -</tr> -<tr> - <td>click</td> - <td>vaadin=runpushcomvaadintestspushBarInUIDL::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VButton[0]/domChild[0]</td> - <td></td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runpushcomvaadintestspushBarInUIDL::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[1]/VLabel[0]</td> - <td>Thank you for clicking | bar</td> -</tr> -<tr> - <td>click</td> - <td>vaadin=runpushcomvaadintestspushBarInUIDL::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VButton[0]/domChild[0]</td> - <td></td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runpushcomvaadintestspushBarInUIDL::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[2]/VLabel[0]</td> - <td>Thank you for clicking | bar</td> -</tr> - -</tbody></table> -</body> -</html> diff --git a/uitest/src/com/vaadin/tests/push/BarInUIDL.java b/uitest/src/com/vaadin/tests/push/BarInUIDL.java index 7e414cc89d..bc05f7c306 100644 --- a/uitest/src/com/vaadin/tests/push/BarInUIDL.java +++ b/uitest/src/com/vaadin/tests/push/BarInUIDL.java @@ -16,12 +16,15 @@ package com.vaadin.tests.push; +import com.vaadin.annotations.Push; import com.vaadin.server.VaadinRequest; +import com.vaadin.shared.ui.ui.Transport; import com.vaadin.tests.components.AbstractTestUI; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Label; +@Push(transport = Transport.STREAMING) public class BarInUIDL extends AbstractTestUI { /* diff --git a/uitest/src/com/vaadin/tests/push/BarInUIDLTest.java b/uitest/src/com/vaadin/tests/push/BarInUIDLTest.java new file mode 100644 index 0000000000..840d653e1e --- /dev/null +++ b/uitest/src/com/vaadin/tests/push/BarInUIDLTest.java @@ -0,0 +1,45 @@ +/* + * 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.push; + +import org.junit.Assert; +import org.junit.Test; +import org.openqa.selenium.WebElement; + +import com.vaadin.tests.tb3.MultiBrowserTest; + +public class BarInUIDLTest extends MultiBrowserTest { + @Test + public void sendBarInUIDL() { + openTestURL(); + getButton().click(); + Assert.assertEquals( + "Thank you for clicking | bar", + vaadinElement( + "/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[1]/VLabel[0]") + .getText()); + getButton().click(); + Assert.assertEquals( + "Thank you for clicking | bar", + vaadinElement( + "/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[2]/VLabel[0]") + .getText()); + } + + private WebElement getButton() { + return vaadinElement("/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VButton[0]"); + } +}
\ No newline at end of file diff --git a/uitest/src/com/vaadin/tests/push/BasicPush.html b/uitest/src/com/vaadin/tests/push/BasicPush.html deleted file mode 100644 index 173ec90674..0000000000 --- a/uitest/src/com/vaadin/tests/push/BasicPush.html +++ /dev/null @@ -1,88 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> -<head profile="http://selenium-ide.openqa.org/profiles/test-case"> -<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> -<link rel="selenium.base" href="http://localhost:8888/" /> -<title>New Test</title> -</head> -<body> -<table cellpadding="1" cellspacing="1" border="1"> -<thead> -<tr><td rowspan="1" colspan="3">New Test</td></tr> -</thead><tbody> -<tr> - <td>open</td> - <td>/run-push/com.vaadin.tests.push.BasicPush?restartApplication&debug</td> - <td></td> -</tr> -<!--Test client initiated push --> -<tr> - <td>assertText</td> - <td>vaadin=runpushcomvaadintestspushBasicPush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[1]/VLabel[0]</td> - <td>0</td> -</tr> -<tr> - <td>click</td> - <td>vaadin=runpushcomvaadintestspushBasicPush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[2]/VButton[0]/domChild[0]/domChild[0]</td> - <td></td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runpushcomvaadintestspushBasicPush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[1]/VLabel[0]</td> - <td>1</td> -</tr> -<tr> - <td>click</td> - <td>vaadin=runpushcomvaadintestspushBasicPush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[2]/VButton[0]/domChild[0]/domChild[0]</td> - <td></td> -</tr> -<tr> - <td>click</td> - <td>vaadin=runpushcomvaadintestspushBasicPush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[2]/VButton[0]/domChild[0]/domChild[0]</td> - <td></td> -</tr> -<tr> - <td>click</td> - <td>vaadin=runpushcomvaadintestspushBasicPush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[2]/VButton[0]/domChild[0]/domChild[0]</td> - <td></td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runpushcomvaadintestspushBasicPush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[1]/VLabel[0]</td> - <td>4</td> -</tr> -<!--Test server initiated push--> -<tr> - <td>click</td> - <td>vaadin=runpushcomvaadintestspushBasicPush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[5]/VButton[0]/domChild[0]/domChild[0]</td> - <td></td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runpushcomvaadintestspushBasicPush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[4]/VLabel[0]</td> - <td>0</td> -</tr> -<tr> - <td>pause</td> - <td>3000</td> - <td></td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runpushcomvaadintestspushBasicPush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[4]/VLabel[0]</td> - <td>1</td> -</tr> -<tr> - <td>pause</td> - <td>3000</td> - <td></td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runpushcomvaadintestspushBasicPush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[4]/VLabel[0]</td> - <td>2</td> -</tr> -</tbody></table> -</body> -</html> diff --git a/uitest/src/com/vaadin/tests/push/BasicPush.java b/uitest/src/com/vaadin/tests/push/BasicPush.java index b80d287a1d..d6c45a2ed0 100644 --- a/uitest/src/com/vaadin/tests/push/BasicPush.java +++ b/uitest/src/com/vaadin/tests/push/BasicPush.java @@ -1,20 +1,33 @@ +/* + * 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.push; -import java.util.Date; import java.util.Timer; import java.util.TimerTask; -import com.vaadin.annotations.Widgetset; +import com.vaadin.annotations.Push; import com.vaadin.data.util.ObjectProperty; import com.vaadin.server.VaadinRequest; import com.vaadin.shared.ui.label.ContentMode; import com.vaadin.tests.components.AbstractTestUI; -import com.vaadin.tests.widgetset.TestingWidgetSet; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Label; -@Widgetset(TestingWidgetSet.NAME) +@Push public class BasicPush extends AbstractTestUI { private ObjectProperty<Integer> counter = new ObjectProperty<Integer>(0); @@ -23,18 +36,7 @@ public class BasicPush extends AbstractTestUI { private final Timer timer = new Timer(true); - private final TimerTask task = new TimerTask() { - - @Override - public void run() { - access(new Runnable() { - @Override - public void run() { - counter2.setValue(counter2.getValue() + 1); - } - }); - } - }; + private TimerTask task; @Override protected void setup(VaadinRequest request) { @@ -65,11 +67,37 @@ public class BasicPush extends AbstractTestUI { lbl.setCaption("Server counter (updates each 3s by server thread) :"); addComponent(lbl); - addComponent(new Button("Reset", new Button.ClickListener() { + addComponent(new Button("Start timer", new Button.ClickListener() { @Override public void buttonClick(ClickEvent event) { counter2.setValue(0); + if (task != null) { + task.cancel(); + } + task = new TimerTask() { + + @Override + public void run() { + access(new Runnable() { + @Override + public void run() { + counter2.setValue(counter2.getValue() + 1); + } + }); + } + }; + timer.scheduleAtFixedRate(task, 3000, 3000); + } + })); + + addComponent(new Button("Stop timer", new Button.ClickListener() { + @Override + public void buttonClick(ClickEvent event) { + if (task != null) { + task.cancel(); + task = null; + } } })); } @@ -94,7 +122,6 @@ public class BasicPush extends AbstractTestUI { @Override public void attach() { super.attach(); - timer.scheduleAtFixedRate(task, new Date(), 3000); } @Override diff --git a/uitest/src/com/vaadin/tests/push/BasicPushStreaming.java b/uitest/src/com/vaadin/tests/push/BasicPushStreaming.java index 37a8afd819..f9dc78dd43 100644 --- a/uitest/src/com/vaadin/tests/push/BasicPushStreaming.java +++ b/uitest/src/com/vaadin/tests/push/BasicPushStreaming.java @@ -1,12 +1,31 @@ +/* + * 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.push; import com.vaadin.annotations.Push; +import com.vaadin.server.VaadinRequest; import com.vaadin.shared.ui.ui.Transport; @Push(transport = Transport.STREAMING) public class BasicPushStreaming extends BasicPush { @Override - protected void setup(com.vaadin.server.VaadinRequest request) { - addComponent(new PushConfigurator(this)); + public void init(VaadinRequest request) { + super.init(request); + // Don't use fallback so we can easier detect if streaming fails + getPushConfiguration().setFallbackTransport(Transport.STREAMING); + } } diff --git a/uitest/src/com/vaadin/tests/push/BasicPushStreamingTest.java b/uitest/src/com/vaadin/tests/push/BasicPushStreamingTest.java new file mode 100644 index 0000000000..67730f72c8 --- /dev/null +++ b/uitest/src/com/vaadin/tests/push/BasicPushStreamingTest.java @@ -0,0 +1,19 @@ +/* + * 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.push; + +public class BasicPushStreamingTest extends BasicPushTest { +}
\ No newline at end of file diff --git a/uitest/src/com/vaadin/tests/push/BasicPushTest.java b/uitest/src/com/vaadin/tests/push/BasicPushTest.java new file mode 100644 index 0000000000..57af8524bc --- /dev/null +++ b/uitest/src/com/vaadin/tests/push/BasicPushTest.java @@ -0,0 +1,92 @@ +/* + * 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.push; + +import org.junit.Assert; +import org.junit.Test; +import org.openqa.selenium.WebElement; + +import com.vaadin.tests.tb3.MultiBrowserTest; + +public abstract class BasicPushTest extends MultiBrowserTest { + + @Test + public void testPush() { + openTestURL(); + + // Test client initiated push + Assert.assertEquals(0, getClientCounter()); + getIncrementButton().click(); + Assert.assertEquals( + "Client counter not incremented by button click", 1, + getClientCounter()); + getIncrementButton().click(); + getIncrementButton().click(); + getIncrementButton().click(); + Assert.assertEquals( + "Four clicks should have incremented counter to 4", 4, + getClientCounter()); + + // Test server initiated push + getServerCounterStartButton().click(); + try { + Assert.assertEquals(0, getServerCounter()); + sleep(3000); + int serverCounter = getServerCounter(); + if (serverCounter < 1) { + // No push has happened + Assert.fail("No push has occured within 3s"); + } + sleep(3000); + if (getServerCounter() <= serverCounter) { + // No push has happened + Assert.fail("Only one push took place within 6s"); + + } + } finally { + // Avoid triggering push assertions + getServerCounterStopButton().click(); + } + } + + private int getServerCounter() { + return Integer.parseInt(getServerCounterElement().getText()); + } + + private int getClientCounter() { + return Integer.parseInt(getClientCounterElement().getText()); + } + + private WebElement getServerCounterElement() { + return vaadinElement("/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[4]/VLabel[0]"); + } + + private WebElement getServerCounterStartButton() { + return vaadinElement("/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[5]/VButton[0]/domChild[0]/domChild[0]"); + } + + private WebElement getServerCounterStopButton() { + return vaadinElement("/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[6]/VButton[0]/domChild[0]/domChild[0]"); + } + + private WebElement getIncrementButton() { + return vaadinElement("/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[2]/VButton[0]/domChild[0]/domChild[0]"); + } + + private WebElement getClientCounterElement() { + return vaadinElement("/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[1]/VLabel[0]"); + } +}
\ No newline at end of file diff --git a/uitest/src/com/vaadin/tests/push/BasicPushWebsocket.java b/uitest/src/com/vaadin/tests/push/BasicPushWebsocket.java index 6fc27e8974..96793a90f8 100644 --- a/uitest/src/com/vaadin/tests/push/BasicPushWebsocket.java +++ b/uitest/src/com/vaadin/tests/push/BasicPushWebsocket.java @@ -1,8 +1,32 @@ +/* + * 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.push; import com.vaadin.annotations.Push; +import com.vaadin.server.VaadinRequest; import com.vaadin.shared.ui.ui.Transport; @Push(transport = Transport.WEBSOCKET) public class BasicPushWebsocket extends BasicPush { + + @Override + public void init(VaadinRequest request) { + super.init(request); + // Don't use fallback so we can easier detect if websocket fails + getPushConfiguration().setFallbackTransport(Transport.WEBSOCKET); + } + } diff --git a/uitest/src/com/vaadin/tests/push/BasicPushWebsocketTest.java b/uitest/src/com/vaadin/tests/push/BasicPushWebsocketTest.java new file mode 100644 index 0000000000..ae4e64ad6b --- /dev/null +++ b/uitest/src/com/vaadin/tests/push/BasicPushWebsocketTest.java @@ -0,0 +1,29 @@ +/* + * 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.push; + +import java.util.Collection; + +import org.openqa.selenium.remote.DesiredCapabilities; + +import com.vaadin.tests.tb3.WebsocketTest; + +public class BasicPushWebsocketTest extends BasicPushTest { + @Override + public Collection<DesiredCapabilities> getBrowsersToTest() { + return WebsocketTest.getWebsocketBrowsers(); + } +}
\ No newline at end of file diff --git a/uitest/src/com/vaadin/tests/push/EnableDisablePush.html b/uitest/src/com/vaadin/tests/push/EnableDisablePush.html deleted file mode 100644 index 87dfa8428f..0000000000 --- a/uitest/src/com/vaadin/tests/push/EnableDisablePush.html +++ /dev/null @@ -1,97 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> -<head profile="http://selenium-ide.openqa.org/profiles/test-case"> -<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> -<link rel="selenium.base" href="" /> -<title>EnableDisablePush</title> -</head> -<body> -<table cellpadding="1" cellspacing="1" border="1"> -<thead> -<tr><td rowspan="1" colspan="3">EnableDisablePush</td></tr> -</thead><tbody> -<tr> - <td>open</td> - <td>/run/EnableDisablePush?restartApplication</td> - <td></td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runEnableDisablePush::PID_SLog_row_0</td> - <td>1. Push enabled</td> -</tr> -<tr> - <td>click</td> - <td>vaadin=runEnableDisablePush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VButton[0]/domChild[0]/domChild[0]</td> - <td></td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runEnableDisablePush::PID_SLog_row_0</td> - <td>3. Push disabled</td> -</tr> -<tr> - <td>click</td> - <td>vaadin=runEnableDisablePush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[3]/VButton[0]/domChild[0]/domChild[0]</td> - <td></td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runEnableDisablePush::PID_SLog_row_0</td> - <td>5. Poll enabled</td> -</tr> -<tr> - <td>click</td> - <td>vaadin=runEnableDisablePush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[1]/VButton[0]/domChild[0]/domChild[0]</td> - <td></td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runEnableDisablePush::PID_SLog_row_0</td> - <td>7. Push enabled</td> -</tr> -<tr> - <td>click</td> - <td>vaadin=runEnableDisablePush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[2]/VButton[0]/domChild[0]/domChild[0]</td> - <td></td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runEnableDisablePush::PID_SLog_row_0</td> - <td>9. Poll disabled</td> -</tr> -<tr> - <td>click</td> - <td>vaadin=runEnableDisablePush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[4]/VButton[0]/domChild[0]/domChild[0]</td> - <td></td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runEnableDisablePush::PID_SLog_row_0</td> - <td>11. Push disabled, polling enabled</td> -</tr> -<tr> - <td>pause</td> - <td>3500</td> - <td></td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runEnableDisablePush::PID_SLog_row_0</td> - <td>16. Polling disabled, push enabled</td> -</tr> -<tr> - <td>click</td> - <td>vaadin=runEnableDisablePush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VButton[0]/domChild[0]/domChild[0]</td> - <td></td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runEnableDisablePush::PID_SLog_row_0</td> - <td>18. Push disabled</td> -</tr> - -</tbody></table> -</body> -</html> diff --git a/uitest/src/com/vaadin/tests/push/EnableDisablePush.java b/uitest/src/com/vaadin/tests/push/EnableDisablePush.java index 1911c66c2d..50dab43667 100644 --- a/uitest/src/com/vaadin/tests/push/EnableDisablePush.java +++ b/uitest/src/com/vaadin/tests/push/EnableDisablePush.java @@ -1,19 +1,74 @@ package com.vaadin.tests.push; +import static org.junit.Assert.assertEquals; + import java.util.Date; import java.util.Timer; import java.util.TimerTask; import java.util.concurrent.TimeUnit; +import org.junit.Test; +import org.openqa.selenium.WebElement; + import com.vaadin.server.VaadinRequest; import com.vaadin.shared.communication.PushMode; import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.tests.tb3.MultiBrowserTest; import com.vaadin.tests.util.Log; import com.vaadin.ui.Button; import com.vaadin.ui.UIDetachedException; public class EnableDisablePush extends AbstractTestUI { + public static class EnableDisablePushTest extends MultiBrowserTest { + @Test + public void testEnablePushWhenUsingPolling() throws Exception { + openTestURL(); + + assertEquals("1. Push enabled", getLogRow(0)); + + getDisablePushButton().click(); + assertEquals("3. Push disabled", getLogRow(0)); + + getEnablePollButton().click(); + assertEquals("5. Poll enabled", getLogRow(0)); + + getEnablePushButton().click(); + assertEquals("7. Push enabled", getLogRow(0)); + + getDisablePollButton().click(); + assertEquals("9. Poll disabled", getLogRow(0)); + + getDisablePushButtonAndReenableFromBackground().click(); + Thread.sleep(2500); + assertEquals("16. Polling disabled, push enabled", getLogRow(0)); + + getDisablePushButton().click(); + assertEquals("18. Push disabled", getLogRow(0)); + } + + private WebElement getDisablePushButton() { + return vaadinElement("/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VButton[0]"); + } + + private WebElement getEnablePushButton() { + return vaadinElement("/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[1]/VButton[0]"); + } + + private WebElement getDisablePollButton() { + return vaadinElement("/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[2]/VButton[0]"); + } + + private WebElement getEnablePollButton() { + return vaadinElement("/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[3]/VButton[0]"); + } + + private WebElement getDisablePushButtonAndReenableFromBackground() { + return vaadinElement("/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[4]/VButton[0]"); + } + + } + private int c = 0; private Log log = new Log(15); @@ -27,7 +82,7 @@ public class EnableDisablePush extends AbstractTestUI { try { while (true) { - TimeUnit.MILLISECONDS.sleep(1000); + TimeUnit.MILLISECONDS.sleep(500); access(new Runnable() { @Override @@ -42,6 +97,9 @@ public class EnableDisablePush extends AbstractTestUI { } } }); + if (c == 3) { + return; + } } } catch (InterruptedException e) { } catch (UIDetachedException e) { diff --git a/uitest/src/com/vaadin/tests/push/PushConfiguration.html b/uitest/src/com/vaadin/tests/push/PushConfiguration.html deleted file mode 100644 index c3786b1cc1..0000000000 --- a/uitest/src/com/vaadin/tests/push/PushConfiguration.html +++ /dev/null @@ -1,130 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> -<head profile="http://selenium-ide.openqa.org/profiles/test-case"> -<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> -<link rel="selenium.base" href="http://localhost:8888/" /> -<title>New Test</title> -</head> -<body> -<table cellpadding="1" cellspacing="1" border="1"> -<thead> -<tr><td rowspan="1" colspan="3">New Test</td></tr> -</thead><tbody> -<!--Websocket--> -<tr> - <td>open</td> - <td>/run/com.vaadin.tests.push.PushConfigurationTest?debug&restartApplication</td> - <td></td> -</tr> -<tr> - <td>assertNotText</td> - <td>vaadin=runcomvaadintestspushPushConfigurationTest::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[5]/VLabel[0]</td> - <td>4</td> -</tr> -<tr> - <td>select</td> - <td>vaadin=runcomvaadintestspushPushConfigurationTest::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VVerticalLayout[0]/Slot[0]/VVerticalLayout[0]/Slot[1]/VNativeSelect[0]/domChild[0]</td> - <td>label=WEBSOCKET</td> -</tr> -<tr> - <td>assertNotText</td> - <td>vaadin=runcomvaadintestspushPushConfigurationTest::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[5]/VLabel[0]</td> - <td>4</td> -</tr> -<tr> - <td>select</td> - <td>vaadin=runcomvaadintestspushPushConfigurationTest::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VVerticalLayout[0]/Slot[0]/VVerticalLayout[0]/Slot[0]/VNativeSelect[0]/domChild[0]</td> - <td>label=AUTOMATIC</td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runcomvaadintestspushPushConfigurationTest::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VVerticalLayout[0]/Slot[0]/VVerticalLayout[0]/Slot[5]/VLabel[0]/domChild[0]</td> - <td>*fallbackTransport: streaming*transport: websocket*</td> -</tr> -<tr> - <td>assertNotText</td> - <td>vaadin=runcomvaadintestspushPushConfigurationTest::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[5]/VLabel[0]</td> - <td>4</td> -</tr> -<tr> - <td>waitForText</td> - <td>vaadin=runcomvaadintestspushPushConfigurationTest::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[5]/VLabel[0]</td> - <td>4</td> -</tr> -<!--Use debug console to verify we used the correct transport type--> -<tr> - <td>assertTextPresent</td> - <td>Push connection established using websocket</td> - <td></td> -</tr> -<tr> - <td>assertTextNotPresent</td> - <td>Push connection established using streaming</td> - <td>Push connection established using streaming</td> -</tr> -<tr> - <td>select</td> - <td>vaadin=runcomvaadintestspushPushConfigurationTest::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VVerticalLayout[0]/Slot[0]/VVerticalLayout[0]/Slot[0]/VNativeSelect[0]/domChild[0]</td> - <td>label=DISABLED</td> -</tr> -<!--Streaming--> -<tr> - <td>open</td> - <td>/run/com.vaadin.tests.push.PushConfigurationTest?debug&restartApplication</td> - <td></td> -</tr> -<tr> - <td>assertNotText</td> - <td>vaadin=runcomvaadintestspushPushConfigurationTest::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[5]/VLabel[0]</td> - <td>4</td> -</tr> -<tr> - <td>select</td> - <td>vaadin=runcomvaadintestspushPushConfigurationTest::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VVerticalLayout[0]/Slot[0]/VVerticalLayout[0]/Slot[1]/VNativeSelect[0]/domChild[0]</td> - <td>label=STREAMING</td> -</tr> -<tr> - <td>assertNotText</td> - <td>vaadin=runcomvaadintestspushPushConfigurationTest::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[5]/VLabel[0]</td> - <td>4</td> -</tr> -<tr> - <td>select</td> - <td>vaadin=runcomvaadintestspushPushConfigurationTest::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VVerticalLayout[0]/Slot[0]/VVerticalLayout[0]/Slot[0]/VNativeSelect[0]/domChild[0]</td> - <td>label=AUTOMATIC</td> -</tr> -<tr> - <td>assertNotText</td> - <td>vaadin=runcomvaadintestspushPushConfigurationTest::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[5]/VLabel[0]</td> - <td>4</td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runcomvaadintestspushPushConfigurationTest::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VVerticalLayout[0]/Slot[0]/VVerticalLayout[0]/Slot[5]/VLabel[0]/domChild[0]</td> - <td>*fallbackTransport: streaming*transport: streaming*</td> -</tr> -<tr> - <td>waitForText</td> - <td>vaadin=runcomvaadintestspushPushConfigurationTest::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[5]/VLabel[0]</td> - <td>4</td> -</tr> -<!--Use debug console to verify we used the correct transport type--> -<tr> - <td>assertTextNotPresent</td> - <td>Push connection established using websocket</td> - <td></td> -</tr> -<tr> - <td>assertTextPresent</td> - <td>Push connection established using streaming</td> - <td></td> -</tr> -<tr> - <td>select</td> - <td>vaadin=runcomvaadintestspushPushConfigurationTest::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VVerticalLayout[0]/Slot[0]/VVerticalLayout[0]/Slot[0]/VNativeSelect[0]/domChild[0]</td> - <td>label=DISABLED</td> -</tr> -</tbody></table> -</body> -</html> diff --git a/uitest/src/com/vaadin/tests/push/PushConfiguration.java b/uitest/src/com/vaadin/tests/push/PushConfiguration.java new file mode 100644 index 0000000000..a7ba4e43ba --- /dev/null +++ b/uitest/src/com/vaadin/tests/push/PushConfiguration.java @@ -0,0 +1,117 @@ +/* + * 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.push; + +import java.util.Date; +import java.util.Timer; +import java.util.TimerTask; + +import com.vaadin.data.util.ObjectProperty; +import com.vaadin.server.VaadinRequest; +import com.vaadin.shared.ui.label.ContentMode; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.Label; + +public class PushConfiguration extends AbstractTestUI { + + private ObjectProperty<Integer> counter = new ObjectProperty<Integer>(0); + + private ObjectProperty<Integer> counter2 = new ObjectProperty<Integer>(0); + + private final Timer timer = new Timer(true); + + private final TimerTask task = new TimerTask() { + + @Override + public void run() { + access(new Runnable() { + @Override + public void run() { + counter2.setValue(counter2.getValue() + 1); + } + }); + } + }; + + @Override + protected void setup(VaadinRequest request) { + addComponent(new PushConfigurator(this)); + spacer(); + + /* + * Client initiated push. + */ + Label lbl = new Label(counter); + lbl.setCaption("Client counter (click 'increment' to update):"); + addComponent(lbl); + + addComponent(new Button("Increment", new Button.ClickListener() { + + @Override + public void buttonClick(ClickEvent event) { + counter.setValue(counter.getValue() + 1); + } + })); + + spacer(); + + /* + * Server initiated push. + */ + lbl = new Label(counter2); + lbl.setCaption("Server counter (updates each 1s by server thread) :"); + addComponent(lbl); + + addComponent(new Button("Reset", new Button.ClickListener() { + + @Override + public void buttonClick(ClickEvent event) { + counter2.setValue(0); + } + })); + } + + @Override + protected String getTestDescription() { + return "This test tests the very basic operations of push. " + + "It tests that client initiated changes are " + + "recieved back to the client as well as server " + + "initiated changes are correctly updated to the client."; + } + + @Override + protected Integer getTicketNumber() { + return 11494; + } + + private void spacer() { + addComponent(new Label("<hr/>", ContentMode.HTML)); + } + + @Override + public void attach() { + super.attach(); + timer.scheduleAtFixedRate(task, new Date(), 1000); + } + + @Override + public void detach() { + super.detach(); + timer.cancel(); + } +} diff --git a/uitest/src/com/vaadin/tests/push/PushConfigurationTest.java b/uitest/src/com/vaadin/tests/push/PushConfigurationTest.java index b57e9732cc..1f8c4c0e38 100644 --- a/uitest/src/com/vaadin/tests/push/PushConfigurationTest.java +++ b/uitest/src/com/vaadin/tests/push/PushConfigurationTest.java @@ -1,102 +1,111 @@ +/* + * 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.push; -import java.util.Date; -import java.util.Timer; -import java.util.TimerTask; - -import com.vaadin.data.util.ObjectProperty; -import com.vaadin.server.VaadinRequest; -import com.vaadin.shared.ui.label.ContentMode; -import com.vaadin.tests.components.AbstractTestUI; -import com.vaadin.ui.Button; -import com.vaadin.ui.Button.ClickEvent; -import com.vaadin.ui.Label; - -public class PushConfigurationTest extends AbstractTestUI { - - private ObjectProperty<Integer> counter = new ObjectProperty<Integer>(0); - - private ObjectProperty<Integer> counter2 = new ObjectProperty<Integer>(0); - - private final Timer timer = new Timer(true); - - private final TimerTask task = new TimerTask() { - - @Override - public void run() { - access(new Runnable() { - @Override - public void run() { - counter2.setValue(counter2.getValue() + 1); - } - }); - } - }; - - @Override - protected void setup(VaadinRequest request) { - addComponent(new PushConfigurator(this)); - spacer(); - - /* - * Client initiated push. - */ - Label lbl = new Label(counter); - lbl.setCaption("Client counter (click 'increment' to update):"); - addComponent(lbl); - - addComponent(new Button("Increment", new Button.ClickListener() { +import org.junit.Assert; +import org.junit.Test; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.support.ui.ExpectedCondition; +import org.openqa.selenium.support.ui.Select; + +import com.vaadin.tests.tb3.WebsocketTest; + +public class PushConfigurationTest extends WebsocketTest { + + @Test + public void testWebsocketAndStreaming() { + setDebug(true); + openTestURL(); + // Websocket + int counter = getServerCounter(); + assertGreaterOrEqual("Counter should be >= 1. Was: " + counter, + counter, 1); + new Select(getTransportSelect()).selectByVisibleText("WEBSOCKET"); + new Select(getPushModeSelect()).selectByVisibleText("AUTOMATIC"); + Assert.assertTrue(vaadinElement( + "/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VVerticalLayout[0]/Slot[0]/VVerticalLayout[0]/Slot[5]/VLabel[0]/domChild[0]") + .getText() + .matches( + "^[\\s\\S]*fallbackTransport: streaming[\\s\\S]*transport: websocket[\\s\\S]*$")); + counter = getServerCounter(); + final int waitCounter = counter + 2; + waitUntil(new ExpectedCondition<Boolean>() { @Override - public void buttonClick(ClickEvent event) { - counter.setValue(counter.getValue() + 1); + public Boolean apply(WebDriver input) { + return (getServerCounter() >= waitCounter); } - })); - - spacer(); - - /* - * Server initiated push. - */ - lbl = new Label(counter2); - lbl.setCaption("Server counter (updates each 1s by server thread) :"); - addComponent(lbl); - - addComponent(new Button("Reset", new Button.ClickListener() { - - @Override - public void buttonClick(ClickEvent event) { - counter2.setValue(0); + }); + + // Use debug console to verify we used the correct transport type + Assert.assertTrue(driver.getPageSource().contains( + "Push connection established using websocket")); + Assert.assertFalse(driver.getPageSource().contains( + "Push connection established using streaming")); + + new Select(getPushModeSelect()).selectByVisibleText("DISABLED"); + + // Streaming + driver.get(getTestUrl()); + Assert.assertEquals(1, getServerCounter()); + + new Select(getTransportSelect()).selectByVisibleText("STREAMING"); + new Select(getPushModeSelect()).selectByVisibleText("AUTOMATIC"); + Assert.assertTrue(vaadinElement( + "/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VVerticalLayout[0]/Slot[0]/VVerticalLayout[0]/Slot[5]/VLabel[0]/domChild[0]") + .getText() + .matches( + "^[\\s\\S]*fallbackTransport: streaming[\\s\\S]*transport: streaming[\\s\\S]*$")); + + counter = getServerCounter(); + for (int second = 0;; second++) { + if (second >= 5) { + Assert.fail("timeout"); } - })); - } + if (getServerCounter() >= (counter + 2)) { + break; + } + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + } + } + + // Use debug console to verify we used the correct transport type + Assert.assertFalse(driver.getPageSource().contains( + "Push connection established using websocket")); + Assert.assertTrue(driver.getPageSource().contains( + "Push connection established using streaming")); - @Override - protected String getTestDescription() { - return "This test tests the very basic operations of push. " - + "It tests that client initiated changes are " - + "recieved back to the client as well as server " - + "initiated changes are correctly updated to the client."; } - @Override - protected Integer getTicketNumber() { - return 11494; + private WebElement getPushModeSelect() { + return vaadinElement("/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VVerticalLayout[0]/Slot[0]/VVerticalLayout[0]/Slot[0]/VNativeSelect[0]/domChild[0]"); } - private void spacer() { - addComponent(new Label("<hr/>", ContentMode.HTML)); + private WebElement getTransportSelect() { + return vaadinElement("/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VVerticalLayout[0]/Slot[0]/VVerticalLayout[0]/Slot[1]/VNativeSelect[0]/domChild[0]"); } - @Override - public void attach() { - super.attach(); - timer.scheduleAtFixedRate(task, new Date(), 1000); + private int getServerCounter() { + return Integer.parseInt(getServerCounterElement().getText()); } - @Override - public void detach() { - super.detach(); - timer.cancel(); + private WebElement getServerCounterElement() { + return vaadinElement("/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[5]/VLabel[0]"); } -} +}
\ No newline at end of file diff --git a/uitest/src/com/vaadin/tests/push/PushFromInit.java b/uitest/src/com/vaadin/tests/push/PushFromInit.java index 4b442de499..cb084f1232 100644 --- a/uitest/src/com/vaadin/tests/push/PushFromInit.java +++ b/uitest/src/com/vaadin/tests/push/PushFromInit.java @@ -1,3 +1,18 @@ +/* + * 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.push; import com.vaadin.server.VaadinRequest; diff --git a/uitest/src/com/vaadin/tests/push/PushFromInitTest.java b/uitest/src/com/vaadin/tests/push/PushFromInitTest.java new file mode 100644 index 0000000000..3c1bc1b610 --- /dev/null +++ b/uitest/src/com/vaadin/tests/push/PushFromInitTest.java @@ -0,0 +1,50 @@ +/* + * 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.push; + +import org.junit.Assert; +import org.junit.Test; + +import com.vaadin.tests.tb3.MultiBrowserTest; + +public class PushFromInitTest extends MultiBrowserTest { + @Test + public void testPushFromInit() { + openTestURL(); + + for (int second = 0;; second++) { + if (second >= 30) { + Assert.fail("timeout"); + } + try { + if ("1. Logged in init".equals(vaadinElementById( + "Log_row_1").getText())) { + break; + } + } catch (Exception e) { + } + try { + Thread.sleep(200); + } catch (InterruptedException e) { + } + } + + Assert.assertEquals( + "2. Logged from background thread started in init", + vaadinElementById("Log_row_0").getText()); + + } +}
\ No newline at end of file diff --git a/uitest/src/com/vaadin/tests/push/PushReattachedComponent.html b/uitest/src/com/vaadin/tests/push/PushReattachedComponent.html deleted file mode 100644 index e1f6a5f048..0000000000 --- a/uitest/src/com/vaadin/tests/push/PushReattachedComponent.html +++ /dev/null @@ -1,47 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> -<head profile="http://selenium-ide.openqa.org/profiles/test-case"> -<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> -<link rel="selenium.base" href="http://192.168.2.162:8888/" /> -<title>New Test</title> -</head> -<body> -<table cellpadding="1" cellspacing="1" border="1"> -<thead> -<tr><td rowspan="1" colspan="3">New Test</td></tr> -</thead><tbody> -<tr> - <td>open</td> - <td>/run-push/com.vaadin.tests.components.panel.PanelChangeContents?restartApplication</td> - <td></td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runpushcomvaadintestscomponentspanelPanelChangeContents::/VVerticalLayout[0]/Slot[1]/VPanel[0]/VVerticalLayout[0]/Slot[0]/VLabel[0]</td> - <td>stats</td> -</tr> -<tr> - <td>click</td> - <td>vaadin=runpushcomvaadintestscomponentspanelPanelChangeContents::/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[1]/VButton[0]/domChild[0]/domChild[0]</td> - <td></td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runpushcomvaadintestscomponentspanelPanelChangeContents::/VVerticalLayout[0]/Slot[1]/VPanel[0]/VVerticalLayout[0]/Slot[0]/VLabel[0]</td> - <td>companies</td> -</tr> -<tr> - <td>click</td> - <td>vaadin=runpushcomvaadintestscomponentspanelPanelChangeContents::/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[0]/VButton[0]/domChild[0]/domChild[0]</td> - <td></td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runpushcomvaadintestscomponentspanelPanelChangeContents::/VVerticalLayout[0]/Slot[1]/VPanel[0]/VVerticalLayout[0]/Slot[0]/VLabel[0]</td> - <td>stats</td> -</tr> - -</tbody></table> -</body> -</html> diff --git a/uitest/src/com/vaadin/tests/push/PushTransportAnnotation.html b/uitest/src/com/vaadin/tests/push/PushTransportAnnotation.html deleted file mode 100644 index 854dd458bb..0000000000 --- a/uitest/src/com/vaadin/tests/push/PushTransportAnnotation.html +++ /dev/null @@ -1,46 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> -<head profile="http://selenium-ide.openqa.org/profiles/test-case"> -<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> -<link rel="selenium.base" href="http://localhost:8888/" /> -<title>New Test</title> -</head> -<body> -<table cellpadding="1" cellspacing="1" border="1"> -<thead> -<tr><td rowspan="1" colspan="3">New Test</td></tr> -</thead><tbody> -<tr> - <td>open</td> - <td>/run/com.vaadin.tests.push.BasicPushStreaming?debug&restartApplication</td> - <td></td> -</tr> -<tr> - <td>waitForTextPresent</td> - <td>Push connection established using streaming</td> - <td></td> -</tr> -<tr> - <td>assertTextNotPresent</td> - <td>Push connection established using websocket</td> - <td></td> -</tr> -<tr> - <td>open</td> - <td>/run/com.vaadin.tests.push.BasicPushWebsocket?debug&restartApplication</td> - <td></td> -</tr> -<tr> - <td>assertTextNotPresent</td> - <td>Push connection established using streaming</td> - <td></td> -</tr> -<tr> - <td>waitForTextPresent</td> - <td>Push connection established using websocket</td> - <td></td> -</tr> -</tbody></table> -</body> -</html> diff --git a/uitest/src/com/vaadin/tests/push/StreamingPush.html b/uitest/src/com/vaadin/tests/push/StreamingPush.html deleted file mode 100644 index cf94a09c63..0000000000 --- a/uitest/src/com/vaadin/tests/push/StreamingPush.html +++ /dev/null @@ -1,88 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> -<head profile="http://selenium-ide.openqa.org/profiles/test-case"> -<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> -<link rel="selenium.base" href="http://localhost:8888/" /> -<title>New Test</title> -</head> -<body> -<table cellpadding="1" cellspacing="1" border="1"> -<thead> -<tr><td rowspan="1" colspan="3">New Test</td></tr> -</thead><tbody> -<tr> - <td>open</td> - <td>/run-push/com.vaadin.tests.push.BasicPush?restartApplication&debug&transport=streaming</td> - <td></td> -</tr> -<!--Test client initiated push --> -<tr> - <td>assertText</td> - <td>vaadin=runpushcomvaadintestspushBasicPush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[1]/VLabel[0]</td> - <td>0</td> -</tr> -<tr> - <td>click</td> - <td>vaadin=runpushcomvaadintestspushBasicPush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[2]/VButton[0]/domChild[0]/domChild[0]</td> - <td></td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runpushcomvaadintestspushBasicPush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[1]/VLabel[0]</td> - <td>1</td> -</tr> -<tr> - <td>click</td> - <td>vaadin=runpushcomvaadintestspushBasicPush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[2]/VButton[0]/domChild[0]/domChild[0]</td> - <td></td> -</tr> -<tr> - <td>click</td> - <td>vaadin=runpushcomvaadintestspushBasicPush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[2]/VButton[0]/domChild[0]/domChild[0]</td> - <td></td> -</tr> -<tr> - <td>click</td> - <td>vaadin=runpushcomvaadintestspushBasicPush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[2]/VButton[0]/domChild[0]/domChild[0]</td> - <td></td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runpushcomvaadintestspushBasicPush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[1]/VLabel[0]</td> - <td>4</td> -</tr> -<!--Test server initiated push--> -<tr> - <td>click</td> - <td>vaadin=runpushcomvaadintestspushBasicPush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[5]/VButton[0]/domChild[0]/domChild[0]</td> - <td></td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runpushcomvaadintestspushBasicPush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[4]/VLabel[0]</td> - <td>0</td> -</tr> -<tr> - <td>pause</td> - <td>3000</td> - <td></td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runpushcomvaadintestspushBasicPush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[4]/VLabel[0]</td> - <td>1</td> -</tr> -<tr> - <td>pause</td> - <td>3000</td> - <td></td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runpushcomvaadintestspushBasicPush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[4]/VLabel[0]</td> - <td>2</td> -</tr> -</tbody></table> -</body> -</html> diff --git a/uitest/src/com/vaadin/tests/push/TogglePush.html b/uitest/src/com/vaadin/tests/push/TogglePush.html deleted file mode 100644 index b752d2120c..0000000000 --- a/uitest/src/com/vaadin/tests/push/TogglePush.html +++ /dev/null @@ -1,91 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> -<head profile="http://selenium-ide.openqa.org/profiles/test-case"> -<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> -<link rel="selenium.base" href="" /> -<title>New Test</title> -</head> -<body> -<table cellpadding="1" cellspacing="1" border="1"> -<thead> -<tr><td rowspan="1" colspan="3">New Test</td></tr> -</thead><tbody> -<tr> - <td>open</td> - <td>/run-push/com.vaadin.tests.push.TogglePush?restartApplication</td> - <td></td> -</tr> -<tr> - <td>click</td> - <td>vaadin=runpushcomvaadintestspushTogglePush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[3]/VButton[0]/domChild[0]/domChild[0]</td> - <td></td> -</tr> -<tr> - <td>pause</td> - <td>2000</td> - <td></td> -</tr> -<!--Push is enabled, so text gets updated--> -<tr> - <td>assertText</td> - <td>vaadin=runpushcomvaadintestspushTogglePush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VLabel[0]</td> - <td>Counter has been updated 1 times</td> -</tr> -<tr> - <td>mouseClick</td> - <td>vaadin=runpushcomvaadintestspushTogglePush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[1]/VCheckBox[0]/domChild[0]</td> - <td>61,6</td> -</tr> -<tr> - <td>click</td> - <td>vaadin=runpushcomvaadintestspushTogglePush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[3]/VButton[0]/domChild[0]/domChild[0]</td> - <td></td> -</tr> -<tr> - <td>pause</td> - <td>2000</td> - <td></td> -</tr> -<!--Push is disabled, so text is not updated--> -<tr> - <td>assertText</td> - <td>vaadin=runpushcomvaadintestspushTogglePush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VLabel[0]</td> - <td>Counter has been updated 1 times</td> -</tr> -<tr> - <td>click</td> - <td>vaadin=runpushcomvaadintestspushTogglePush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[2]/VButton[0]/domChild[0]/domChild[0]</td> - <td></td> -</tr> -<!--Direct update is visible, and includes previous update--> -<tr> - <td>assertText</td> - <td>vaadin=runpushcomvaadintestspushTogglePush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VLabel[0]</td> - <td>Counter has been updated 3 times</td> -</tr> -<tr> - <td>mouseClick</td> - <td>vaadin=runpushcomvaadintestspushTogglePush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[1]/VCheckBox[0]/domChild[0]</td> - <td>61,3</td> -</tr> -<tr> - <td>click</td> - <td>vaadin=runpushcomvaadintestspushTogglePush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[3]/VButton[0]/domChild[0]/domChild[0]</td> - <td></td> -</tr> -<tr> - <td>pause</td> - <td>2000</td> - <td></td> -</tr> -<!--Push is enabled again, so text gets updated--> -<tr> - <td>assertText</td> - <td>vaadin=runpushcomvaadintestspushTogglePush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VLabel[0]</td> - <td>Counter has been updated 4 times</td> -</tr> - -</tbody></table> -</body> -</html> diff --git a/uitest/src/com/vaadin/tests/push/TogglePush.java b/uitest/src/com/vaadin/tests/push/TogglePush.java index c0bdc54ee0..6ec8903d65 100644 --- a/uitest/src/com/vaadin/tests/push/TogglePush.java +++ b/uitest/src/com/vaadin/tests/push/TogglePush.java @@ -1,3 +1,18 @@ +/* + * 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.push; import java.util.Timer; diff --git a/uitest/src/com/vaadin/tests/push/TogglePushInInit.html b/uitest/src/com/vaadin/tests/push/TogglePushInInit.html deleted file mode 100644 index c735f225e1..0000000000 --- a/uitest/src/com/vaadin/tests/push/TogglePushInInit.html +++ /dev/null @@ -1,69 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> -<head profile="http://selenium-ide.openqa.org/profiles/test-case"> -<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> -<link rel="selenium.base" href="http://localhost:8071/" /> -<title>TogglePushInInit</title> -</head> -<body> -<table cellpadding="1" cellspacing="1" border="1"> -<thead> -<tr><td rowspan="1" colspan="3">TogglePushInInit</td></tr> -</thead><tbody> -<!--Open with push disabled--> -<tr> - <td>open</td> - <td>/run-push/com.vaadin.tests.push.TogglePush?restartApplication&push=disabled</td> - <td></td> -</tr> -<tr> - <td>assertValue</td> - <td>vaadin=runpushcomvaadintestspushTogglePush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[1]/VCheckBox[0]/domChild[0]</td> - <td>off</td> -</tr> -<tr> - <td>click</td> - <td>vaadin=runpushcomvaadintestspushTogglePush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[3]/VButton[0]/domChild[0]/domChild[0]</td> - <td></td> -</tr> -<tr> - <td>pause</td> - <td>2000</td> - <td></td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runpushcomvaadintestspushTogglePush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VLabel[0]</td> - <td>Counter has been updated 0 times</td> -</tr> -<!--Open with push enabled--> -<tr> - <td>open</td> - <td>/run-push/com.vaadin.tests.push.TogglePush?restartApplication&push=enabled</td> - <td></td> -</tr> -<tr> - <td>assertValue</td> - <td>vaadin=runpushcomvaadintestspushTogglePush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[1]/VCheckBox[0]/domChild[0]</td> - <td>on</td> -</tr> -<tr> - <td>click</td> - <td>vaadin=runpushcomvaadintestspushTogglePush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[3]/VButton[0]/domChild[0]/domChild[0]</td> - <td></td> -</tr> -<tr> - <td>pause</td> - <td>2000</td> - <td></td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runpushcomvaadintestspushTogglePush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VLabel[0]</td> - <td>Counter has been updated 1 times</td> -</tr> - -</tbody></table> -</body> -</html> diff --git a/uitest/src/com/vaadin/tests/push/TogglePushTest.java b/uitest/src/com/vaadin/tests/push/TogglePushTest.java new file mode 100644 index 0000000000..68d6f52b9f --- /dev/null +++ b/uitest/src/com/vaadin/tests/push/TogglePushTest.java @@ -0,0 +1,112 @@ +/* + * 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.push; + +import org.junit.Assert; +import org.junit.Test; +import org.openqa.selenium.WebElement; + +import com.vaadin.tests.tb3.MultiBrowserTest; + +public class TogglePushTest extends MultiBrowserTest { + + @Test + public void togglePushInInit() { + setPush(true); + String url = getTestUrl(); + + // Open with push disabled + driver.get(addParameter(url, "push=disabled")); + + Assert.assertFalse(getPushToggle().isSelected()); + + getDelayedCounterUpdateButton().click(); + sleep(2000); + Assert.assertEquals("Counter has been updated 0 times", + getCounterText()); + + // Open with push enabled + driver.get(addParameter(url, "push=enabled")); + Assert.assertTrue(getPushToggle().isSelected()); + + getDelayedCounterUpdateButton().click(); + sleep(2000); + Assert.assertEquals("Counter has been updated 1 times", + getCounterText()); + + } + + private String addParameter(String url, String queryParameter) { + if (url.contains("?")) { + return url + "&" + queryParameter; + } else { + return url + "?" + queryParameter; + } + } + + @Test + public void togglePush() { + setPush(true); + openTestURL(); + getDelayedCounterUpdateButton().click(); + sleep(2000); + + // Push is enabled, so text gets updated + Assert.assertEquals("Counter has been updated 1 times", + getCounterText()); + + // Disable push + getPushToggle().click(); + getDelayedCounterUpdateButton().click(); + sleep(2000); + // Push is disabled, so text is not updated + Assert.assertEquals("Counter has been updated 1 times", + getCounterText()); + + getDirectCounterUpdateButton().click(); + // Direct update is visible, and includes previous update + Assert.assertEquals("Counter has been updated 3 times", + getCounterText()); + + // Re-enable push + getPushToggle().click(); + getDelayedCounterUpdateButton().click(); + sleep(2000); + + // Push is enabled again, so text gets updated + Assert.assertEquals("Counter has been updated 4 times", + getCounterText()); + } + + private WebElement getDirectCounterUpdateButton() { + return vaadinElement("/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[2]/VButton[0]/domChild[0]/domChild[0]"); + } + + private WebElement getPushToggle() { + return vaadinElement("/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[1]/VCheckBox[0]/domChild[0]"); + } + + private WebElement getDelayedCounterUpdateButton() { + return vaadinElement("/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[3]/VButton[0]/domChild[0]/domChild[0]"); + } + + private String getCounterText() { + return vaadinElement( + "/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VLabel[0]") + .getText(); + } + +}
\ No newline at end of file diff --git a/uitest/src/com/vaadin/tests/push/TrackMessageSizeUnitTests.java b/uitest/src/com/vaadin/tests/push/TrackMessageSizeUI.java index 062698edf5..67715339da 100644 --- a/uitest/src/com/vaadin/tests/push/TrackMessageSizeUnitTests.java +++ b/uitest/src/com/vaadin/tests/push/TrackMessageSizeUI.java @@ -35,7 +35,7 @@ import com.vaadin.ui.JavaScriptFunction; // Load vaadinPush.js so that jQueryVaadin is defined @JavaScript("vaadin://vaadinPush.js") -public class TrackMessageSizeUnitTests extends AbstractTestUIWithLog { +public class TrackMessageSizeUI extends AbstractTestUIWithLog { private String testMethod = "function testSequence(expected, data) {\n" + " var request = {trackMessageLength: true, messageDelimiter: '|'};\n" diff --git a/uitest/src/com/vaadin/tests/push/TrackMessageSizeUITest.java b/uitest/src/com/vaadin/tests/push/TrackMessageSizeUITest.java new file mode 100644 index 0000000000..f904675b5e --- /dev/null +++ b/uitest/src/com/vaadin/tests/push/TrackMessageSizeUITest.java @@ -0,0 +1,30 @@ +/* + * 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.push; + +import org.junit.Assert; +import org.junit.Test; + +import com.vaadin.tests.tb3.MultiBrowserTest; + +public class TrackMessageSizeUITest extends MultiBrowserTest { + @Test + public void runTests() { + openTestURL(); + Assert.assertEquals("1. All tests run", + vaadinElementById("Log_row_0").getText()); + } +}
\ No newline at end of file diff --git a/uitest/src/com/vaadin/tests/push/TrackMessageSizeUnitTests.html b/uitest/src/com/vaadin/tests/push/TrackMessageSizeUnitTests.html deleted file mode 100644 index 89dd7d4e78..0000000000 --- a/uitest/src/com/vaadin/tests/push/TrackMessageSizeUnitTests.html +++ /dev/null @@ -1,26 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> -<head profile="http://selenium-ide.openqa.org/profiles/test-case"> -<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> -<link rel="selenium.base" href="http://192.168.2.162:8888/" /> -<title>New Test</title> -</head> -<body> -<table cellpadding="1" cellspacing="1" border="1"> -<thead> -<tr><td rowspan="1" colspan="3">New Test</td></tr> -</thead><tbody> -<tr> - <td>open</td> - <td>/run/com.vaadin.tests.push.TrackMessageSizeUnitTests?restartApplication</td> - <td></td> -</tr> -<tr> - <td>assertText</td> - <td>vaadin=runcomvaadintestspushTrackMessageSizeUnitTests::PID_SLog_row_0</td> - <td>1. All tests run</td> -</tr> -</tbody></table> -</body> -</html> diff --git a/uitest/src/com/vaadin/tests/tb3/AbstractTB3Test.java b/uitest/src/com/vaadin/tests/tb3/AbstractTB3Test.java new file mode 100644 index 0000000000..1967891a7a --- /dev/null +++ b/uitest/src/com/vaadin/tests/tb3/AbstractTB3Test.java @@ -0,0 +1,793 @@ +/* + * 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.tb3; + +import java.net.URL; +import java.util.Collection; +import java.util.Collections; +import java.util.logging.Logger; + +import org.junit.After; +import org.junit.Before; +import org.junit.runner.RunWith; +import org.openqa.selenium.By; +import org.openqa.selenium.Platform; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.remote.BrowserType; +import org.openqa.selenium.remote.DesiredCapabilities; +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.vaadin.server.LegacyApplication; +import com.vaadin.server.UIProvider; +import com.vaadin.testbench.TestBench; +import com.vaadin.testbench.TestBenchTestCase; +import com.vaadin.tests.components.AbstractTestUIWithLog; +import com.vaadin.ui.UI; + +/** + * Base class for TestBench 3+ tests. All TB3+ tests in the project should + * extend this class. + * + * Provides: + * <ul> + * <li>Helpers for browser selection</li> + * <li>Hub connection setup and teardown</li> + * <li>Automatic generation of URL for a given test on the development server + * using {@link #getUIClass()} or by automatically finding an enclosing UI class + * 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 { + /** + * Height of the screenshots we want to capture + */ + private static final int SCREENSHOT_HEIGHT = 850; + + /** + * Width of the screenshots we want to capture + */ + private static final int SCREENSHOT_WIDTH = 1500; + + private DesiredCapabilities desiredCapabilities; + + private boolean debug = false; + + private boolean push = false; + { + // Default browser to run on unless setDesiredCapabilities is called + desiredCapabilities = BrowserUtil.firefox(24); + } + + /** + * 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 + 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 = getDesiredCapabilities(); + + WebDriver dr = TestBench.createDriver(new RemoteWebDriver(new URL( + getHubURL()), capabilities)); + setDriver(dr); + + int w = SCREENSHOT_WIDTH; + int h = SCREENSHOT_HEIGHT; + + if (BrowserUtil.isIE8(capabilities)) { + // IE8 gets size wrong, who would have guessed... + w += 4; + h += 4; + } + try { + testBench().resizeViewPortTo(w, h); + } catch (UnsupportedOperationException e) { + // Opera does not support this... + } + + } + + /** + * Opens the given test (defined by {@link #getTestUrl(boolean, boolean)}, + * optionally with debug window and/or push + * + * @param debug + * @param push + */ + protected void openTestURL() { + driver.get(getTestUrl()); + } + + /** + * Returns the full URL to be used for the test + * + * @return the full URL for the test + */ + protected String getTestUrl() { + String baseUrl = getBaseURL(); + if (baseUrl.endsWith("/")) { + baseUrl = baseUrl.substring(0, baseUrl.length() - 1); + } + + return baseUrl + getDeploymentPath(); + } + + /** + * + * @return the location (URL) of the TB hub + */ + protected String getHubURL() { + return "http://" + getHubHostname() + ":4444/wd/hub"; + } + + /** + * Used for building the hub URL to use for the test + * + * @return the host name of the TestBench hub + */ + protected abstract String getHubHostname(); + + /** + * 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 String getDeploymentPort(); + + /** + * Produces a collection of browsers to run the test on. This method is + * executed by the test runner when determining how many test methods to + * invoke and with what parameters. For each returned value a test method is + * 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 + */ + public Collection<DesiredCapabilities> getBrowsersToTest() { + return Collections.singleton(BrowserUtil.firefox(17)); + + } + + /** + * 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 + */ + protected WebElement vaadinElement(String vaadinLocator) { + return driver.findElement(vaadinLocator(vaadinLocator)); + } + + /** + * Find a Vaadin element based on its id given using Component.setId + * + * @param id + * The id to locate + * @return + */ + public WebElement vaadinElementById(String id) { + return driver.findElement(vaadinLocatorById(id)); + } + + /** + * Finds a {@link By} locator 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 + */ + public org.openqa.selenium.By vaadinLocator(String vaadinLocator) { + String base = getApplicationId(getDeploymentPath()); + + base += "::"; + return com.vaadin.testbench.By.vaadin(base + vaadinLocator); + } + + /** + * 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 + */ + public By vaadinLocatorById(String id) { + return vaadinLocator("PID_S" + id); + } + + /** + * Waits a short while 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) { + new WebDriverWait(driver, 10).until(condition); + } + + /** + * Waits a short while 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) { + new WebDriverWait(driver, 10).until(ExpectedConditions.not(condition)); + } + + /** + * 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 + */ + protected WebElement getLogRowElement(int rowNr) { + return vaadinElementById("Log_row_" + rowNr); + } + + /** + * 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 + */ + protected String getLogRow(int rowNr) { + return getLogRowElement(rowNr).getText(); + } + + /** + * Asserts that {@literal a} is >= {@literal b} + * + * @param message + * The message to include in the {@link AssertionError} + * @param a + * @param b + * @throws AssertionError + * If comparison fails + */ + public static final <T> void assertGreaterOrEqual(String message, + Comparable<T> a, T b) throws AssertionError { + if (a.compareTo(b) >= 0) { + return; + } + + throw new AssertionError(decorate(message, a, b)); + } + + /** + * Asserts that {@literal a} is > {@literal b} + * + * @param message + * The message to include in the {@link AssertionError} + * @param a + * @param b + * @throws AssertionError + * If comparison fails + */ + public static final <T> void assertGreater(String message, Comparable<T> a, + T b) throws AssertionError { + if (a.compareTo(b) > 0) { + return; + } + throw new AssertionError(decorate(message, a, b)); + } + + /** + * Asserts that {@literal a} is <= {@literal b} + * + * @param message + * The message to include in the {@link AssertionError} + * @param a + * @param b + * @throws AssertionError + * If comparison fails + */ + public static final <T> void assertLessThanOrEqual(String message, + Comparable<T> a, T b) throws AssertionError { + if (a.compareTo(b) <= 0) { + return; + } + + throw new AssertionError(decorate(message, a, b)); + } + + /** + * Asserts that {@literal a} is < {@literal b} + * + * @param message + * The message to include in the {@link AssertionError} + * @param a + * @param b + * @throws AssertionError + * If comparison fails + */ + public static final <T> void assertLessThan(String message, + Comparable<T> a, T b) throws AssertionError { + if (a.compareTo(b) < 0) { + return; + } + throw new AssertionError(decorate(message, a, b)); + } + + private static <T> String decorate(String message, Comparable<T> a, T b) { + message = message.replace("{0}", a.toString()); + message = message.replace("{1}", b.toString()); + return message; + } + + /** + * 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() { + Class<?> uiClass = getUIClass(); + if (uiClass != null) { + return getDeploymentPath(uiClass); + } + throw new IllegalArgumentException("Unable to determine path for " + + getClass().getCanonicalName()); + + } + + /** + * 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() { + try { + // Convention: SomeUITest uses the SomeUI UI class + String uiClassName = getClass().getName().replaceFirst("Test$", ""); + Class<?> cls = Class.forName(uiClassName); + if (isSupportedRunnerClass(cls)) { + return cls; + } + } catch (Exception e) { + } + Class<?> enclosingClass = getClass().getEnclosingClass(); + if (enclosingClass != null) { + if (UI.class.isAssignableFrom(enclosingClass)) { + Logger.getLogger(getClass().getName()) + .severe("Test is an static inner class to the UI. This will no longer be supported in the future. The test should be named UIClassTest and reside in the same package as the UI"); + return enclosingClass; + } + } + throw new RuntimeException( + "Could not determine UI class. Ensure the test is named UIClassTest and is in the same package as the UIClass"); + } + + /** + * @return true if the given class is supported by ApplicationServletRunner + */ + @SuppressWarnings("deprecation") + private boolean isSupportedRunnerClass(Class<?> cls) { + if (UI.class.isAssignableFrom(cls)) { + return true; + } + if (UIProvider.class.isAssignableFrom(cls)) { + return true; + } + if (LegacyApplication.class.isAssignableFrom(cls)) { + return true; + } + + return false; + } + + /** + * 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() { + return debug; + } + + /** + * 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 + */ + protected final void setDebug(boolean debug) { + this.debug = debug; + } + + /** + * 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() { + return push; + } + + /** + * 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 + */ + protected final void setPush(boolean push) { + this.push = push; + } + + /** + * 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 + * @param debug + * true if /run-push should be used instead of /run + * @return The path to the given UI class + */ + private String getDeploymentPath(Class<?> uiClass) { + String runPath = "/run"; + if (isPush()) { + runPath = "/run-push"; + } + + if (UI.class.isAssignableFrom(uiClass)) { + return runPath + "/" + uiClass.getCanonicalName() + + (isDebug() ? "?debug" : ""); + } else if (LegacyApplication.class.isAssignableFrom(uiClass)) { + return runPath + "/" + uiClass.getCanonicalName() + + "?restartApplication" + (isDebug() ? "&debug" : ""); + } else { + throw new IllegalArgumentException( + "Unable to determine path for enclosing class " + + uiClass.getCanonicalName()); + } + } + + /** + * 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() { + return "http://" + getDeploymentHostname() + ":" + getDeploymentPort(); + } + + /** + * 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 + * @return The application ID string used in Vaadin locators + */ + private String getApplicationId(String pathWithQueryParameters) { + // Remove any possible URL parameters + String pathWithoutQueryParameters = pathWithQueryParameters.replaceAll( + "\\?.*", ""); + if ("".equals(pathWithoutQueryParameters)) { + return "ROOT"; + } + + // Retain only a-z and numbers + return pathWithoutQueryParameters.replaceAll("[^a-zA-Z0-9]", ""); + } + + /** + * Helper method for sleeping X ms in a test. Catches and ignores + * InterruptedExceptions + * + * @param timeoutMillis + * Number of ms to wait + */ + protected void sleep(int timeoutMillis) { + try { + Thread.sleep(timeoutMillis); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + + /** + * 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.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; + } + + /** + * 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 BrowserType.IE.equals(capabilities.getBrowserName()) + && "8".equals(capabilities.getVersion()); + } + + /** + * 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) { + String browserName = capabilities.getBrowserName(); + + if (BrowserType.IE.equals(browserName)) { + return "InternetExplorer"; + } else if (BrowserType.FIREFOX.equals(browserName)) { + return "Firefox"; + } else if (BrowserType.CHROME.equals(browserName)) { + return "Chrome"; + } else if (BrowserType.SAFARI.equals(browserName)) { + return "Safari"; + } else if (BrowserType.OPERA.equals(browserName)) { + return "Opera"; + } + + return browserName; + } + + /** + * 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 + */ + public void onUncaughtException(Throwable t) { + // Do nothing by default + + } +} diff --git a/uitest/src/com/vaadin/tests/tb3/AllTB3Tests.java b/uitest/src/com/vaadin/tests/tb3/AllTB3Tests.java new file mode 100644 index 0000000000..bd9027bec2 --- /dev/null +++ b/uitest/src/com/vaadin/tests/tb3/AllTB3Tests.java @@ -0,0 +1,42 @@ +/* + * 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.tb3; + +import org.junit.runner.RunWith; +import org.junit.runners.model.InitializationError; + +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) +public class AllTB3Tests { + + public static class AllTB3TestsSuite extends TB3TestSuite { + + public AllTB3TestsSuite(Class<?> klass) throws InitializationError { + super(klass, AbstractTB3Test.class, "com.vaadin.tests", + new String[] { "com.vaadin.tests.integration" }); + } + + } + +} diff --git a/uitest/src/com/vaadin/tests/tb3/MultiBrowserTest.java b/uitest/src/com/vaadin/tests/tb3/MultiBrowserTest.java new file mode 100644 index 0000000000..3553954ec0 --- /dev/null +++ b/uitest/src/com/vaadin/tests/tb3/MultiBrowserTest.java @@ -0,0 +1,69 @@ +/* + * 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.tb3; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.openqa.selenium.remote.DesiredCapabilities; + +/** + * 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 { + + static List<DesiredCapabilities> allBrowsers = new ArrayList<DesiredCapabilities>(); + static { + allBrowsers.add(BrowserUtil.ie(8)); + allBrowsers.add(BrowserUtil.ie(9)); + allBrowsers.add(BrowserUtil.ie(10)); + allBrowsers.add(BrowserUtil.ie(11)); + allBrowsers.add(BrowserUtil.firefox(24)); + // Uncomment once we have the capability to run on Safari 6 + // allBrowsers.add(safari(6)); + allBrowsers.add(BrowserUtil.chrome(29)); + allBrowsers.add(BrowserUtil.opera(12)); + + } + + /** + * @return all supported browsers which are actively tested + */ + public static List<DesiredCapabilities> getAllBrowsers() { + return allBrowsers; + } + + @Override + public Collection<DesiredCapabilities> getBrowsersToTest() { + return allBrowsers; + } + +} diff --git a/uitest/src/com/vaadin/tests/tb3/ParallelScheduler.java b/uitest/src/com/vaadin/tests/tb3/ParallelScheduler.java new file mode 100644 index 0000000000..912d7d010e --- /dev/null +++ b/uitest/src/com/vaadin/tests/tb3/ParallelScheduler.java @@ -0,0 +1,69 @@ +/* + * 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.tb3; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; + +import org.junit.runners.model.RunnerScheduler; + +/** + * JUnit scheduler capable of running multiple tets in parallel. Each test is + * run in its own thread. Uses an {@link ExecutorService} to manage the threads. + * + * @author Vaadin Ltd + */ +public class ParallelScheduler implements RunnerScheduler { + private final List<Future<Object>> fResults = new ArrayList<Future<Object>>(); + private ExecutorService fService; + + /** + * Creates a parallel scheduler which will use the given executor service + * when submitting test jobs. + * + * @param service + * The service to use for tests + */ + public ParallelScheduler(ExecutorService service) { + fService = service; + } + + @Override + public void schedule(final Runnable childStatement) { + fResults.add(fService.submit(new Callable<Object>() { + @Override + public Object call() throws Exception { + childStatement.run(); + return null; + } + })); + } + + @Override + public void finished() { + for (Future<Object> each : fResults) { + try { + each.get(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } +} diff --git a/uitest/src/com/vaadin/tests/tb3/PrivateTB3Configuration.java b/uitest/src/com/vaadin/tests/tb3/PrivateTB3Configuration.java new file mode 100644 index 0000000000..09615f0b2e --- /dev/null +++ b/uitest/src/com/vaadin/tests/tb3/PrivateTB3Configuration.java @@ -0,0 +1,135 @@ +/* + * 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 + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.vaadin.tests.tb3; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.util.Enumeration; +import java.util.Properties; + +/** + * 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 + */ +public abstract class PrivateTB3Configuration extends ScreenshotTB3Test { + private static final String HOSTNAME_PROPERTY = "com.vaadin.testbench.deployment.hostname"; + private static final String PORT_PROPERTY = "com.vaadin.testbench.deployment.port"; + private final Properties properties = new Properties(); + + public PrivateTB3Configuration() { + File file = new File("work", "eclipse-run-selected-test.properties"); + if (file.exists()) { + try { + properties.load(new FileInputStream(file)); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + } + + private String getProperty(String name) { + String property = properties.getProperty(name); + if (property == null) { + property = System.getProperty(name); + } + + return property; + } + + @Override + protected String getScreenshotDirectory() { + String screenshotDirectory = getProperty("com.vaadin.testbench.screenshot.directory"); + if (screenshotDirectory == null) { + throw new RuntimeException( + "No screenshot directory defined. Use -Dcom.vaadin.testbench.screenshot.directory=<path>"); + } + return screenshotDirectory; + } + + @Override + protected String getHubHostname() { + return "tb3-hub.intra.itmill.com"; + } + + @Override + protected String getDeploymentHostname() { + String hostName = getProperty(HOSTNAME_PROPERTY); + + if (hostName == null || "".equals(hostName)) { + hostName = findAutoHostname(); + } + + return hostName; + } + + @Override + protected String getDeploymentPort() { + String port = getProperty(PORT_PROPERTY); + + if (port == null || "".equals(port)) { + port = "8888"; + } + + return port; + } + + /** + * 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 + */ + private String findAutoHostname() { + try { + Enumeration<NetworkInterface> interfaces = NetworkInterface + .getNetworkInterfaces(); + while (interfaces.hasMoreElements()) { + NetworkInterface current = interfaces.nextElement(); + if (!current.isUp() || current.isLoopback() + || current.isVirtual()) { + continue; + } + Enumeration<InetAddress> addresses = current.getInetAddresses(); + while (addresses.hasMoreElements()) { + InetAddress current_addr = addresses.nextElement(); + if (current_addr.isLoopbackAddress()) { + continue; + } + String hostAddress = current_addr.getHostAddress(); + if (hostAddress.startsWith("192.168.")) { + return hostAddress; + } + } + } + } catch (SocketException e) { + throw new RuntimeException("Could not enumerate "); + } + + throw new RuntimeException( + "No compatible (192.168.*) ip address found."); + } + +} diff --git a/uitest/src/com/vaadin/tests/tb3/ScreenshotTB3Test.java b/uitest/src/com/vaadin/tests/tb3/ScreenshotTB3Test.java new file mode 100644 index 0000000000..cbdae1a6c1 --- /dev/null +++ b/uitest/src/com/vaadin/tests/tb3/ScreenshotTB3Test.java @@ -0,0 +1,400 @@ +/* + * 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.tb3; + +import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileFilter; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import javax.imageio.ImageIO; + +import org.junit.After; +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; + +import com.vaadin.testbench.Parameters; +import com.vaadin.testbench.commands.TestBenchCommands; + +/** + * Base class which provides functionality for tests which use the automatic + * screenshot comparison function. + * + * @author Vaadin Ltd + */ +public abstract class ScreenshotTB3Test extends AbstractTB3Test { + + private String screenshotBaseName; + + @Rule + public TestRule watcher = new TestWatcher() { + + @Override + protected void starting(org.junit.runner.Description description) { + Class<?> testClass = description.getTestClass(); + // Runner adds [BrowserName] which we do not want to use in the + // screenshot name + String testMethod = description.getMethodName(); + testMethod = testMethod.replaceAll("\\[.*\\]", ""); + + 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']"); + } + } + }; + + /** + * Contains a list of screenshot identifiers for which + * {@link #compareScreen(String)} has failed during the test + */ + private List<String> screenshotFailures = new ArrayList<String>(); + + /** + * Defines TestBench screen comparison parameters before each test run + */ + @Before + public void setupScreenComparisonParameters() { + Parameters.setScreenshotErrorDirectory(getScreenshotErrorDirectory()); + Parameters + .setScreenshotReferenceDirectory(getScreenshotReferenceDirectory()); + } + + /** + * 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 + */ + protected void compareScreen(String identifier) throws IOException { + if (identifier == null || identifier.isEmpty()) { + throw new IllegalArgumentException("Empty identifier not supported"); + } + + File mainReference = getScreenshotReferenceFile(identifier); + + List<File> alternativeFiles = findReferenceAlternatives(mainReference); + List<File> failedReferenceAlternatives = new ArrayList<File>(); + + for (File file : alternativeFiles) { + if (testBench(driver).compareScreen(file)) { + break; + } else { + failedReferenceAlternatives.add(file); + } + } + + File referenceToKeep = null; + if (failedReferenceAlternatives.size() != alternativeFiles.size()) { + // 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; + } + + // Remove all PNG/HTML files we no longer need (failed alternative + // references or all error files (PNG/HTML) if comparison succeeded) + for (File failedAlternative : failedReferenceAlternatives) { + File failurePng = getErrorFileFromReference(failedAlternative); + if (failedAlternative != referenceToKeep) { + // Delete png + HTML + String htmlFileName = failurePng.getName().replace(".png", + ".html"); + File failureHtml = new File(failurePng.getParentFile(), + htmlFileName); + + failurePng.delete(); + failureHtml.delete(); + } + } + } + + /** + * + * @param referenceFile + * The reference image file (in the directory defined by + * {@link #getScreenshotReferenceDirectory()}) + * @return the file name of the file generated in the directory defined by + * {@link #getScreenshotErrorDirectory()} if comparison with the + * given reference image fails. + */ + private File getErrorFileFromReference(File referenceFile) { + return new File(referenceFile.getAbsolutePath().replace( + getScreenshotReferenceDirectory(), + getScreenshotErrorDirectory())); + } + + /** + * 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 + */ + private List<File> findReferenceAlternatives(File reference) { + List<File> files = new ArrayList<File>(); + files.add(reference); + + File screenshotDir = reference.getParentFile(); + String name = reference.getName(); + // Remove ".png" + String nameBase = name.substring(0, name.length() - 4); + for (int i = 1;; i++) { + File file = new File(screenshotDir, nameBase + "_" + i + ".png"); + if (file.exists()) { + files.add(file); + } else { + break; + } + } + + return files; + } + + /** + * @param testName + * @return the reference file name to use for the given browser, as + * described by {@literal capabilities}, and identifier + */ + private File getScreenshotReferenceFile(String identifier) { + DesiredCapabilities capabilities = getDesiredCapabilities(); + + String originalName = getScreenshotReferenceName(identifier); + File exactVersionFile = new File(originalName); + if (exactVersionFile.exists()) { + return exactVersionFile; + } + + String browserVersion = capabilities.getVersion(); + + if (browserVersion.matches("\\d+")) { + for (int version = Integer.parseInt(browserVersion); version > 0; version--) { + String fileName = getScreenshotReferenceName(identifier, + version); + File oldVersionFile = new File(fileName); + if (oldVersionFile.exists()) { + return oldVersionFile; + } + } + } + + return exactVersionFile; + } + + /** + * @return the base directory of 'reference' and 'errors' screenshots + */ + protected abstract String getScreenshotDirectory(); + + /** + * @return the directory where reference images are stored (the 'reference' + * folder inside the screenshot directory) + */ + private String getScreenshotReferenceDirectory() { + return getScreenshotDirectory() + "/reference"; + } + + /** + * @return the directory where comparison error images should be created + * (the 'errors' folder inside the screenshot directory) + */ + private String getScreenshotErrorDirectory() { + return getScreenshotDirectory() + "/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 + */ + @After + public void checkCompareFailures() throws IOException { + if (!screenshotFailures.isEmpty()) { + throw new IOException( + "The following screenshots did not match the reference: " + + screenshotFailures.toString()); + } + + } + + /* + * (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 the base name used for screenshots. This is the first part of the + * screenshot file name, typically created as "testclass-testmethod" + */ + public String getScreenshotBaseName() { + return screenshotBaseName; + } + + /** + * Returns the name of the reference file based on the given parameters. + * + * @param testName + * @param capabilities + * @param identifier + * @return the full path of the reference + */ + private String getScreenshotReferenceName(String identifier) { + return getScreenshotReferenceName(identifier, null); + } + + /** + * 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 + * @return the full path of the reference + */ + private String getScreenshotReferenceName(String identifier, + Integer versionOverride) { + String uniqueBrowserIdentifier; + if (versionOverride == null) { + uniqueBrowserIdentifier = BrowserUtil + .getUniqueIdentifier(getDesiredCapabilities()); + } else { + uniqueBrowserIdentifier = BrowserUtil.getUniqueIdentifier( + getDesiredCapabilities(), "" + versionOverride); + } + + // WindowMaximizeRestoreTest_Windows_InternetExplorer_8_window-1-moved-maximized-restored.png + return getScreenshotReferenceDirectory() + "/" + + getScreenshotBaseName() + "_" + uniqueBrowserIdentifier + "_" + + identifier + ".png"; + } + + /** + * 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 + * {@link #getDesiredCapabilities()}) and can safely be removed before + * running this test. + */ + private String getScreenshotErrorBaseName() { + return getScreenshotReferenceName("dummy", null).replace( + getScreenshotReferenceDirectory(), + getScreenshotErrorDirectory()).replace("_dummy.png", ""); + } + + /** + * Removes any old screenshots related to this test from the errors + * directory before running the test + */ + @Before + public void cleanErrorDirectory() { + // Remove any screenshots for this test from the error directory + // before running it. Leave unrelated files as-is + File errorDirectory = new File(getScreenshotErrorDirectory()); + + // Create errors directory if it does not exist + if (!errorDirectory.exists()) { + errorDirectory.mkdirs(); + } + + final String errorBase = getScreenshotErrorBaseName() + .replace("\\", "/"); + File[] files = errorDirectory.listFiles(new FileFilter() { + + @Override + public boolean accept(File pathname) { + String thisFile = pathname.getAbsolutePath().replace("\\", "/"); + if (thisFile.startsWith(errorBase)) { + return true; + } + return false; + } + }); + for (File f : files) { + f.delete(); + } + } +} diff --git a/uitest/src/com/vaadin/tests/tb3/ServletIntegrationTests.java b/uitest/src/com/vaadin/tests/tb3/ServletIntegrationTests.java new file mode 100644 index 0000000000..c511b99e6e --- /dev/null +++ b/uitest/src/com/vaadin/tests/tb3/ServletIntegrationTests.java @@ -0,0 +1,35 @@ +/* + * 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.tb3; + +import org.junit.runner.RunWith; +import org.junit.runners.model.InitializationError; + +import com.vaadin.tests.integration.AbstractServletIntegrationTest; +import com.vaadin.tests.tb3.ServletIntegrationTests.ServletIntegrationTestSuite; + +@RunWith(ServletIntegrationTestSuite.class) +public class ServletIntegrationTests { + + public static class ServletIntegrationTestSuite extends TB3TestSuite { + public ServletIntegrationTestSuite(Class<?> klass) + throws InitializationError { + super(klass, AbstractServletIntegrationTest.class, + "com.vaadin.tests.integration", new String[] {}); + } + } +} diff --git a/uitest/src/com/vaadin/tests/tb3/SimpleMultiBrowserTest.java b/uitest/src/com/vaadin/tests/tb3/SimpleMultiBrowserTest.java new file mode 100644 index 0000000000..aeeed4198c --- /dev/null +++ b/uitest/src/com/vaadin/tests/tb3/SimpleMultiBrowserTest.java @@ -0,0 +1,50 @@ +/* + * 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.tb3; + +import org.junit.Test; + +/** + * A simple version of {@link MultiBrowserTest} which allows only one test + * method ({@link #test()}). Uses only the enclosing class name as test + * identifier (i.e. excludes "-test"). + * + * This class is only provided as a helper for converting existing TB2 tests + * without renaming all screenshots. All new TB3+ tests should extend + * {@link MultiBrowserTest} directly instead of this. + * + * @author Vaadin Ltd + */ +@Deprecated +public abstract class SimpleMultiBrowserTest extends MultiBrowserTest { + + @Test + public abstract void test() throws Exception; + + /* + * (non-Javadoc) + * + * @see com.vaadin.tests.tb3.ScreenshotTB3Test#getScreenshotBaseName() + */ + @Override + public String getScreenshotBaseName() { + return super.getScreenshotBaseName().replaceFirst("-test$", ""); + } +} diff --git a/uitest/src/com/vaadin/tests/tb3/TB3Runner.java b/uitest/src/com/vaadin/tests/tb3/TB3Runner.java new file mode 100644 index 0000000000..b612b17caa --- /dev/null +++ b/uitest/src/com/vaadin/tests/tb3/TB3Runner.java @@ -0,0 +1,154 @@ +/* + * 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.tb3; + +import java.lang.reflect.Method; +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import org.junit.Test; +import org.junit.runners.BlockJUnit4ClassRunner; +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 com.vaadin.tests.tb3.AbstractTB3Test.BrowserUtil; + +/** + * This runner is loosely based on FactoryTestRunner by Ted Young + * (http://tedyoung.me/2011/01/23/junit-runtime-tests-custom-runners/). The + * generated test names give information about the parameters used (unlike + * {@link Parameterized}). + * + * @since 7.1 + */ +public class TB3Runner extends BlockJUnit4ClassRunner { + + /** + * This is the total limit of actual JUnit test instances run in parallel + */ + private static final int MAX_CONCURRENT_TESTS = 50; + + /** + * 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 = Executors + .newFixedThreadPool(MAX_CONCURRENT_TESTS); + + 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 = (AbstractTB3Test) getTestClass() + .getOnlyConstructor().newInstance(); + for (DesiredCapabilities capabilities : testClassInstance + .getBrowsersToTest()) { + + // Find any methods marked with @Test. + for (FrameworkMethod m : getTestClass().getAnnotatedMethods( + Test.class)) { + tests.add(new TB3Method(m.getMethod(), capabilities)); + } + } + } catch (Exception e) { + throw new RuntimeException("Error retrieving browsers to run on", e); + } + + return tests; + } + + /* + * (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; + + public TB3Method(Method method, DesiredCapabilities capabilities) { + super(method); + this.capabilities = capabilities; + } + + @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(), + BrowserUtil.getUniqueIdentifier(capabilities)); + } + + } +} diff --git a/uitest/src/com/vaadin/tests/tb3/TB3TestSuite.java b/uitest/src/com/vaadin/tests/tb3/TB3TestSuite.java new file mode 100644 index 0000000000..e1c8edfd60 --- /dev/null +++ b/uitest/src/com/vaadin/tests/tb3/TB3TestSuite.java @@ -0,0 +1,238 @@ +/* + * 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.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; + +/** + * 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 TB3TestSuite(Class<?> klass, + Class<? extends AbstractTB3Test> baseClass, String basePackage, + String[] ignorePackages) throws InitializationError { + super(klass, findTests(baseClass, basePackage, ignorePackages)); + setScheduler(new ParallelScheduler(service)); + } + + /** + * 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( + 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 (!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 + } + + } + +}
\ No newline at end of file diff --git a/uitest/src/com/vaadin/tests/tb3/WebsocketTest.java b/uitest/src/com/vaadin/tests/tb3/WebsocketTest.java new file mode 100644 index 0000000000..5c6ea329f5 --- /dev/null +++ b/uitest/src/com/vaadin/tests/tb3/WebsocketTest.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.tb3; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import org.openqa.selenium.remote.DesiredCapabilities; + +/** + * A {@link MultiBrowserTest} which restricts the tests to the browsers which + * support websocket + * + * @author Vaadin Ltd + */ +public abstract class WebsocketTest extends PrivateTB3Configuration { + private static List<DesiredCapabilities> websocketBrowsers = new ArrayList<DesiredCapabilities>(); + static { + websocketBrowsers.addAll(MultiBrowserTest.getAllBrowsers()); + websocketBrowsers.remove(BrowserUtil.ie(8)); + websocketBrowsers.remove(BrowserUtil.ie(9)); + } + + /** + * @return All supported browsers which are actively tested and support + * websockets + */ + public static Collection<DesiredCapabilities> getWebsocketBrowsers() { + return Collections.unmodifiableCollection(websocketBrowsers); + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.tests.tb3.AbstractTB3Test#getBrowserToRunOn() + */ + @Override + public Collection<DesiredCapabilities> getBrowsersToTest() { + return getWebsocketBrowsers(); + } +} diff --git a/uitest/tb3test.xml b/uitest/tb3test.xml new file mode 100644 index 0000000000..de69e0ebe6 --- /dev/null +++ b/uitest/tb3test.xml @@ -0,0 +1,42 @@ +<?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}" /> + + <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" 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" /> + + <!-- 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> + + </target> + +</project> diff --git a/uitest/test.xml b/uitest/test.xml index 3baccb4117..c534d676b9 100644 --- a/uitest/test.xml +++ b/uitest/test.xml @@ -83,7 +83,7 @@ <fail unless="com.vaadin.testbench.deployment.url" message="The 'com.vaadin.testbench.deployment.url' property must be defined." /> </target> - <target name="run-tests" depends="compile-tests"> + <target name="run-tb2-tests" depends="check-parameters,compile-tests"> <fileset dir="${test-output-dir}" id="tests-fileset"> <include name="**/**.java" /> </fileset> @@ -134,8 +134,18 @@ </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"> @@ -161,12 +171,10 @@ <!-- ================================================================== --> <!-- The default target. --> - <target name="run-and-clean-up" depends="check-parameters,remove-error-screens,run-tests" /> - + <target name="run-and-clean-up" depends="check-parameters,remove-error-screens,run-tb2-tests" /> - <!-- Starts the server and runs all TestBench tests --> - <target name="test-package"> - <fail unless="war.file" message="No 'war.file' parameter given." /> + <!-- Runs all TestBench 2 tests --> + <target name="tb2-tests"> <property name="test-output-dir" location="${test.xml.dir}/result/testbench-junit-classes" /> <property name="retries" value="2" /> @@ -177,15 +185,6 @@ <property name="com.vaadin.testbench.screenshot.block.error" value="0.025" /> <property name="com.vaadin.testbench.debug" value="false" /> - <parallel> - <daemons> - <ant antfile="${test.xml.dir}/vaadin-server.xml" inheritall="true" inheritrefs="true" target="deploy-and-start" /> - </daemons> - <sequential> - <ant antfile="${test.xml.dir}/vaadin-server.xml" target="wait-for-startup" /> - <antcall inheritall="true" inheritrefs="true" target="run-and-clean-up" /> - <echo message="All TestBench tests have been run" /> - </sequential> - </parallel> + <antcall inheritall="true" inheritrefs="true" target="run-tb2-tests" /> </target> </project> |