├── .gitignore ├── LICENSE.txt ├── README.md ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── src └── main └── java └── de └── otto └── wickettester ├── ComponentMatcher.java ├── ComponentMatchers.java ├── EnabledComponentMatcher.java ├── EnhancedWicketTester.java ├── HavingChildComponentMatcher.java ├── HavingDirectChildComponentMatcher.java ├── HavingDirectParentComponentMatcher.java ├── HavingSiblingComponentMatcher.java ├── ModelObjectComponentMatcher.java ├── NegatingComponentMatcher.java ├── TypeComponentMatcher.java ├── VisibleComponentMatcher.java └── WicketIdComponentMatcher.java /.gitignore: -------------------------------------------------------------------------------- 1 | .classpath 2 | .gradle 3 | .project 4 | .settings 5 | .idea 6 | bin 7 | build 8 | *.iml 9 | *.ipr 10 | *.iws 11 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Enhanced WicketTester 2 | 3 | ## Description 4 | 5 | The WicketTester is a helper class to ease unit testing of wicket component and pages. There is no need for a servlet container, because it uses a mocked servlet context and a mocked wicket application. In the following it is possible to test the rendered page and the contained components. This is mostly done by selecting components with their wicket path as string. As you can image this is a common error on refactoring components on pages which results in changed wicket paths. 6 | 7 | The following example shows how the WicketTester renders a test page and asserts that a bookmarkable link is present to that page. 8 | 9 | ```java 10 | //given 11 | final WicketTester tester = new WicketTester(); 12 | tester.startPage(new TestPage()); 13 | 14 | //when 15 | final Component link = tester.getComponentFromLastRenderedPage("some:wicket:path"); 16 | 17 | //then 18 | assertThat(link, is(not(nullValue()))); 19 | ``` 20 | 21 | Now this example can be rewritten selecting the component using the component matchers. The Enhanced WicketTester uses a 22 | component matcher construct for several functions you are already used to call with a wicket-path. 23 | 24 | ```java 25 | //given 26 | final EnhancedWicketTester tester = new EnhancedWicketTester(); 27 | tester.startPage(new TestPage()); 28 | 29 | //when 30 | final BookmarkablePageLink link = tester.getChildMatching( 31 | ComponentMatchers.type(BookmarkablePageLink.class)); 32 | 33 | //then 34 | assertThat(link, is(not(nullValue()))); 35 | ``` 36 | 37 | ## Features 38 | 39 | - select components without the need of the wicket path 40 | - base wickettester functionality using component matchers 41 | 42 | ## Usage 43 | 44 | Selectors for components can be formed using the ComponentMatcherBuilder which uses a builder pattern: 45 | 46 | ```java 47 | ComponentMatchers.type(BookmarkablePageLink.class).wicketId("link").visible(); 48 | ``` 49 | 50 | Selectors can be combined together: 51 | 52 | ```java 53 | ComponentMatchers.type(BookmarkablePageLink.class).wicketId("link").visible() 54 | .havingChild(ComponentMatchers.type(BookmarkablePageLink.class)); 55 | ``` 56 | 57 | ### Selectors 58 | 59 | In the following you will find a list of all selectors possible: 60 | 61 | ```java 62 | ComponentMatcherBuilder type(final Class componentClass) 63 | ``` 64 | 65 | ```java 66 | ComponentMatcherBuilder wicketId(final String wicketId) 67 | ``` 68 | 69 | ```java 70 | ComponentMatcherBuilder visible() 71 | ``` 72 | 73 | ```java 74 | ComponentMatcherBuilder enabled() 75 | ``` 76 | 77 | ```java 78 | ComponentMatcherBuilder type(final Class componentClass) 79 | ``` 80 | 81 | ```java 82 | ComponentMatcherBuilder not(final ComponentMatcherBuilder builder) 83 | ``` 84 | 85 | ```java 86 | ComponentMatcherBuilder modelObject(final Object modelObject) 87 | ``` 88 | 89 | ```java 90 | ComponentMatcherBuilder havingChild(final ComponentMatcherBuilder builder) 91 | ``` 92 | 93 | ```java 94 | ComponentMatcherBuilder havingDirectChild(final ComponentMatcherBuilder builder) 95 | ``` 96 | 97 | ```java 98 | ComponentMatcherBuilder havingSibling(final ComponentMatcherBuilder builder) 99 | ``` 100 | 101 | ```java 102 | ComponentMatcherBuilder havingDirectParent(final ComponentMatcherBuilder builder) 103 | ``` 104 | 105 | ### WicketTester functions 106 | 107 | #### Select a list of children 108 | 109 | ```java 110 | List getChildrenMatching(final MarkupContainer root, final ComponentMatcherBuilder builder) 111 | ``` 112 | 113 | ```java 114 | List getChildrenMatching(final ComponentMatcherBuilder builder, 115 | final ComponentMatcherBuilder... parentBuilders) 116 | ``` 117 | 118 | ```java 119 | List getChildrenMatching(final ComponentMatcherBuilder builder) 120 | ``` 121 | 122 | #### Select a single child 123 | 124 | ```java 125 | T getChildMatching(final MarkupContainer root, final ComponentMatcherBuilder builder, 126 | final ComponentMatcherBuilder... parentBuilders) 127 | ``` 128 | 129 | ```java 130 | T getChildMatching(final MarkupContainer root, final ComponentMatcherBuilder builder) 131 | ``` 132 | 133 | ```java 134 | T getChildMatching(final ComponentMatcherBuilder builder, 135 | final ComponentMatcherBuilder... parentBuilders) 136 | ``` 137 | 138 | ```java 139 | T getChildMatching(final ComponentMatcherBuilder builder) 140 | ``` 141 | 142 | #### Select first child of a list of children 143 | 144 | ```java 145 | T getFirstChildMatching(final MarkupContainer root, final ComponentMatcherBuilder builder, 146 | final ComponentMatcherBuilder... parentBuilders) 147 | ``` 148 | 149 | ```java 150 | T getFirstChildMatching(final ComponentMatcherBuilder builder, 151 | final ComponentMatcherBuilder... parentBuilders) 152 | ``` 153 | 154 | ```java 155 | T getFirstChildMatching(final MarkupContainer root, final ComponentMatcherBuilder builder) 156 | ``` 157 | 158 | ```java 159 | T getFirstChildMatching(final ComponentMatcherBuilder builder) 160 | ``` 161 | 162 | #### Get the wicket-path 163 | 164 | ```java 165 | String getPathRelativeToRoot(final Component root, final Component component) 166 | ``` 167 | 168 | ```java 169 | String getPathRelativeToPage(final Component component) 170 | ``` 171 | 172 | #### Create a TagTester for attribute testing 173 | 174 | ```java 175 | TagTester getTagTesterByComponent(final Component component) 176 | ``` 177 | 178 | ```java 179 | TagTester getTagTesterByComponentMatcher(final ComponentMatcherBuilder builder, 180 | final ComponentMatcherBuilder... parentBuilders) 181 | ``` 182 | 183 | #### Create a FormTester 184 | 185 | ```java 186 | FormTester newFormTester(final Form form) 187 | ``` 188 | 189 | ```java 190 | FormTester newFormTester(final ComponentMatcherBuilder builder, 191 | final ComponentMatcherBuilder... parentBuilders) 192 | ``` 193 | 194 | #### Execution 195 | 196 | ```java 197 | void clickLink(final ComponentMatcherBuilder builder, 198 | final ComponentMatcherBuilder... parentBuilders) 199 | ``` 200 | 201 | ```java 202 | void executeAjaxEvent(final String event, 203 | final ComponentMatcherBuilder builder, 204 | final ComponentMatcherBuilder... parentBuilders) 205 | ``` 206 | 207 | #### Assertion helpers 208 | 209 | ```java 210 | void assertModelValue(final Object expectedModelObject, 211 | final ComponentMatcherBuilder builder, 212 | final ComponentMatcherBuilder... parentBuilders) 213 | ``` 214 | 215 | ```java 216 | void assertVisible(final Component component) 217 | ``` 218 | 219 | ```java 220 | void assertVisible(final ComponentMatcherBuilder builder, 221 | final ComponentMatcherBuilder... parentBuilders) 222 | ``` 223 | 224 | ```java 225 | void assertInvisible(final Label component) 226 | ``` 227 | 228 | ```java 229 | void assertFeedback(final ComponentMatcherBuilder builder, 230 | final String... feedback) 231 | ``` 232 | 233 | ## Gradle, Maven 234 | 235 | You can find all releases in Maven Central and in the public Sonatype repository: 236 | 237 | https://oss.sonatype.org/content/repositories/releases 238 | 239 | The current release is 0.2: 240 | 241 | * de.otto:enhanced-wickettester:0.2 242 | 243 | For development usage you should use the snapshot instead: 244 | 245 | https://oss.sonatype.org/content/repositories/snapshots 246 | 247 | The current snapshot-release is 0.3-SNAPSHOT: 248 | 249 | * de.otto:enhanced-wickettester:0.3-SNAPSHOT 250 | 251 | ## License 252 | 253 | Apache 2 254 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'eclipse' 4 | id 'idea' 5 | id 'maven' 6 | id 'signing' 7 | id 'com.github.ben-manes.versions' version '0.20.0' 8 | } 9 | 10 | version = '0.3-SNAPSHOT' 11 | 12 | sourceCompatibility = 1.8 13 | 14 | group = 'de.otto' 15 | 16 | repositories { 17 | mavenCentral() 18 | 19 | maven { 20 | url 'https://oss.sonatype.org/content/repositories/snapshots/' 21 | } 22 | } 23 | 24 | dependencies { 25 | compile 'org.apache.wicket:wicket-core:7.0.0' 26 | compile 'org.apache.commons:commons-lang3:3.7' 27 | compile 'org.hamcrest:hamcrest-all:1.3' 28 | compile 'org.testng:testng:6.14.3' 29 | } 30 | 31 | jar { 32 | manifest.attributes provider: 'gradle' 33 | } 34 | 35 | test { 36 | useTestNG() 37 | } 38 | 39 | task packageJavadoc(type: Jar, dependsOn: 'javadoc') { 40 | from javadoc.destinationDir 41 | classifier = 'javadoc' 42 | } 43 | 44 | task packageSources(type: Jar) { 45 | from sourceSets.main.allSource 46 | classifier = 'sources' 47 | } 48 | 49 | artifacts { 50 | archives packageJavadoc 51 | archives packageSources 52 | } 53 | 54 | signing { 55 | sign configurations.archives 56 | } 57 | 58 | uploadArchives { 59 | repositories { 60 | mavenDeployer { 61 | beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } 62 | 63 | repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2/") { 64 | authentication(userName: sonatypeUsername, password: sonatypePassword) 65 | } 66 | snapshotRepository(url: "https://oss.sonatype.org/content/repositories/snapshots/") { 67 | authentication(userName: sonatypeUsername, password: sonatypePassword) 68 | } 69 | pom.version = "0.2" 70 | pom.artifactId = "enhanced-wickettester" 71 | pom.groupId = "de.otto" 72 | pom.project { 73 | name 'enhanced-wickettester' 74 | packaging 'jar' 75 | description 'A enhanced wickettester library' 76 | url 'http://github.com/otto-de/enhanced-wickettester' 77 | 78 | scm { 79 | url 'scm:git@github.com:otto-de/enhanced-wickettester.git' 80 | connection 'scm:git@github.com:otto-de/enhanced-wickettester.git' 81 | developerConnection 'scm:git@github.com:otto-de/enhanced-wickettester.git' 82 | } 83 | 84 | licenses { 85 | license { 86 | name 'The Apache Software License, Version 2.0' 87 | url 'http://www.apache.org/licenses/LICENSE-2.0.txt' 88 | distribution 'repo' 89 | } 90 | } 91 | 92 | developers { 93 | developer { 94 | id 'sschmidt' 95 | name 'Stefan Schmidt' 96 | } 97 | } 98 | } 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | sonatypeUsername= 2 | sonatypePassword= 3 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otto-de/enhanced-wickettester/d684d040f77b5095ad72035d2a8aa85d1021934e/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Jul 11 16:56:41 CEST 2018 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.8.1-bin.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn ( ) { 37 | echo "$*" 38 | } 39 | 40 | die ( ) { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name="enhanced-wickettester" 2 | -------------------------------------------------------------------------------- /src/main/java/de/otto/wickettester/ComponentMatcher.java: -------------------------------------------------------------------------------- 1 | package de.otto.wickettester; 2 | 3 | import org.apache.wicket.Component; 4 | 5 | public interface ComponentMatcher { 6 | 7 | R match(T component); 8 | 9 | String criterionAsString(); 10 | } -------------------------------------------------------------------------------- /src/main/java/de/otto/wickettester/ComponentMatchers.java: -------------------------------------------------------------------------------- 1 | package de.otto.wickettester; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Arrays; 5 | import java.util.Collections; 6 | import java.util.LinkedList; 7 | import java.util.List; 8 | 9 | import org.apache.commons.lang3.StringUtils; 10 | import org.apache.wicket.Component; 11 | import org.apache.wicket.MarkupContainer; 12 | 13 | 14 | public class ComponentMatchers { 15 | 16 | public static class ComponentMatcherBuilder { 17 | 18 | static class CollectingComponentMatcher implements ComponentMatcher { 19 | 20 | private final List bucket; 21 | private final ComponentMatcher componentMatcher; 22 | 23 | public CollectingComponentMatcher(final ComponentMatcher matcher) { 24 | componentMatcher = matcher; 25 | bucket = new ArrayList(); 26 | } 27 | 28 | public void addToBucket(final R element) { 29 | bucket.add(element); 30 | } 31 | 32 | public List getBucket() { 33 | return bucket; 34 | } 35 | 36 | @Override 37 | public R match(final T component) { 38 | final R visited = componentMatcher.match(component); 39 | if (visited != null) { 40 | addToBucket(visited); 41 | } 42 | return null; 43 | } 44 | 45 | @Override 46 | public String criterionAsString() { 47 | return "a list of components"; 48 | } 49 | } 50 | 51 | private static class JoiningComponentMatcher implements ComponentMatcher { 52 | 53 | private final List> componentMatchers = new LinkedList>( 54 | Collections.singleton(new AllComponentMatcher())); 55 | 56 | public JoiningComponentMatcher(final ComponentMatcher... componentMatchers) { 57 | this.componentMatchers.addAll(Arrays.asList(componentMatchers)); 58 | } 59 | 60 | @Override 61 | public T match(final T component) { 62 | for (final ComponentMatcher visitor : componentMatchers) { 63 | final T visited = visitor.match(component); 64 | if (visited == null) { 65 | return null; 66 | } 67 | } 68 | return component; 69 | } 70 | 71 | @Override 72 | public String criterionAsString() { 73 | final List criteria = new LinkedList(); 74 | for (final ComponentMatcher visitor : componentMatchers) { 75 | criteria.add(visitor.criterionAsString()); 76 | } 77 | return StringUtils.join(criteria, " and "); 78 | } 79 | 80 | } 81 | 82 | private static class AllComponentMatcher implements ComponentMatcher { 83 | 84 | @Override 85 | public T match(final T component) { 86 | return component; 87 | } 88 | 89 | @Override 90 | public String criterionAsString() { 91 | return "being a component"; 92 | } 93 | } 94 | 95 | private final List> visitors = new LinkedList>(); 96 | 97 | public ComponentMatcherBuilder wicketId(final String wicketId) { 98 | this.visitors.add(new WicketIdComponentMatcher(wicketId)); 99 | return this; 100 | } 101 | 102 | public ComponentMatcherBuilder visible() { 103 | this.visitors.add(new VisibleComponentMatcher()); 104 | return this; 105 | } 106 | 107 | public ComponentMatcherBuilder enabled() { 108 | this.visitors.add(new EnabledComponentMatcher()); 109 | return this; 110 | } 111 | 112 | public ComponentMatcherBuilder type(final Class componentClass) { 113 | this.visitors.add(new TypeComponentMatcher(componentClass)); 114 | return this; 115 | } 116 | 117 | public ComponentMatcherBuilder visitedBy(final ComponentMatcher visitor) { 118 | this.visitors.add(visitor); 119 | return this; 120 | } 121 | 122 | public ComponentMatcherBuilder havingChild(final ComponentMatcherBuilder builder) { 123 | this.visitors.add(new HavingChildComponentMatcher(builder.build())); 124 | return this; 125 | } 126 | 127 | public ComponentMatcherBuilder havingDirectChild(final ComponentMatcherBuilder builder) { 128 | this.visitors.add(new HavingDirectChildComponentMatcher(builder.build())); 129 | return this; 130 | } 131 | 132 | public ComponentMatcherBuilder havingSibling(final ComponentMatcherBuilder builder) { 133 | this.visitors.add(new HavingSiblingComponentMatcher(builder.build())); 134 | return this; 135 | } 136 | 137 | public ComponentMatcherBuilder havingDirectParent( 138 | final ComponentMatcherBuilder builder) { 139 | this.visitors.add(new HavingDirectParentComponentMatcher(builder.build())); 140 | return this; 141 | } 142 | 143 | public ComponentMatcherBuilder modelObject(final Object modelObject) { 144 | this.visitors.add(new ModelObjectComponentMatcher(modelObject)); 145 | return this; 146 | } 147 | 148 | public ComponentMatcherBuilder not(final ComponentMatcherBuilder builder) { 149 | this.visitors.add(new NegatingComponentMatcher(builder.build())); 150 | return this; 151 | } 152 | 153 | @SuppressWarnings("unchecked") 154 | public ComponentMatcher build() { 155 | return new JoiningComponentMatcher(visitors.toArray(new ComponentMatcher[visitors.size()])); 156 | } 157 | 158 | public CollectingComponentMatcher buildCollecting() { 159 | return new CollectingComponentMatcher(build()); 160 | } 161 | 162 | public Object criteriaAsString() { 163 | final List criteria = new LinkedList(); 164 | for (final ComponentMatcher visitor : visitors) { 165 | criteria.add(visitor.criterionAsString()); 166 | } 167 | return StringUtils.join(criteria, " and "); 168 | } 169 | } 170 | 171 | public static ComponentMatcherBuilder builder() { 172 | return new ComponentMatcherBuilder(); 173 | } 174 | 175 | public static ComponentMatcherBuilder type(final Class componentClass) { 176 | return ComponentMatchers. builder().type(componentClass); 177 | } 178 | 179 | } 180 | -------------------------------------------------------------------------------- /src/main/java/de/otto/wickettester/EnabledComponentMatcher.java: -------------------------------------------------------------------------------- 1 | package de.otto.wickettester; 2 | 3 | import org.apache.wicket.Component; 4 | 5 | public class EnabledComponentMatcher implements ComponentMatcher { 6 | 7 | @Override 8 | public T match(final T component) { 9 | if (component.isEnabledInHierarchy()) { 10 | return component; 11 | } 12 | return null; 13 | } 14 | 15 | @Override 16 | public String criterionAsString() { 17 | return String.format("being enabled"); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/de/otto/wickettester/EnhancedWicketTester.java: -------------------------------------------------------------------------------- 1 | package de.otto.wickettester; 2 | 3 | import static org.hamcrest.MatcherAssert.assertThat; 4 | import static org.hamcrest.Matchers.equalTo; 5 | 6 | import java.io.Serializable; 7 | import java.util.Arrays; 8 | import java.util.LinkedList; 9 | import java.util.List; 10 | 11 | import org.apache.commons.lang3.ArrayUtils; 12 | import org.apache.commons.lang3.StringUtils; 13 | import org.apache.wicket.Component; 14 | import org.apache.wicket.MarkupContainer; 15 | import org.apache.wicket.markup.html.basic.Label; 16 | import org.apache.wicket.markup.html.form.Form; 17 | import org.apache.wicket.protocol.http.WebApplication; 18 | import org.apache.wicket.util.tester.FormTester; 19 | import org.apache.wicket.util.tester.TagTester; 20 | import org.apache.wicket.util.tester.WicketTester; 21 | import org.apache.wicket.util.visit.IVisit; 22 | import org.apache.wicket.util.visit.IVisitor; 23 | import org.apache.wicket.util.visit.Visits; 24 | import org.testng.Assert; 25 | 26 | import de.otto.wickettester.ComponentMatchers.ComponentMatcherBuilder; 27 | import de.otto.wickettester.ComponentMatchers.ComponentMatcherBuilder.CollectingComponentMatcher; 28 | 29 | public class EnhancedWicketTester extends WicketTester { 30 | 31 | public EnhancedWicketTester() { 32 | super(); 33 | } 34 | 35 | public EnhancedWicketTester(final WebApplication application) { 36 | super(application); 37 | } 38 | 39 | public static R visitComponentTree(final MarkupContainer root, 40 | final ComponentMatcher matcher) { 41 | final R res = Visits.visitChildren(root, new IVisitor() { 42 | 43 | @Override 44 | public void component(final T component, final IVisit visit) { 45 | final R result = matcher.match(component); 46 | if (result != null) { 47 | visit.stop(result); 48 | } 49 | } 50 | }); 51 | return res; 52 | } 53 | 54 | public List getChildrenMatching(final MarkupContainer root, final ComponentMatcherBuilder builder, 55 | final ComponentMatcherBuilder... parentBuilders) { 56 | final ComponentMatcherBuilder[] realParentBuilders = cleanup(parentBuilders); 57 | if (realParentBuilders.length == 0) { 58 | final CollectingComponentMatcher matcher = builder.buildCollecting(); 59 | visitComponentTree(root, matcher); 60 | return matcher.getBucket(); 61 | } else { 62 | final List parentsMatching = getChildrenMatching(root, realParentBuilders[0], 63 | tail(realParentBuilders)); 64 | final List childrenMatching = new LinkedList(); 65 | for (final Component parent : parentsMatching) { 66 | final CollectingComponentMatcher matcher = builder.buildCollecting(); 67 | visitComponentTree((MarkupContainer) parent, matcher); 68 | childrenMatching.addAll(matcher.getBucket()); 69 | } 70 | return childrenMatching; 71 | } 72 | } 73 | 74 | @SuppressWarnings("unchecked") 75 | private ComponentMatcherBuilder[] cleanup( 76 | final ComponentMatcherBuilder[] builders) { 77 | if (builders == null || builders.length == 0) { 78 | return new ComponentMatcherBuilder[0]; 79 | } 80 | // remove null values 81 | ComponentMatcherBuilder[] buildersWip = builders; 82 | while (ArrayUtils.contains(buildersWip, null)) { 83 | buildersWip = (ComponentMatcherBuilder[]) ArrayUtils.removeElement(builders, 84 | (Object) null); 85 | } 86 | return buildersWip; 87 | } 88 | 89 | @SuppressWarnings("unchecked") 90 | private ComponentMatcherBuilder[] tail( 91 | final ComponentMatcherBuilder[] arr) { 92 | return (ComponentMatcherBuilder[]) ArrayUtils.remove(arr, 0); 93 | } 94 | 95 | @SuppressWarnings("unchecked") 96 | public List getChildrenMatching(final MarkupContainer root, 97 | final ComponentMatcherBuilder builder) { 98 | return getChildrenMatching(root, builder, (ComponentMatcherBuilder) null); 99 | } 100 | 101 | public List getChildrenMatching(final ComponentMatcherBuilder builder, 102 | final ComponentMatcherBuilder... parentBuilders) { 103 | return getChildrenMatching(getLastRenderedPage(), builder, parentBuilders); 104 | } 105 | 106 | @SuppressWarnings("unchecked") 107 | public List getChildrenMatching(final ComponentMatcherBuilder builder) { 108 | return getChildrenMatching(builder, (ComponentMatcherBuilder) null); 109 | } 110 | 111 | public T getChildMatching(final MarkupContainer root, final ComponentMatcherBuilder builder, 112 | final ComponentMatcherBuilder... parentBuilders) { 113 | final List children = getChildrenMatching(root, builder, parentBuilders); 114 | 115 | Assert.assertEquals(children.size(), 1, String.format("Did not find exactly one child %s", builder.criteriaAsString())); 116 | 117 | return children.get(0); 118 | } 119 | 120 | @SuppressWarnings("unchecked") 121 | public T getChildMatching(final MarkupContainer root, final ComponentMatcherBuilder builder) { 122 | return getChildMatching(root, builder, (ComponentMatcherBuilder) null); 123 | } 124 | 125 | public T getChildMatching(final ComponentMatcherBuilder builder, 126 | final ComponentMatcherBuilder... parentBuilders) { 127 | return getChildMatching(getLastRenderedPage(), builder, parentBuilders); 128 | } 129 | 130 | @SuppressWarnings("unchecked") 131 | public T getChildMatching(final ComponentMatcherBuilder builder) { 132 | return getChildMatching(builder, (ComponentMatcherBuilder) null); 133 | } 134 | 135 | public T getFirstChildMatching(final MarkupContainer root, final ComponentMatcherBuilder builder, 136 | final ComponentMatcherBuilder... parentBuilders) { 137 | final List children = getChildrenMatching(root, builder, parentBuilders); 138 | 139 | Assert.assertTrue(children.size() > 0, String.format("Did not find at least one child %s", builder.criteriaAsString())); 140 | 141 | return children.get(0); 142 | } 143 | 144 | public T getFirstChildMatching(final ComponentMatcherBuilder builder, 145 | final ComponentMatcherBuilder... parentBuilders) { 146 | return getFirstChildMatching(getLastRenderedPage(), builder, parentBuilders); 147 | } 148 | 149 | @SuppressWarnings("unchecked") 150 | public T getFirstChildMatching(final MarkupContainer root, final ComponentMatcherBuilder builder) { 151 | return getFirstChildMatching(root, builder, (ComponentMatcherBuilder) null); 152 | } 153 | 154 | @SuppressWarnings("unchecked") 155 | public T getFirstChildMatching(final ComponentMatcherBuilder builder) { 156 | return getFirstChildMatching(builder, (ComponentMatcherBuilder) null); 157 | } 158 | 159 | public String getPathRelativeToRoot(final Component root, final Component component) { 160 | final String rootPath = root.getPageRelativePath(); 161 | final String componentPath = component.getPageRelativePath(); 162 | 163 | Assert.assertTrue(componentPath.startsWith(rootPath), "Component is not a child of the root component"); 164 | 165 | if (rootPath.length() == componentPath.length()) { 166 | return StringUtils.EMPTY; 167 | } 168 | 169 | /* 170 | * remove the root path prefix and any possible leftover path 171 | * separators. 172 | */ 173 | return StringUtils.stripStart(componentPath.substring(rootPath.length()), ":"); 174 | } 175 | 176 | public String getPathRelativeToPage(final Component component) { 177 | return getPathRelativeToRoot(getLastRenderedPage(), component); 178 | } 179 | 180 | public TagTester getTagTesterByComponent(final Component component) { 181 | final String[] pathSegments = component.getPath().split(String.valueOf(Component.PATH_SEPARATOR)); 182 | 183 | //strip leading 0: 184 | final String[] tail = Arrays.copyOfRange(pathSegments, 1, pathSegments.length); 185 | 186 | return TagTester.createTagByAttribute(getLastResponseAsString(), "wicketpath", getWicketPath(tail)); 187 | } 188 | 189 | public TagTester getTagTesterByComponentMatcher(final ComponentMatcherBuilder builder, 190 | final ComponentMatcherBuilder... parentBuilders) { 191 | return getTagTesterByComponent(getChildMatching(builder, parentBuilders)); 192 | } 193 | 194 | private String getWicketPath(final String[] tail) { 195 | for (int i = 0; i < tail.length; i++) { 196 | tail[i] = tail[i].replace("_", "__"); 197 | } 198 | return StringUtils.join(tail, "_"); 199 | } 200 | 201 | public void assertModelValue(final Component component, final Object expectedModelObject) { 202 | assertThat(component.getDefaultModelObject(), equalTo(expectedModelObject)); 203 | } 204 | 205 | public void assertModelValue(final Object expectedModelObject, final ComponentMatcherBuilder builder, 206 | final ComponentMatcherBuilder... parentBuilders) { 207 | assertThat(getChildMatching(builder, parentBuilders).getDefaultModelObject(), equalTo(expectedModelObject)); 208 | } 209 | 210 | public void assertVisible(final Component component) { 211 | assertVisible(getPathRelativeToPage(component)); 212 | } 213 | 214 | public void assertVisible(final ComponentMatcherBuilder builder, 215 | final ComponentMatcherBuilder... parentBuilders) { 216 | assertVisible(getChildMatching(builder, parentBuilders)); 217 | } 218 | 219 | public void assertFeedback(final ComponentMatcherBuilder builder, final Serializable... feedback) { 220 | assertFeedback(getPathRelativeToPage(getChildMatching(builder)), feedback); 221 | } 222 | 223 | public FormTester newFormTester(final Form form) { 224 | return newFormTester(getPathRelativeToPage(form)); 225 | } 226 | 227 | public FormTester newFormTester(@SuppressWarnings("rawtypes") final ComponentMatcherBuilder builder, 228 | final ComponentMatcherBuilder... parentBuilders) { 229 | return newFormTester(getChildMatching(builder, parentBuilders)); 230 | } 231 | 232 | public void assertInvisible(final Label component) { 233 | assertInvisible(getPathRelativeToPage(component)); 234 | } 235 | 236 | public void clickLink(final ComponentMatcherBuilder builder, 237 | final ComponentMatcherBuilder... parentBuilders) { 238 | clickLink(getChildMatching(builder, parentBuilders)); 239 | } 240 | 241 | public void executeAjaxEvent(final String event, final ComponentMatcherBuilder builder, 242 | final ComponentMatcherBuilder... parentBuilders) { 243 | executeAjaxEvent(getChildMatching(builder, parentBuilders), event); 244 | } 245 | 246 | } 247 | -------------------------------------------------------------------------------- /src/main/java/de/otto/wickettester/HavingChildComponentMatcher.java: -------------------------------------------------------------------------------- 1 | package de.otto.wickettester; 2 | 3 | import org.apache.wicket.Component; 4 | import org.apache.wicket.MarkupContainer; 5 | import org.apache.wicket.util.visit.IVisit; 6 | import org.apache.wicket.util.visit.IVisitor; 7 | import org.apache.wicket.util.visit.Visits; 8 | 9 | public class HavingChildComponentMatcher implements ComponentMatcher { 10 | 11 | private final ComponentMatcher matcher; 12 | 13 | public HavingChildComponentMatcher(final ComponentMatcher matcher) { 14 | this.matcher = matcher; 15 | } 16 | 17 | @Override 18 | public T match(final T component) { 19 | if (!(component instanceof MarkupContainer)) { 20 | return null; 21 | } else { 22 | final Component res = Visits.visitChildren((MarkupContainer) component, new IVisitor() { 23 | 24 | @Override 25 | public void component(final CT component, final IVisit visit) { 26 | final CT result = matcher.match(component); 27 | if (result != null) { 28 | visit.stop(result); 29 | } 30 | } 31 | }); 32 | return res != null ? component : null; 33 | } 34 | } 35 | 36 | @Override 37 | public String criterionAsString() { 38 | return String.format("having a child (%s)", matcher.criterionAsString()); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/de/otto/wickettester/HavingDirectChildComponentMatcher.java: -------------------------------------------------------------------------------- 1 | package de.otto.wickettester; 2 | 3 | import org.apache.wicket.Component; 4 | import org.apache.wicket.MarkupContainer; 5 | 6 | public class HavingDirectChildComponentMatcher implements ComponentMatcher { 7 | 8 | private final ComponentMatcher matcher; 9 | 10 | public HavingDirectChildComponentMatcher(final ComponentMatcher matcher) { 11 | this.matcher = matcher; 12 | } 13 | 14 | @SuppressWarnings("unchecked") 15 | @Override 16 | public T match(final T component) { 17 | if (!(component instanceof MarkupContainer)) { 18 | return null; 19 | } else { 20 | for (final Component directChild : (MarkupContainer) component) { 21 | // this is just plain wrong, but works, since the type matcher is in the chain 22 | final CT result = matcher.match((CT) directChild); 23 | if (result != null) { 24 | return component; 25 | } 26 | } 27 | return null; 28 | } 29 | } 30 | 31 | @Override 32 | public String criterionAsString() { 33 | return String.format("having a direct child (%s)", matcher.criterionAsString()); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/de/otto/wickettester/HavingDirectParentComponentMatcher.java: -------------------------------------------------------------------------------- 1 | package de.otto.wickettester; 2 | 3 | import org.apache.wicket.Component; 4 | 5 | public class HavingDirectParentComponentMatcher implements ComponentMatcher { 6 | 7 | private final ComponentMatcher matcher; 8 | 9 | public HavingDirectParentComponentMatcher(final ComponentMatcher matcher) { 10 | this.matcher = matcher; 11 | } 12 | 13 | @SuppressWarnings("unchecked") 14 | @Override 15 | public T match(final T component) { 16 | // this is just plain wrong, but works, since the type matcher is in the chain 17 | return matcher.match((CT) component.getParent()) != null ? component : null; 18 | 19 | } 20 | 21 | @Override 22 | public String criterionAsString() { 23 | return String.format("having a direct parent (%s)", matcher.criterionAsString()); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/de/otto/wickettester/HavingSiblingComponentMatcher.java: -------------------------------------------------------------------------------- 1 | package de.otto.wickettester; 2 | 3 | import java.util.Iterator; 4 | 5 | import org.apache.wicket.Component; 6 | import org.apache.wicket.MarkupContainer; 7 | 8 | /** 9 | * Returns true if one of the siblings matches the criteria 10 | * 11 | * @author Oliver Langer (oliver.langer@ottogroup.com) 12 | */ 13 | public class HavingSiblingComponentMatcher implements ComponentMatcher { 14 | 15 | private final ComponentMatcher matcher; 16 | 17 | public HavingSiblingComponentMatcher(final ComponentMatcher matcher) { 18 | this.matcher = matcher; 19 | } 20 | 21 | @SuppressWarnings("unchecked") 22 | @Override 23 | public T match(final T component) { 24 | if (component == null) { 25 | return null; 26 | } 27 | 28 | final MarkupContainer parent = component.getParent(); 29 | 30 | if (parent == null) { 31 | return null; 32 | } 33 | 34 | T toReturn = null; 35 | final Iterator children = parent.iterator(); 36 | while (children.hasNext()) { 37 | final CT next = (CT) children.next(); 38 | if (matcher.match(next) != null) { 39 | toReturn = (T) next; 40 | } 41 | } 42 | 43 | return toReturn; 44 | } 45 | 46 | @Override 47 | public String criterionAsString() { 48 | return String.format("having a direct parent (%s)", matcher.criterionAsString()); 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/de/otto/wickettester/ModelObjectComponentMatcher.java: -------------------------------------------------------------------------------- 1 | package de.otto.wickettester; 2 | 3 | import org.apache.wicket.Component; 4 | 5 | public class ModelObjectComponentMatcher implements ComponentMatcher { 6 | 7 | private final Object modelObject; 8 | 9 | public ModelObjectComponentMatcher(final Object modelObject) { 10 | this.modelObject = modelObject; 11 | } 12 | 13 | @Override 14 | public T match(final T component) { 15 | return modelObject.equals(component.getDefaultModelObject()) ? component : null; 16 | } 17 | 18 | @Override 19 | public String criterionAsString() { 20 | return String.format("having a model object '%s'", modelObject); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/de/otto/wickettester/NegatingComponentMatcher.java: -------------------------------------------------------------------------------- 1 | package de.otto.wickettester; 2 | 3 | import org.apache.wicket.Component; 4 | 5 | public class NegatingComponentMatcher implements ComponentMatcher { 6 | 7 | private final ComponentMatcher matcher; 8 | 9 | public NegatingComponentMatcher(final ComponentMatcher matcher) { 10 | this.matcher = matcher; 11 | } 12 | 13 | @Override 14 | public T match(final T component) { 15 | return matcher.match(component) != null ? null : component; 16 | } 17 | 18 | @Override 19 | public String criterionAsString() { 20 | return "not " + matcher.criterionAsString(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/de/otto/wickettester/TypeComponentMatcher.java: -------------------------------------------------------------------------------- 1 | package de.otto.wickettester; 2 | 3 | import org.apache.wicket.Component; 4 | 5 | public class TypeComponentMatcher implements ComponentMatcher { 6 | 7 | private final Class componentClass; 8 | 9 | public TypeComponentMatcher(final Class componentClass) { 10 | this.componentClass = componentClass; 11 | } 12 | 13 | @Override 14 | public T match(final T component) { 15 | if (componentClass.isAssignableFrom(component.getClass())) { 16 | return component; 17 | } 18 | return null; 19 | } 20 | 21 | @Override 22 | public String criterionAsString() { 23 | return String.format("being of type '%s'", componentClass.getSimpleName()); 24 | } 25 | 26 | } -------------------------------------------------------------------------------- /src/main/java/de/otto/wickettester/VisibleComponentMatcher.java: -------------------------------------------------------------------------------- 1 | package de.otto.wickettester; 2 | 3 | import org.apache.wicket.Component; 4 | 5 | public class VisibleComponentMatcher implements ComponentMatcher { 6 | 7 | @Override 8 | public T match(final T component) { 9 | if (component.isVisibleInHierarchy()) { 10 | return component; 11 | } 12 | return null; 13 | } 14 | 15 | @Override 16 | public String criterionAsString() { 17 | return String.format("being visible"); 18 | } 19 | 20 | } -------------------------------------------------------------------------------- /src/main/java/de/otto/wickettester/WicketIdComponentMatcher.java: -------------------------------------------------------------------------------- 1 | package de.otto.wickettester; 2 | 3 | import org.apache.wicket.Component; 4 | 5 | public class WicketIdComponentMatcher implements ComponentMatcher { 6 | 7 | private final String wicketId; 8 | 9 | public WicketIdComponentMatcher(final String wicketId) { 10 | this.wicketId = wicketId; 11 | } 12 | 13 | @Override 14 | public T match(final T component) { 15 | if (component.getId().equals(wicketId)) { 16 | return component; 17 | } 18 | return null; 19 | } 20 | 21 | @Override 22 | public String criterionAsString() { 23 | return String.format("having the wicket id '%s'", wicketId); 24 | } 25 | 26 | } --------------------------------------------------------------------------------