├── .gitignore ├── README.md ├── metrics.out ├── pom.xml └── src └── test └── java └── com └── paulhammant └── fluentSeleniumExamples ├── BasePage.java ├── WholeSuiteListener.java ├── etsy ├── BuyAHatTest.java ├── Cart.java ├── Home.java ├── Listing.java └── SearchResults.java ├── hipmunk ├── BookAFlightTest.java ├── BookingOverlay.java ├── Home.java ├── SearchResults.java └── UnitedAirlinesBooking.java └── jimmyjohns ├── CustomizeYourOrder.java ├── Home.java ├── JimmyJohnsTest.java ├── Menu.java └── VerifyAddress.java /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | *.iml 3 | .idea -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FluentSelenium examples 2 | 3 | Refer to my [Fluent Selenium Examples Blog Entry](http://paulhammant.com/2013/05/19/fluent-selenium-examples) -------------------------------------------------------------------------------- /metrics.out: -------------------------------------------------------------------------------- 1 | 7/22/13 7:12:42 PM ============================================================= 2 | 3 | -- Timers ---------------------------------------------------------------------- 4 | etsy.BuyAHatTest.adding_a_hat_to_the_cart:etsy.Home.:button(By.id: search_submit).click() 5 | count = 1 6 | mean rate = 0.00 calls/millisecond 7 | 1-minute rate = 0.00 calls/millisecond 8 | 5-minute rate = 0.00 calls/millisecond 9 | 15-minute rate = 0.00 calls/millisecond 10 | min = 1354.56 milliseconds 11 | max = 1354.56 milliseconds 12 | mean = 1354.56 milliseconds 13 | stddev = 0.00 milliseconds 14 | median = 1354.56 milliseconds 15 | 75% <= 1354.56 milliseconds 16 | 95% <= 1354.56 milliseconds 17 | 98% <= 1354.56 milliseconds 18 | 99% <= 1354.56 milliseconds 19 | 99.9% <= 1354.56 milliseconds 20 | etsy.BuyAHatTest.adding_a_hat_to_the_cart:etsy.Home.:input(By.id: search-query).sendKeys('Hat') 21 | count = 1 22 | mean rate = 0.00 calls/millisecond 23 | 1-minute rate = 0.00 calls/millisecond 24 | 5-minute rate = 0.00 calls/millisecond 25 | 15-minute rate = 0.00 calls/millisecond 26 | min = 53.82 milliseconds 27 | max = 53.82 milliseconds 28 | mean = 53.82 milliseconds 29 | stddev = 0.00 milliseconds 30 | median = 53.82 milliseconds 31 | 75% <= 53.82 milliseconds 32 | 95% <= 53.82 milliseconds 33 | 98% <= 53.82 milliseconds 34 | 99% <= 53.82 milliseconds 35 | 99.9% <= 53.82 milliseconds 36 | etsy.BuyAHatTest.adding_a_hat_to_the_cart:etsy.Listing.:button(By.className: btn-transaction).click() 37 | count = 1 38 | mean rate = 0.00 calls/millisecond 39 | 1-minute rate = 0.00 calls/millisecond 40 | 5-minute rate = 0.00 calls/millisecond 41 | 15-minute rate = 0.00 calls/millisecond 42 | min = 298.48 milliseconds 43 | max = 298.48 milliseconds 44 | mean = 298.48 milliseconds 45 | stddev = 0.00 milliseconds 46 | median = 298.48 milliseconds 47 | 75% <= 298.48 milliseconds 48 | 95% <= 298.48 milliseconds 49 | 98% <= 298.48 milliseconds 50 | 99% <= 298.48 milliseconds 51 | 99.9% <= 298.48 milliseconds 52 | etsy.BuyAHatTest.adding_a_hat_to_the_cart:etsy.SearchResults.:ul(By.className: listings).lis(By.tagName: li).a() 53 | count = 1 54 | mean rate = 0.00 calls/millisecond 55 | 1-minute rate = 0.00 calls/millisecond 56 | 5-minute rate = 0.00 calls/millisecond 57 | 15-minute rate = 0.00 calls/millisecond 58 | min = 10.55 milliseconds 59 | max = 10.55 milliseconds 60 | mean = 10.55 milliseconds 61 | stddev = 0.00 milliseconds 62 | median = 10.55 milliseconds 63 | 75% <= 10.55 milliseconds 64 | 95% <= 10.55 milliseconds 65 | 98% <= 10.55 milliseconds 66 | 99% <= 10.55 milliseconds 67 | 99.9% <= 10.55 milliseconds 68 | etsy.BuyAHatTest.adding_a_hat_to_the_cart:etsy.SearchResults.:ul(By.className: listings).lis(By.tagName: li).a().click() 69 | count = 1 70 | mean rate = 0.00 calls/millisecond 71 | 1-minute rate = 0.00 calls/millisecond 72 | 5-minute rate = 0.00 calls/millisecond 73 | 15-minute rate = 0.00 calls/millisecond 74 | min = 69.30 milliseconds 75 | max = 69.30 milliseconds 76 | mean = 69.30 milliseconds 77 | stddev = 0.00 milliseconds 78 | median = 69.30 milliseconds 79 | 75% <= 69.30 milliseconds 80 | 95% <= 69.30 milliseconds 81 | 98% <= 69.30 milliseconds 82 | 99% <= 69.30 milliseconds 83 | 99.9% <= 69.30 milliseconds 84 | etsy.Home.searchButton:button(By.id: search_submit) 85 | count = 1 86 | mean rate = 0.00 calls/millisecond 87 | 1-minute rate = 0.00 calls/millisecond 88 | 5-minute rate = 0.00 calls/millisecond 89 | 15-minute rate = 0.00 calls/millisecond 90 | min = 115.86 milliseconds 91 | max = 115.86 milliseconds 92 | mean = 115.86 milliseconds 93 | stddev = 0.00 milliseconds 94 | median = 115.86 milliseconds 95 | 75% <= 115.86 milliseconds 96 | 95% <= 115.86 milliseconds 97 | 98% <= 115.86 milliseconds 98 | 99% <= 115.86 milliseconds 99 | 99.9% <= 115.86 milliseconds 100 | etsy.Home.searchFor:input(By.id: search-query) 101 | count = 1 102 | mean rate = 0.00 calls/millisecond 103 | 1-minute rate = 0.00 calls/millisecond 104 | 5-minute rate = 0.00 calls/millisecond 105 | 15-minute rate = 0.00 calls/millisecond 106 | min = 41.27 milliseconds 107 | max = 41.27 milliseconds 108 | mean = 41.27 milliseconds 109 | stddev = 0.00 milliseconds 110 | median = 41.27 milliseconds 111 | 75% <= 41.27 milliseconds 112 | 95% <= 41.27 milliseconds 113 | 98% <= 41.27 milliseconds 114 | 99% <= 41.27 milliseconds 115 | 99.9% <= 41.27 milliseconds 116 | etsy.Listing.addToCartButton:button(By.className: btn-transaction) 117 | count = 1 118 | mean rate = 0.00 calls/millisecond 119 | 1-minute rate = 0.00 calls/millisecond 120 | 5-minute rate = 0.00 calls/millisecond 121 | 15-minute rate = 0.00 calls/millisecond 122 | min = 15.25 milliseconds 123 | max = 15.25 milliseconds 124 | mean = 15.25 milliseconds 125 | stddev = 0.00 milliseconds 126 | median = 15.25 milliseconds 127 | 75% <= 15.25 milliseconds 128 | 95% <= 15.25 milliseconds 129 | 98% <= 15.25 milliseconds 130 | 99% <= 15.25 milliseconds 131 | 99.9% <= 15.25 milliseconds 132 | etsy.SearchResults.firstNonSponsoredListing:ul(By.className: listings) 133 | count = 1 134 | mean rate = 0.00 calls/millisecond 135 | 1-minute rate = 0.00 calls/millisecond 136 | 5-minute rate = 0.00 calls/millisecond 137 | 15-minute rate = 0.00 calls/millisecond 138 | min = 16.15 milliseconds 139 | max = 16.15 milliseconds 140 | mean = 16.15 milliseconds 141 | stddev = 0.00 milliseconds 142 | median = 16.15 milliseconds 143 | 75% <= 16.15 milliseconds 144 | 95% <= 16.15 milliseconds 145 | 98% <= 16.15 milliseconds 146 | 99% <= 16.15 milliseconds 147 | 99.9% <= 16.15 milliseconds 148 | etsy.SearchResults.firstNonSponsoredListing:ul(By.className: listings).lis(By.tagName: li) 149 | count = 1 150 | mean rate = 0.00 calls/millisecond 151 | 1-minute rate = 0.00 calls/millisecond 152 | 5-minute rate = 0.00 calls/millisecond 153 | 15-minute rate = 0.00 calls/millisecond 154 | min = 32.21 milliseconds 155 | max = 32.21 milliseconds 156 | mean = 32.21 milliseconds 157 | stddev = 0.00 milliseconds 158 | median = 32.21 milliseconds 159 | 75% <= 32.21 milliseconds 160 | 95% <= 32.21 milliseconds 161 | 98% <= 32.21 milliseconds 162 | 99% <= 32.21 milliseconds 163 | 99.9% <= 32.21 milliseconds 164 | etsy.SearchResults.numberMatchingSearchHeader:div(By.id: search-header) 165 | count = 1 166 | mean rate = 0.00 calls/millisecond 167 | 1-minute rate = 0.00 calls/millisecond 168 | 5-minute rate = 0.00 calls/millisecond 169 | 15-minute rate = 0.00 calls/millisecond 170 | min = 13.52 milliseconds 171 | max = 13.52 milliseconds 172 | mean = 13.52 milliseconds 173 | stddev = 0.00 milliseconds 174 | median = 13.52 milliseconds 175 | 75% <= 13.52 milliseconds 176 | 95% <= 13.52 milliseconds 177 | 98% <= 13.52 milliseconds 178 | 99% <= 13.52 milliseconds 179 | 99.9% <= 13.52 milliseconds 180 | etsy.SearchResults.numberMatchingSearchHeader:div(By.id: search-header).h1() 181 | count = 1 182 | mean rate = 0.00 calls/millisecond 183 | 1-minute rate = 0.00 calls/millisecond 184 | 5-minute rate = 0.00 calls/millisecond 185 | 15-minute rate = 0.00 calls/millisecond 186 | min = 14.63 milliseconds 187 | max = 14.63 milliseconds 188 | mean = 14.63 milliseconds 189 | stddev = 0.00 milliseconds 190 | median = 14.63 milliseconds 191 | 75% <= 14.63 milliseconds 192 | 95% <= 14.63 milliseconds 193 | 98% <= 14.63 milliseconds 194 | 99% <= 14.63 milliseconds 195 | 99.9% <= 14.63 milliseconds 196 | hipmunk.BookAFlightTest.a_booking_through_to_priceline_affiliate:hipmunk.BookingOverlay.:hipmunk.SearchResults.:divs(By.className: booking-link-row).a() 197 | count = 1 198 | mean rate = 0.00 calls/millisecond 199 | 1-minute rate = 0.00 calls/millisecond 200 | 5-minute rate = 0.00 calls/millisecond 201 | 15-minute rate = 0.00 calls/millisecond 202 | min = 16.61 milliseconds 203 | max = 16.61 milliseconds 204 | mean = 16.61 milliseconds 205 | stddev = 0.00 milliseconds 206 | median = 16.61 milliseconds 207 | 75% <= 16.61 milliseconds 208 | 95% <= 16.61 milliseconds 209 | 98% <= 16.61 milliseconds 210 | 99% <= 16.61 milliseconds 211 | 99.9% <= 16.61 milliseconds 212 | hipmunk.BookAFlightTest.a_booking_through_to_priceline_affiliate:hipmunk.BookingOverlay.:hipmunk.SearchResults.:divs(By.className: booking-link-row).a().click() 213 | count = 1 214 | mean rate = 0.00 calls/millisecond 215 | 1-minute rate = 0.00 calls/millisecond 216 | 5-minute rate = 0.00 calls/millisecond 217 | 15-minute rate = 0.00 calls/millisecond 218 | min = 404.70 milliseconds 219 | max = 404.70 milliseconds 220 | mean = 404.70 milliseconds 221 | stddev = 0.00 milliseconds 222 | median = 404.70 milliseconds 223 | 75% <= 404.70 milliseconds 224 | 95% <= 404.70 milliseconds 225 | 98% <= 404.70 milliseconds 226 | 99% <= 404.70 milliseconds 227 | 99.9% <= 404.70 milliseconds 228 | hipmunk.BookAFlightTest.a_booking_through_to_priceline_affiliate:hipmunk.BookingOverlay.:hipmunk.SearchResults.:divs(By.className: booking-link-row).div() 229 | count = 1 230 | mean rate = 0.00 calls/millisecond 231 | 1-minute rate = 0.00 calls/millisecond 232 | 5-minute rate = 0.00 calls/millisecond 233 | 15-minute rate = 0.00 calls/millisecond 234 | min = 13.59 milliseconds 235 | max = 13.59 milliseconds 236 | mean = 13.59 milliseconds 237 | stddev = 0.00 milliseconds 238 | median = 13.59 milliseconds 239 | 75% <= 13.59 milliseconds 240 | 95% <= 13.59 milliseconds 241 | 98% <= 13.59 milliseconds 242 | 99% <= 13.59 milliseconds 243 | 99.9% <= 13.59 milliseconds 244 | hipmunk.BookAFlightTest.a_booking_through_to_priceline_affiliate:hipmunk.Home.:form(By.id: flight).button().click() 245 | count = 1 246 | mean rate = 0.00 calls/millisecond 247 | 1-minute rate = 0.00 calls/millisecond 248 | 5-minute rate = 0.00 calls/millisecond 249 | 15-minute rate = 0.00 calls/millisecond 250 | min = 127.03 milliseconds 251 | max = 127.03 milliseconds 252 | mean = 127.03 milliseconds 253 | stddev = 0.00 milliseconds 254 | median = 127.03 milliseconds 255 | 75% <= 127.03 milliseconds 256 | 95% <= 127.03 milliseconds 257 | 98% <= 127.03 milliseconds 258 | 99% <= 127.03 milliseconds 259 | 99.9% <= 127.03 milliseconds 260 | hipmunk.BookAFlightTest.a_booking_through_to_priceline_affiliate:hipmunk.Home.:input(By.id: fac1flight).sendKeys('DFW') 261 | count = 1 262 | mean rate = 0.00 calls/millisecond 263 | 1-minute rate = 0.00 calls/millisecond 264 | 5-minute rate = 0.00 calls/millisecond 265 | 15-minute rate = 0.00 calls/millisecond 266 | min = 119.18 milliseconds 267 | max = 119.18 milliseconds 268 | mean = 119.18 milliseconds 269 | stddev = 0.00 milliseconds 270 | median = 119.18 milliseconds 271 | 75% <= 119.18 milliseconds 272 | 95% <= 119.18 milliseconds 273 | 98% <= 119.18 milliseconds 274 | 99% <= 119.18 milliseconds 275 | 99.9% <= 119.18 milliseconds 276 | hipmunk.BookAFlightTest.a_booking_through_to_priceline_affiliate:hipmunk.Home.:input(By.id: fac2flight).sendKeys('ORD') 277 | count = 1 278 | mean rate = 0.00 calls/millisecond 279 | 1-minute rate = 0.00 calls/millisecond 280 | 5-minute rate = 0.00 calls/millisecond 281 | 15-minute rate = 0.00 calls/millisecond 282 | min = 52.34 milliseconds 283 | max = 52.34 milliseconds 284 | mean = 52.34 milliseconds 285 | stddev = 0.00 milliseconds 286 | median = 52.34 milliseconds 287 | 75% <= 52.34 milliseconds 288 | 95% <= 52.34 milliseconds 289 | 98% <= 52.34 milliseconds 290 | 99% <= 52.34 milliseconds 291 | 99.9% <= 52.34 milliseconds 292 | hipmunk.BookAFlightTest.a_booking_through_to_priceline_affiliate:hipmunk.SearchResults.:div(By.id: sub-graph-1).div(By.className: select-leg).click() 293 | count = 2 294 | mean rate = 0.00 calls/millisecond 295 | 1-minute rate = 0.00 calls/millisecond 296 | 5-minute rate = 0.00 calls/millisecond 297 | 15-minute rate = 0.00 calls/millisecond 298 | min = 91.05 milliseconds 299 | max = 170.19 milliseconds 300 | mean = 130.62 milliseconds 301 | stddev = 55.96 milliseconds 302 | median = 130.62 milliseconds 303 | 75% <= 170.19 milliseconds 304 | 95% <= 170.19 milliseconds 305 | 98% <= 170.19 milliseconds 306 | 99% <= 170.19 milliseconds 307 | 99.9% <= 170.19 milliseconds 308 | hipmunk.BookAFlightTest.timeBizOperation:DFW->ORD Initial Search Results (End User Experience) 309 | count = 1 310 | mean rate = 0.00 calls/millisecond 311 | 1-minute rate = 0.00 calls/millisecond 312 | 5-minute rate = 0.00 calls/millisecond 313 | 15-minute rate = 0.00 calls/millisecond 314 | min = 2486.31 milliseconds 315 | max = 2486.31 milliseconds 316 | mean = 2486.31 milliseconds 317 | stddev = 0.00 milliseconds 318 | median = 2486.31 milliseconds 319 | 75% <= 2486.31 milliseconds 320 | 95% <= 2486.31 milliseconds 321 | 98% <= 2486.31 milliseconds 322 | 99% <= 2486.31 milliseconds 323 | 99.9% <= 2486.31 milliseconds 324 | hipmunk.BookAFlightTest.timeBizOperation:DFW->ORD Priceline Transfer (End User Experience) 325 | count = 1 326 | mean rate = 0.00 calls/millisecond 327 | 1-minute rate = 0.00 calls/millisecond 328 | 5-minute rate = 0.00 calls/millisecond 329 | 15-minute rate = 0.00 calls/millisecond 330 | min = 12978.57 milliseconds 331 | max = 12978.57 milliseconds 332 | mean = 12978.57 milliseconds 333 | stddev = 0.00 milliseconds 334 | median = 12978.57 milliseconds 335 | 75% <= 12978.57 milliseconds 336 | 95% <= 12978.57 milliseconds 337 | 98% <= 12978.57 milliseconds 338 | 99% <= 12978.57 milliseconds 339 | 99.9% <= 12978.57 milliseconds 340 | hipmunk.BookAFlightTest.timeBizOperation:DFW->ORD Return Leg Search Results (End User Experience) 341 | count = 1 342 | mean rate = 0.00 calls/millisecond 343 | 1-minute rate = 0.00 calls/millisecond 344 | 5-minute rate = 0.00 calls/millisecond 345 | 15-minute rate = 0.00 calls/millisecond 346 | min = 1038.87 milliseconds 347 | max = 1038.87 milliseconds 348 | mean = 1038.87 milliseconds 349 | stddev = 0.00 milliseconds 350 | median = 1038.87 milliseconds 351 | 75% <= 1038.87 milliseconds 352 | 95% <= 1038.87 milliseconds 353 | 98% <= 1038.87 milliseconds 354 | 99% <= 1038.87 milliseconds 355 | 99.9% <= 1038.87 milliseconds 356 | hipmunk.BookingOverlay.pricelineRow:divs(By.className: booking-link-row) 357 | count = 1 358 | mean rate = 0.00 calls/millisecond 359 | 1-minute rate = 0.00 calls/millisecond 360 | 5-minute rate = 0.00 calls/millisecond 361 | 15-minute rate = 0.00 calls/millisecond 362 | min = 56.58 milliseconds 363 | max = 56.58 milliseconds 364 | mean = 56.58 milliseconds 365 | stddev = 0.00 milliseconds 366 | median = 56.58 milliseconds 367 | 75% <= 56.58 milliseconds 368 | 95% <= 56.58 milliseconds 369 | 98% <= 56.58 milliseconds 370 | 99% <= 56.58 milliseconds 371 | 99.9% <= 56.58 milliseconds 372 | hipmunk.BookingOverlay.pricelineRow:divs(By.className: booking-link-row).first(com.paulhammant.fluentSeleniumExamples.hipmunk.BookingOverlay$1@63a6b16f) 373 | count = 1 374 | mean rate = 0.00 calls/millisecond 375 | 1-minute rate = 0.00 calls/millisecond 376 | 5-minute rate = 0.00 calls/millisecond 377 | 15-minute rate = 0.00 calls/millisecond 378 | min = 39.10 milliseconds 379 | max = 39.10 milliseconds 380 | mean = 39.10 milliseconds 381 | stddev = 0.00 milliseconds 382 | median = 39.10 milliseconds 383 | 75% <= 39.10 milliseconds 384 | 95% <= 39.10 milliseconds 385 | 98% <= 39.10 milliseconds 386 | 99% <= 39.10 milliseconds 387 | 99.9% <= 39.10 milliseconds 388 | hipmunk.Home.fromAirportField:input(By.id: fac1flight) 389 | count = 1 390 | mean rate = 0.00 calls/millisecond 391 | 1-minute rate = 0.00 calls/millisecond 392 | 5-minute rate = 0.00 calls/millisecond 393 | 15-minute rate = 0.00 calls/millisecond 394 | min = 39.48 milliseconds 395 | max = 39.48 milliseconds 396 | mean = 39.48 milliseconds 397 | stddev = 0.00 milliseconds 398 | median = 39.48 milliseconds 399 | 75% <= 39.48 milliseconds 400 | 95% <= 39.48 milliseconds 401 | 98% <= 39.48 milliseconds 402 | 99% <= 39.48 milliseconds 403 | 99.9% <= 39.48 milliseconds 404 | hipmunk.Home.searchButton:form(By.id: flight) 405 | count = 1 406 | mean rate = 0.00 calls/millisecond 407 | 1-minute rate = 0.00 calls/millisecond 408 | 5-minute rate = 0.00 calls/millisecond 409 | 15-minute rate = 0.00 calls/millisecond 410 | min = 13.17 milliseconds 411 | max = 13.17 milliseconds 412 | mean = 13.17 milliseconds 413 | stddev = 0.00 milliseconds 414 | median = 13.17 milliseconds 415 | 75% <= 13.17 milliseconds 416 | 95% <= 13.17 milliseconds 417 | 98% <= 13.17 milliseconds 418 | 99% <= 13.17 milliseconds 419 | 99.9% <= 13.17 milliseconds 420 | hipmunk.Home.searchButton:form(By.id: flight).button() 421 | count = 1 422 | mean rate = 0.00 calls/millisecond 423 | 1-minute rate = 0.00 calls/millisecond 424 | 5-minute rate = 0.00 calls/millisecond 425 | 15-minute rate = 0.00 calls/millisecond 426 | min = 16.63 milliseconds 427 | max = 16.63 milliseconds 428 | mean = 16.63 milliseconds 429 | stddev = 0.00 milliseconds 430 | median = 16.63 milliseconds 431 | 75% <= 16.63 milliseconds 432 | 95% <= 16.63 milliseconds 433 | 98% <= 16.63 milliseconds 434 | 99% <= 16.63 milliseconds 435 | 99.9% <= 16.63 milliseconds 436 | hipmunk.Home.toAirportField:input(By.id: fac2flight) 437 | count = 1 438 | mean rate = 0.00 calls/millisecond 439 | 1-minute rate = 0.00 calls/millisecond 440 | 5-minute rate = 0.00 calls/millisecond 441 | 15-minute rate = 0.00 calls/millisecond 442 | min = 81.66 milliseconds 443 | max = 81.66 milliseconds 444 | mean = 81.66 milliseconds 445 | stddev = 0.00 milliseconds 446 | median = 81.66 milliseconds 447 | 75% <= 81.66 milliseconds 448 | 95% <= 81.66 milliseconds 449 | 98% <= 81.66 milliseconds 450 | 99% <= 81.66 milliseconds 451 | 99.9% <= 81.66 milliseconds 452 | hipmunk.Home.waitForExpandoToComplete:div(By.id: flight-search) 453 | count = 1 454 | mean rate = 0.00 calls/millisecond 455 | 1-minute rate = 0.00 calls/millisecond 456 | 5-minute rate = 0.00 calls/millisecond 457 | 15-minute rate = 0.00 calls/millisecond 458 | min = 46.31 milliseconds 459 | max = 46.31 milliseconds 460 | mean = 46.31 milliseconds 461 | stddev = 0.00 milliseconds 462 | median = 46.31 milliseconds 463 | 75% <= 46.31 milliseconds 464 | 95% <= 46.31 milliseconds 465 | 98% <= 46.31 milliseconds 466 | 99% <= 46.31 milliseconds 467 | 99.9% <= 46.31 milliseconds 468 | hipmunk.PricelineAffiliateBooking.getActualPrice:span(By.id: ttp1) 469 | count = 1 470 | mean rate = 0.00 calls/millisecond 471 | 1-minute rate = 0.00 calls/millisecond 472 | 5-minute rate = 0.00 calls/millisecond 473 | 15-minute rate = 0.00 calls/millisecond 474 | min = 15.92 milliseconds 475 | max = 15.92 milliseconds 476 | mean = 15.92 milliseconds 477 | stddev = 0.00 milliseconds 478 | median = 15.92 milliseconds 479 | 75% <= 15.92 milliseconds 480 | 95% <= 15.92 milliseconds 481 | 98% <= 15.92 milliseconds 482 | 99% <= 15.92 milliseconds 483 | 99.9% <= 15.92 milliseconds 484 | hipmunk.SearchResults.firstShownLeg:div(By.id: sub-graph-1) 485 | count = 2 486 | mean rate = 0.00 calls/millisecond 487 | 1-minute rate = 0.00 calls/millisecond 488 | 5-minute rate = 0.00 calls/millisecond 489 | 15-minute rate = 0.00 calls/millisecond 490 | min = 11.92 milliseconds 491 | max = 19.02 milliseconds 492 | mean = 15.47 milliseconds 493 | stddev = 5.02 milliseconds 494 | median = 15.47 milliseconds 495 | 75% <= 19.02 milliseconds 496 | 95% <= 19.02 milliseconds 497 | 98% <= 19.02 milliseconds 498 | 99% <= 19.02 milliseconds 499 | 99.9% <= 19.02 milliseconds 500 | hipmunk.SearchResults.firstShownLeg:div(By.id: sub-graph-1).div(By.className: select-leg) 501 | count = 2 502 | mean rate = 0.00 calls/millisecond 503 | 1-minute rate = 0.00 calls/millisecond 504 | 5-minute rate = 0.00 calls/millisecond 505 | 15-minute rate = 0.00 calls/millisecond 506 | min = 20.35 milliseconds 507 | max = 20.35 milliseconds 508 | mean = 20.35 milliseconds 509 | stddev = 0.00 milliseconds 510 | median = 20.35 milliseconds 511 | 75% <= 20.35 milliseconds 512 | 95% <= 20.35 milliseconds 513 | 98% <= 20.35 milliseconds 514 | 99% <= 20.35 milliseconds 515 | 99.9% <= 20.35 milliseconds 516 | hipmunk.SearchResults.waitForFlightListFor:div(By.id: leg-selector-1) 517 | count = 2 518 | mean rate = 0.00 calls/millisecond 519 | 1-minute rate = 0.00 calls/millisecond 520 | 5-minute rate = 0.00 calls/millisecond 521 | 15-minute rate = 0.00 calls/millisecond 522 | min = 13.37 milliseconds 523 | max = 14.46 milliseconds 524 | mean = 13.92 milliseconds 525 | stddev = 0.77 milliseconds 526 | median = 13.92 milliseconds 527 | 75% <= 14.46 milliseconds 528 | 95% <= 14.46 milliseconds 529 | 98% <= 14.46 milliseconds 530 | 99% <= 14.46 milliseconds 531 | 99.9% <= 14.46 milliseconds 532 | hipmunk.SearchResults.waitForFlightListFor:div(By.id: leg-selector-1).div(By.className: selected) 533 | count = 2 534 | mean rate = 0.00 calls/millisecond 535 | 1-minute rate = 0.00 calls/millisecond 536 | 5-minute rate = 0.00 calls/millisecond 537 | 15-minute rate = 0.00 calls/millisecond 538 | min = 13.32 milliseconds 539 | max = 13.66 milliseconds 540 | mean = 13.49 milliseconds 541 | stddev = 0.24 milliseconds 542 | median = 13.49 milliseconds 543 | 75% <= 13.66 milliseconds 544 | 95% <= 13.66 milliseconds 545 | 98% <= 13.66 milliseconds 546 | 99% <= 13.66 milliseconds 547 | 99.9% <= 13.66 milliseconds 548 | 549 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.paulhammant 6 | fluent-selenium-examples 7 | 1.0-SNAPSHOT 8 | jar 9 | 10 | fluent-selenium examples 11 | 12 | 13 | UTF-8 14 | 15 | 16 | 17 | 18 | junit 19 | junit-dep 20 | 4.11 21 | test 22 | 23 | 24 | org.seleniumhq.selenium.fluent 25 | fluent-selenium 26 | 1.14 27 | test 28 | 29 | 30 | org.hamcrest 31 | hamcrest-all 32 | 1.3 33 | test 34 | 35 | 36 | com.codahale.metrics 37 | metrics-core 38 | 3.0.0 39 | 40 | 41 | 42 | 43 | 44 | org.apache.maven.plugins 45 | maven-surefire-plugin 46 | 47 | 48 | 49 | listener 50 | com.paulhammant.fluentSeleniumExamples.WholeSuiteListener 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /src/test/java/com/paulhammant/fluentSeleniumExamples/BasePage.java: -------------------------------------------------------------------------------- 1 | package com.paulhammant.fluentSeleniumExamples; 2 | 3 | import org.openqa.selenium.firefox.FirefoxDriver; 4 | import org.seleniumhq.selenium.fluent.FluentWebDriver; 5 | import org.seleniumhq.selenium.fluent.monitors.CompositeMonitor; 6 | import org.seleniumhq.selenium.fluent.monitors.HighlightOnError; 7 | import org.seleniumhq.selenium.fluent.monitors.ScreenShotOnError; 8 | 9 | public class BasePage extends FluentWebDriver { 10 | 11 | public BasePage(FirefoxDriver delegate) { 12 | super(delegate, 13 | new CompositeMonitor(WholeSuiteListener.codahaleMetricsMonitor, 14 | new HighlightOnError(delegate), 15 | new ScreenShotOnError.WithUnitTestFrameWorkContext(delegate, BasePage.class, "test-classes", "surefire-reports"))); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/test/java/com/paulhammant/fluentSeleniumExamples/WholeSuiteListener.java: -------------------------------------------------------------------------------- 1 | package com.paulhammant.fluentSeleniumExamples; 2 | 3 | import com.codahale.metrics.ConsoleReporter; 4 | import org.junit.runner.Result; 5 | import org.junit.runner.notification.RunListener; 6 | import org.seleniumhq.selenium.fluent.monitors.CodaHaleMetricsMonitor; 7 | 8 | import java.util.concurrent.TimeUnit; 9 | 10 | public class WholeSuiteListener extends RunListener { 11 | 12 | @Override 13 | public void testRunFinished(Result result) throws Exception { 14 | super.testRunFinished(result); 15 | 16 | final ConsoleReporter reporter = ConsoleReporter.forRegistry(codahaleMetricsMonitor.getMetrics()) 17 | .convertRatesTo(TimeUnit.MILLISECONDS) 18 | .convertDurationsTo(TimeUnit.MILLISECONDS) 19 | .outputTo(System.out) 20 | .build(); 21 | 22 | reporter.report(); 23 | 24 | } 25 | 26 | public static final CodaHaleMetricsMonitor codahaleMetricsMonitor = new CodaHaleMetricsMonitor("com.paulhammant.fluentSeleniumExamples."); 27 | } 28 | 29 | -------------------------------------------------------------------------------- /src/test/java/com/paulhammant/fluentSeleniumExamples/etsy/BuyAHatTest.java: -------------------------------------------------------------------------------- 1 | package com.paulhammant.fluentSeleniumExamples.etsy; 2 | 3 | import org.junit.After; 4 | import org.junit.Before; 5 | import org.junit.Test; 6 | import org.openqa.selenium.firefox.FirefoxDriver; 7 | 8 | public class BuyAHatTest { 9 | 10 | private FirefoxDriver wd; 11 | 12 | @Before 13 | public void makeWebDriverAndGotoSite() { 14 | wd = new FirefoxDriver(); 15 | wd.get("http://etsy.com"); 16 | } 17 | 18 | @After 19 | public void killWebDriver() { 20 | wd.quit(); 21 | } 22 | 23 | @Test 24 | public void adding_a_hat_to_the_cart() { 25 | 26 | new Home(wd) {{ 27 | searchFor().sendKeys("Hat"); 28 | searchButton().click(); 29 | }}; 30 | 31 | new SearchResults(wd) {{ 32 | numberMatchingSearchHeader().shouldMatch(".*\\d items.*"); 33 | firstNonSponsoredListing().link().click(); 34 | }}; 35 | 36 | new Listing(wd) {{ 37 | addToCartButton().click(); 38 | }}; 39 | 40 | new Cart(wd) {{ 41 | numberOfItemsInCartHeader().shouldContain("1 Item in Your Cart"); 42 | }}; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/test/java/com/paulhammant/fluentSeleniumExamples/etsy/Cart.java: -------------------------------------------------------------------------------- 1 | package com.paulhammant.fluentSeleniumExamples.etsy; 2 | 3 | import com.paulhammant.fluentSeleniumExamples.BasePage; 4 | import org.openqa.selenium.firefox.FirefoxDriver; 5 | import org.seleniumhq.selenium.fluent.TestableString; 6 | 7 | import static org.openqa.selenium.By.id; 8 | import static org.seleniumhq.selenium.fluent.Period.secs; 9 | 10 | public class Cart extends BasePage { 11 | public Cart(FirefoxDriver delegate) { 12 | super(delegate); 13 | url().within(secs(3)).shouldContain("etsy.com/cart/"); 14 | } 15 | 16 | protected TestableString numberOfItemsInCartHeader() { 17 | return div(id("checkout-header")).h1().getText(); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/test/java/com/paulhammant/fluentSeleniumExamples/etsy/Home.java: -------------------------------------------------------------------------------- 1 | package com.paulhammant.fluentSeleniumExamples.etsy; 2 | 3 | import com.paulhammant.fluentSeleniumExamples.BasePage; 4 | import org.openqa.selenium.firefox.FirefoxDriver; 5 | import org.seleniumhq.selenium.fluent.FluentWebElement; 6 | 7 | import static org.openqa.selenium.By.id; 8 | 9 | public class Home extends BasePage { 10 | public Home(FirefoxDriver delegate) { 11 | super(delegate); 12 | url().shouldMatch(".*etsy.com/"); 13 | } 14 | 15 | protected FluentWebElement searchButton() { 16 | return button(id("search_submit")); 17 | } 18 | 19 | protected FluentWebElement searchFor() { 20 | return input(id("search-query")); 21 | } 22 | 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/test/java/com/paulhammant/fluentSeleniumExamples/etsy/Listing.java: -------------------------------------------------------------------------------- 1 | package com.paulhammant.fluentSeleniumExamples.etsy; 2 | 3 | import com.paulhammant.fluentSeleniumExamples.BasePage; 4 | import org.openqa.selenium.firefox.FirefoxDriver; 5 | import org.seleniumhq.selenium.fluent.FluentWebElement; 6 | 7 | import static org.hamcrest.MatcherAssert.assertThat; 8 | import static org.hamcrest.Matchers.containsString; 9 | import static org.openqa.selenium.By.className; 10 | 11 | public class Listing extends BasePage { 12 | public Listing(FirefoxDriver delegate) { 13 | super(delegate); 14 | assertThat(delegate.getCurrentUrl(), containsString("etsy.com/listing/")); 15 | } 16 | 17 | protected FluentWebElement addToCartButton() { 18 | return button(className("btn-transaction")); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/test/java/com/paulhammant/fluentSeleniumExamples/etsy/SearchResults.java: -------------------------------------------------------------------------------- 1 | package com.paulhammant.fluentSeleniumExamples.etsy; 2 | 3 | import com.paulhammant.fluentSeleniumExamples.BasePage; 4 | import org.openqa.selenium.firefox.FirefoxDriver; 5 | import org.seleniumhq.selenium.fluent.FluentWebElement; 6 | import org.seleniumhq.selenium.fluent.TestableString; 7 | 8 | import static org.hamcrest.MatcherAssert.assertThat; 9 | import static org.hamcrest.Matchers.containsString; 10 | import static org.openqa.selenium.By.className; 11 | import static org.openqa.selenium.By.id; 12 | 13 | public class SearchResults extends BasePage { 14 | public SearchResults(FirefoxDriver delegate) { 15 | super(delegate); 16 | assertThat(delegate.getCurrentUrl(), containsString("/search?")); 17 | } 18 | 19 | protected FluentWebElement firstNonSponsoredListing() { 20 | return ul(className("listings")).lis().get(0); 21 | } 22 | 23 | protected TestableString numberMatchingSearchHeader() { 24 | return div(id("search-header")).h1().getText(); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/test/java/com/paulhammant/fluentSeleniumExamples/hipmunk/BookAFlightTest.java: -------------------------------------------------------------------------------- 1 | package com.paulhammant.fluentSeleniumExamples.hipmunk; 2 | 3 | import com.paulhammant.fluentSeleniumExamples.WholeSuiteListener; 4 | import org.junit.After; 5 | import org.junit.Before; 6 | import org.junit.Test; 7 | import org.openqa.selenium.WebDriver; 8 | import org.openqa.selenium.firefox.FirefoxDriver; 9 | import org.seleniumhq.selenium.fluent.FluentWebElement; 10 | import org.seleniumhq.selenium.fluent.Monitor; 11 | 12 | import java.util.Set; 13 | 14 | import static org.hamcrest.core.IsEqual.equalTo; 15 | import static org.junit.Assert.assertThat; 16 | 17 | public class BookAFlightTest { 18 | 19 | private FirefoxDriver wd; 20 | private Monitor.Timer bizOperationTiming; 21 | private int claimedUnitedPrice; 22 | private String hipmunkWindowHandle; 23 | 24 | @Before 25 | public void makeWebDriverAndGotoSite() { 26 | wd = new FirefoxDriver(); 27 | wd.get("http://hipmunk.com"); 28 | } 29 | 30 | @After 31 | public void killWebDriver() { 32 | wd.quit(); 33 | } 34 | 35 | @Test 36 | public void a_booking_through_to_united_affiliate() { 37 | 38 | new Home(wd) {{ 39 | fromAirportField().sendKeys("DAL"); 40 | waitForExpandoToComplete(); 41 | toAirportField().sendKeys("IAH"); 42 | timeBizOperation("DAL->IAH Initial Search Results"); 43 | searchButton().click(); 44 | }}; 45 | 46 | new SearchResults(wd) {{ 47 | waitForFlightListFor("DAL\nIAH"); 48 | bizOperationTiming.end(true); 49 | timeBizOperation("DAL->IAH Return Leg Search Results"); 50 | firstShownLeg().click(); 51 | waitForFlightListFor("IAH\nDAL"); 52 | bizOperationTiming.end(true); 53 | firstShownLeg().click(); 54 | 55 | new BookingOverlay(wd) {{ 56 | hipmunkWindowHandle = delegate.getWindowHandle(); 57 | FluentWebElement unitedRow = unitedRow(); 58 | claimedUnitedPrice = Integer.parseInt(unitedRow.div().getText().toString().replace("$", "")); 59 | timeBizOperation("DAL->IAH United.com Transfer"); 60 | unitedRow.link().click(); // purchase 61 | changeWebDriverWindow(delegate); 62 | }}; 63 | }}; 64 | 65 | new UnitedAirlinesBooking(wd) {{ 66 | float actualPrice = getActualPrice(); // includes cents 67 | assertThat("price", Math.round(actualPrice), equalTo(claimedUnitedPrice)); 68 | bizOperationTiming.end(true); 69 | }}; 70 | 71 | } 72 | 73 | private void changeWebDriverWindow(WebDriver driver) { 74 | Set handles = driver.getWindowHandles(); 75 | for (String popupHandle : handles) { 76 | if (!popupHandle.contains(hipmunkWindowHandle)) { 77 | driver.switchTo().window(popupHandle); 78 | } 79 | } 80 | } 81 | 82 | private void timeBizOperation(String description) { 83 | bizOperationTiming = WholeSuiteListener.codahaleMetricsMonitor.start(description + " (End User Experience)"); 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /src/test/java/com/paulhammant/fluentSeleniumExamples/hipmunk/BookingOverlay.java: -------------------------------------------------------------------------------- 1 | package com.paulhammant.fluentSeleniumExamples.hipmunk; 2 | 3 | import com.paulhammant.fluentSeleniumExamples.BasePage; 4 | import org.openqa.selenium.WebElement; 5 | import org.openqa.selenium.firefox.FirefoxDriver; 6 | import org.seleniumhq.selenium.fluent.FluentMatcher; 7 | import org.seleniumhq.selenium.fluent.FluentWebElement; 8 | 9 | import static org.openqa.selenium.By.className; 10 | import static org.seleniumhq.selenium.fluent.Period.secs; 11 | 12 | public class BookingOverlay extends BasePage { 13 | public BookingOverlay(FirefoxDriver delegate) { 14 | super(delegate); 15 | within(secs(8)).div(className("booking-info-container")); 16 | 17 | } 18 | 19 | protected FluentWebElement unitedRow() { 20 | return divs(className("booking-link-row")).first(new FluentMatcher() { 21 | public boolean matches(WebElement webElement) { 22 | return webElement.getText().contains("United"); 23 | } 24 | 25 | @Override 26 | public String toString() { 27 | return "Matches United Airlines"; 28 | } 29 | }); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/test/java/com/paulhammant/fluentSeleniumExamples/hipmunk/Home.java: -------------------------------------------------------------------------------- 1 | package com.paulhammant.fluentSeleniumExamples.hipmunk; 2 | 3 | import com.paulhammant.fluentSeleniumExamples.BasePage; 4 | import org.openqa.selenium.firefox.FirefoxDriver; 5 | import org.seleniumhq.selenium.fluent.FluentWebElement; 6 | 7 | import static org.openqa.selenium.By.id; 8 | import static org.seleniumhq.selenium.fluent.Period.secs; 9 | 10 | public class Home extends BasePage { 11 | public Home(FirefoxDriver delegate) { 12 | super(delegate); 13 | url().shouldMatch(".*hipmunk.com/"); 14 | } 15 | 16 | protected void waitForExpandoToComplete() { 17 | div(id("flight-search")).getAttribute("class").within(secs(3)).shouldContain("expanded"); 18 | } 19 | 20 | protected FluentWebElement searchButton() { 21 | return form(id("flight")).button(); 22 | } 23 | 24 | protected FluentWebElement toAirportField() { 25 | return input(id("fac2flight")); 26 | } 27 | 28 | protected FluentWebElement fromAirportField() { 29 | return input(id("fac1flight")); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/test/java/com/paulhammant/fluentSeleniumExamples/hipmunk/SearchResults.java: -------------------------------------------------------------------------------- 1 | package com.paulhammant.fluentSeleniumExamples.hipmunk; 2 | 3 | import com.paulhammant.fluentSeleniumExamples.BasePage; 4 | import org.openqa.selenium.firefox.FirefoxDriver; 5 | import org.seleniumhq.selenium.fluent.FluentWebElement; 6 | 7 | import static org.openqa.selenium.By.className; 8 | import static org.openqa.selenium.By.id; 9 | import static org.seleniumhq.selenium.fluent.Period.secs; 10 | 11 | public class SearchResults extends BasePage { 12 | public SearchResults(FirefoxDriver delegate) { 13 | super(delegate); 14 | within(secs(2)).url().shouldContain("hipmunk.com/flights/"); 15 | 16 | // move past interstitial 17 | within(secs(20)).div(id("sub-graph-1")); 18 | } 19 | 20 | protected void waitForFlightListFor(final String flights) { 21 | div(id("leg-selector-1")).div(className("selected")).getText().within(secs(2)).shouldMatch(flights + ".*"); 22 | } 23 | 24 | protected FluentWebElement firstShownLeg() { 25 | return div(className("select-leg")); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/test/java/com/paulhammant/fluentSeleniumExamples/hipmunk/UnitedAirlinesBooking.java: -------------------------------------------------------------------------------- 1 | package com.paulhammant.fluentSeleniumExamples.hipmunk; 2 | 3 | import com.paulhammant.fluentSeleniumExamples.BasePage; 4 | import org.openqa.selenium.firefox.FirefoxDriver; 5 | 6 | import static org.openqa.selenium.By.className; 7 | import static org.openqa.selenium.By.id; 8 | import static org.seleniumhq.selenium.fluent.Period.secs; 9 | 10 | public class UnitedAirlinesBooking extends BasePage { 11 | public UnitedAirlinesBooking(FirefoxDriver delegate) { 12 | super(delegate); 13 | // move past a few redirects to the page in question 14 | within(secs(20)).url().shouldMatch("united\\.com\\/web\\/.*\\/apps\\/booking"); 15 | within(secs(15)).div(className("priceContinerB")); 16 | } 17 | 18 | public float getActualPrice() { 19 | return Float.parseFloat(td(id("ctl00_ContentInfo_priceRevenueSummary_Price_ctl02_tdDisplayValue")).getText().toString().replace("\n", "").replace("$", "").trim()); 20 | } 21 | 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/test/java/com/paulhammant/fluentSeleniumExamples/jimmyjohns/CustomizeYourOrder.java: -------------------------------------------------------------------------------- 1 | package com.paulhammant.fluentSeleniumExamples.jimmyjohns; 2 | 3 | import com.paulhammant.fluentSeleniumExamples.BasePage; 4 | import org.openqa.selenium.firefox.FirefoxDriver; 5 | import org.seleniumhq.selenium.fluent.TestableString; 6 | 7 | import static com.paulhammant.fluentSeleniumExamples.jimmyjohns.Home.ngWait; 8 | import static org.openqa.selenium.By.className; 9 | 10 | public class CustomizeYourOrder extends BasePage { 11 | 12 | public CustomizeYourOrder(FirefoxDriver wd) { 13 | super(wd); 14 | div(ngWait(className("headingBar"))).getText().shouldContain("CUSTOMIZE YOUR ORDER"); 15 | } 16 | 17 | public TestableString sandwichName() { 18 | return span(className("sandwichName")).getText(); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/test/java/com/paulhammant/fluentSeleniumExamples/jimmyjohns/Home.java: -------------------------------------------------------------------------------- 1 | package com.paulhammant.fluentSeleniumExamples.jimmyjohns; 2 | 3 | import com.paulhammant.fluentSeleniumExamples.BasePage; 4 | import org.openqa.selenium.By; 5 | import org.openqa.selenium.JavascriptExecutor; 6 | import org.openqa.selenium.SearchContext; 7 | import org.openqa.selenium.WebDriver; 8 | import org.openqa.selenium.WebElement; 9 | import org.openqa.selenium.firefox.FirefoxDriver; 10 | import org.seleniumhq.selenium.fluent.FluentBy; 11 | import org.seleniumhq.selenium.fluent.FluentWebElement; 12 | 13 | import java.util.List; 14 | import java.util.concurrent.TimeUnit; 15 | 16 | import static org.openqa.selenium.By.className; 17 | import static org.openqa.selenium.By.id; 18 | 19 | public class Home extends BasePage { 20 | 21 | public Home(FirefoxDriver delegate) { 22 | super(delegate); 23 | div(className("startAnOrder")); 24 | } 25 | 26 | protected FluentWebElement deliveryOption() { 27 | return h2(id("newDeliveryOrderBtn")); 28 | } 29 | 30 | protected FluentWebElement addressField() { 31 | return input(id("placesInput")); 32 | } 33 | 34 | protected FluentWebElement firstOfferedAddress() { 35 | return div(ngWait(className("pac-container"))).div(); 36 | } 37 | 38 | protected FluentWebElement newDeliveryButton() { 39 | return link(id("submitNewDeliveryAddressBtn")); 40 | } 41 | 42 | public static By ngWait(final By by) { 43 | return new FluentBy() { 44 | @Override 45 | public void beforeFindElement(WebDriver driver) { 46 | driver.manage().timeouts().setScriptTimeout(30, TimeUnit.SECONDS); 47 | ((JavascriptExecutor) driver).executeAsyncScript("var callback = arguments[arguments.length - 1];" + 48 | "angular.element(document.body).injector().get('$browser').notifyWhenNoOutstandingRequests(callback);"); 49 | super.beforeFindElement(driver); 50 | } 51 | 52 | @Override 53 | public List findElements(SearchContext context) { 54 | return by.findElements(context); 55 | } 56 | 57 | @Override 58 | public WebElement findElement(SearchContext context) { 59 | return by.findElement(context); 60 | } 61 | 62 | @Override 63 | public String toString() { 64 | return "ngWait(" + by.toString() + ")"; 65 | } 66 | }; 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /src/test/java/com/paulhammant/fluentSeleniumExamples/jimmyjohns/JimmyJohnsTest.java: -------------------------------------------------------------------------------- 1 | package com.paulhammant.fluentSeleniumExamples.jimmyjohns; 2 | 3 | import org.junit.After; 4 | import org.junit.Before; 5 | import org.junit.Test; 6 | import org.openqa.selenium.firefox.FirefoxDriver; 7 | 8 | public class JimmyJohnsTest { 9 | 10 | private FirefoxDriver wd; 11 | 12 | @Before 13 | public void makeWebDriverAndGotoSite() { 14 | wd = new FirefoxDriver(); 15 | wd.get("https://online.jimmyjohns.com"); 16 | } 17 | 18 | @After 19 | public void killWebDriver() { 20 | wd.quit(); 21 | } 22 | 23 | @Test 24 | public void order_a_large_sarnie() { 25 | 26 | new Home(wd) {{ 27 | deliveryOption().click(); 28 | addressField().sendKeys("1600 Pennsylvania Ave NW, Washington"); 29 | addressField().click(); 30 | firstOfferedAddress().click(); 31 | newDeliveryButton().click(); 32 | }}; 33 | 34 | new VerifyAddress(wd) {{ 35 | confirmButton().click(); 36 | }}; 37 | 38 | final String sarnie = "THE J.J. GARGANTUAN®"; 39 | 40 | new Menu(wd) {{ 41 | selectItem(sarnie); 42 | }}; 43 | 44 | new CustomizeYourOrder(wd) {{ 45 | sandwichName().shouldBe(sarnie); 46 | }}; 47 | 48 | // Stop here as we don't want The Secret Service calling. 49 | 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /src/test/java/com/paulhammant/fluentSeleniumExamples/jimmyjohns/Menu.java: -------------------------------------------------------------------------------- 1 | package com.paulhammant.fluentSeleniumExamples.jimmyjohns; 2 | 3 | import com.paulhammant.fluentSeleniumExamples.BasePage; 4 | import org.openqa.selenium.By; 5 | import org.openqa.selenium.WebElement; 6 | import org.openqa.selenium.firefox.FirefoxDriver; 7 | import org.seleniumhq.selenium.fluent.FluentMatcher; 8 | 9 | import static com.paulhammant.fluentSeleniumExamples.jimmyjohns.Home.ngWait; 10 | import static org.seleniumhq.selenium.fluent.FluentBy.attribute; 11 | 12 | public class Menu extends BasePage { 13 | public Menu(FirefoxDriver wd) { 14 | super(wd); 15 | div(ngWait(attribute("ng-controller", "MenuController"))).getText().shouldContain("JJ'S MENU"); 16 | } 17 | 18 | public void selectItem(final String name) { 19 | spans(By.className("catHeadCopy")).first(new HasText(name)).click(); 20 | links(By.className("menuItem")).first(new HasText(name)).click(); 21 | } 22 | 23 | private static class HasText implements FluentMatcher { 24 | private final String name; 25 | 26 | public HasText(String name) { 27 | this.name = name; 28 | } 29 | 30 | public boolean matches(WebElement webElement) { 31 | return webElement.getText().contains(name); 32 | } 33 | 34 | @Override 35 | public String toString() { 36 | return "HasText: " + name; 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/test/java/com/paulhammant/fluentSeleniumExamples/jimmyjohns/VerifyAddress.java: -------------------------------------------------------------------------------- 1 | package com.paulhammant.fluentSeleniumExamples.jimmyjohns; 2 | 3 | import com.paulhammant.fluentSeleniumExamples.BasePage; 4 | import org.openqa.selenium.firefox.FirefoxDriver; 5 | import org.seleniumhq.selenium.fluent.FluentWebElement; 6 | 7 | import static com.paulhammant.fluentSeleniumExamples.jimmyjohns.Home.ngWait; 8 | import static org.openqa.selenium.By.className; 9 | import static org.openqa.selenium.By.id; 10 | 11 | public class VerifyAddress extends BasePage { 12 | 13 | public VerifyAddress(FirefoxDriver wd) { 14 | super(wd); 15 | div(ngWait(className("headingBar"))).getText().shouldContain("VERIFY ADDRESS"); 16 | } 17 | 18 | public FluentWebElement confirmButton() { 19 | return link(id("confirmDeliveryAddressBtn")); 20 | } 21 | 22 | } 23 | --------------------------------------------------------------------------------