site_prism 0.9.9 → 1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +962 -0
- data/lib/site_prism/element_container.rb +0 -66
- data/lib/site_prism/exceptions.rb +0 -4
- data/lib/site_prism/page.rb +0 -51
- data/lib/site_prism/section.rb +0 -4
- data/lib/site_prism/version.rb +2 -1
- metadata +3 -2
data/README.md
ADDED
@@ -0,0 +1,962 @@
|
|
1
|
+
# SitePrism
|
2
|
+
_A Page Object Model DSL for Capybara_
|
3
|
+
|
4
|
+
SitePrism gives you a simple, clean and semantic DSL for describing your site using the Page Object Model pattern, for use with Capybara in automated acceptance testing.
|
5
|
+
|
6
|
+
Find the pretty documentation here: http://rdoc.info/gems/site_prism/frames
|
7
|
+
|
8
|
+
## Synopsis
|
9
|
+
|
10
|
+
Here's an overview of how SitePrism is designed to be used:
|
11
|
+
|
12
|
+
```ruby
|
13
|
+
# define our site's pages
|
14
|
+
|
15
|
+
class Home < SitePrism::Page
|
16
|
+
set_url "http://www.google.com"
|
17
|
+
set_url_matcher /google.com\/?/
|
18
|
+
|
19
|
+
element :search_field, "input[name='q']"
|
20
|
+
element :search_button, "button[name='btnK']"
|
21
|
+
elements :footer_links, "#footer a"
|
22
|
+
section :menu, MenuSection, "#gbx3"
|
23
|
+
end
|
24
|
+
|
25
|
+
class SearchResults < SitePrism::Page
|
26
|
+
set_url_matcher /google.com\/results\?.*/
|
27
|
+
|
28
|
+
section :menu, MenuSection, "#gbx3"
|
29
|
+
sections :search_results, SearchResultSection, "#results li"
|
30
|
+
end
|
31
|
+
|
32
|
+
# define sections used on multiple pages or multiple times on one page
|
33
|
+
|
34
|
+
class MenuSection < SitePrism::Section
|
35
|
+
element :search, "a.search"
|
36
|
+
element :images, "a.image-search"
|
37
|
+
element :maps, "a.map-search"
|
38
|
+
end
|
39
|
+
|
40
|
+
class SearchResultSection < SitePrism::Section
|
41
|
+
element :title, "a.title"
|
42
|
+
element :blurb, "span.result-decription"
|
43
|
+
end
|
44
|
+
|
45
|
+
# now for some tests
|
46
|
+
|
47
|
+
When /^I navigate to the google home page$/ do
|
48
|
+
@home = Home.new
|
49
|
+
@home.load
|
50
|
+
end
|
51
|
+
|
52
|
+
Then /^the home page should contain the menu and the search form$/ do
|
53
|
+
@home.wait_for_menu # menu loads after a second or 2, give it time to arrive
|
54
|
+
@home.should have_menu
|
55
|
+
@home.should have_search_field
|
56
|
+
@home.should have_search_button
|
57
|
+
end
|
58
|
+
|
59
|
+
When /^I search for Sausages$/ do
|
60
|
+
@home.search_field.set "Sausages"
|
61
|
+
@home.search_button.click
|
62
|
+
end
|
63
|
+
|
64
|
+
Then /^the search results page is displayed$/ do
|
65
|
+
@results_page = SearchResults.new
|
66
|
+
@results_page.should be_displayed
|
67
|
+
end
|
68
|
+
|
69
|
+
Then /^the search results page contains 10 individual search results$/ do
|
70
|
+
@results_page.wait_for_search_results
|
71
|
+
@results_page.should have_search_results
|
72
|
+
@results_page.search_results.size.should == 10
|
73
|
+
end
|
74
|
+
|
75
|
+
Then /^the search results contain a link to the wikipedia sausages page$/ do
|
76
|
+
@results_page.search_results.map {|sr| sr.title['href']}.should include "http://en.wikipedia.org/wiki/Sausage"
|
77
|
+
end
|
78
|
+
```
|
79
|
+
|
80
|
+
Now for the details...
|
81
|
+
|
82
|
+
## Setup
|
83
|
+
|
84
|
+
### Installation
|
85
|
+
|
86
|
+
To install SitePrism:
|
87
|
+
|
88
|
+
```bash
|
89
|
+
gem install site_prism
|
90
|
+
```
|
91
|
+
|
92
|
+
### Using SitePrism with Cucumber
|
93
|
+
|
94
|
+
If you are using cucumber, here's what needs requiring:
|
95
|
+
|
96
|
+
```ruby
|
97
|
+
require 'capybara'
|
98
|
+
require 'capybara/dsl'
|
99
|
+
require 'capybara/cucumber'
|
100
|
+
require 'selenium-webdriver'
|
101
|
+
require 'site_prism'
|
102
|
+
```
|
103
|
+
|
104
|
+
### Using SitePrism with RSpec
|
105
|
+
|
106
|
+
If you're using rspec instead, here's what needs requiring:
|
107
|
+
|
108
|
+
```ruby
|
109
|
+
require 'capybara'
|
110
|
+
require 'capybara/dsl'
|
111
|
+
require 'capybara/rspec'
|
112
|
+
require 'selenium-webdriver'
|
113
|
+
require 'site_prism'
|
114
|
+
```
|
115
|
+
|
116
|
+
## Introduction to the Page Object Model
|
117
|
+
|
118
|
+
The Page Object Model is a test automation pattern that aims to create
|
119
|
+
an abstraction of your site's user interface that can be used in tests.
|
120
|
+
The most common way to do this is to model each page as a class, and
|
121
|
+
to then use instances of those classes in your tests.
|
122
|
+
|
123
|
+
If a class represents a page then each element of the page is
|
124
|
+
represented by a method that, when called, returns a reference to that
|
125
|
+
element that can then be acted upon (clicked, set text value), or
|
126
|
+
queried (is it enabled? visible?).
|
127
|
+
|
128
|
+
SitePrism is based around this concept, but goes further as you'll see
|
129
|
+
below by also allowing modelling of repeated sections that appear on
|
130
|
+
muliple pages, or many times on a page using the concept of sections.
|
131
|
+
|
132
|
+
## Pages
|
133
|
+
|
134
|
+
As you might be able to guess from the name, pages are fairly central to
|
135
|
+
the Page Object Model. Here's how SitePrism models them:
|
136
|
+
|
137
|
+
### Creating a Page Model
|
138
|
+
|
139
|
+
The simplest page is one that has nothing defined in it. Here's an
|
140
|
+
example of how to begin modelling a home page:
|
141
|
+
|
142
|
+
```ruby
|
143
|
+
class Home < SitePrism::Page
|
144
|
+
end
|
145
|
+
```
|
146
|
+
|
147
|
+
The above has nothing useful defined, only the name.
|
148
|
+
|
149
|
+
### Adding a URL
|
150
|
+
|
151
|
+
A page usually has a URL. If you want to be able to navigate to a page,
|
152
|
+
you'll need to set its URL. Here's how:
|
153
|
+
|
154
|
+
```ruby
|
155
|
+
class Home < SitePrism::Page
|
156
|
+
set_url "http://www.google.com"
|
157
|
+
end
|
158
|
+
```
|
159
|
+
|
160
|
+
Note that setting a URL is optional - you only need to set a url if you want to be able to navigate
|
161
|
+
directly to that page. It makes sense to set the URL for a page model of a home
|
162
|
+
page or a login page, but probably not a search results page.
|
163
|
+
|
164
|
+
### Navigating to the Page
|
165
|
+
|
166
|
+
Once the URL has been set (using `set_url`), you can navigate directly
|
167
|
+
to the page using `#load`:
|
168
|
+
|
169
|
+
```ruby
|
170
|
+
@home_page = Home.new
|
171
|
+
@home_page.load
|
172
|
+
```
|
173
|
+
|
174
|
+
This will tell which ever capybara driver you have configured to
|
175
|
+
navigate to the URL set against that page's class.
|
176
|
+
|
177
|
+
### Verifying that a particular page is displayed
|
178
|
+
|
179
|
+
Automated tests often need to verify that a particular page is
|
180
|
+
displayed. Intuitively you'd think that simply checking that the URL
|
181
|
+
defined using `set_url` is the current page in the browser would be enough, but experience shows that it's
|
182
|
+
not. It is far more robust to check to see if the browser's current url
|
183
|
+
matches a regular expression. For example, though `account/1` and `account/2`
|
184
|
+
are the same page, their URLs are different. To deal with this,
|
185
|
+
SitePrism provides the ability to set a URL matcher.
|
186
|
+
|
187
|
+
```ruby
|
188
|
+
class Account < SitePrism::Page
|
189
|
+
set_url_matcher /\account\/\d+/
|
190
|
+
end
|
191
|
+
```
|
192
|
+
|
193
|
+
Once a URL matcher is set for a page, you can test to see if it is
|
194
|
+
displayed:
|
195
|
+
|
196
|
+
```ruby
|
197
|
+
@account_page = Account.new
|
198
|
+
#...
|
199
|
+
@account_page.displayed? #=> true or false
|
200
|
+
```
|
201
|
+
|
202
|
+
Calling `#displayed?` will return true if the browser's current URL
|
203
|
+
matches the regular expression for the page and false if it doesn't. So
|
204
|
+
in the above example (`account/1` and `account/2`), calling
|
205
|
+
`@account_page.displayed?` will return true for both examples.
|
206
|
+
|
207
|
+
#### Testing for Page display
|
208
|
+
|
209
|
+
SitePrism's `#displayed?` predicate method allows for semantic code in
|
210
|
+
your test:
|
211
|
+
|
212
|
+
```ruby
|
213
|
+
Then /^the account page is displayed$/ do
|
214
|
+
@account_page.should be_displayed
|
215
|
+
@some_other_page.should_not be_displayed
|
216
|
+
end
|
217
|
+
```
|
218
|
+
|
219
|
+
Another example that demonstrates why using regex instead of string
|
220
|
+
comparison for URL checking is when you want to be able to run your
|
221
|
+
tests across multiple environments.
|
222
|
+
|
223
|
+
```ruby
|
224
|
+
class Login < SitePrism::Page
|
225
|
+
set_url "#{$test_environment}.example.com/login" #=> global var used for demonstration purposes only!!!
|
226
|
+
set_url_matcher /(?:dev|test|www)\.example\.com\/login/
|
227
|
+
end
|
228
|
+
```
|
229
|
+
|
230
|
+
The above example would work for `dev.example.com/login`,
|
231
|
+
`test.example.com/login` and `www.example.com/login`; now your tests
|
232
|
+
aren't limited to one environment but can verify that they are on the
|
233
|
+
correct page regardless of the environment the tests are being executed
|
234
|
+
against.
|
235
|
+
|
236
|
+
#### Page Title
|
237
|
+
|
238
|
+
Getting a page's title isn't hard:
|
239
|
+
|
240
|
+
```ruby
|
241
|
+
class Account < SitePrism::Page
|
242
|
+
end
|
243
|
+
|
244
|
+
@account = Account.new
|
245
|
+
#...
|
246
|
+
@account.title #=> "Welcome to Your Account"
|
247
|
+
```
|
248
|
+
|
249
|
+
## Elements
|
250
|
+
|
251
|
+
Pages are made up of elements (text fields, buttons, combo boxes, etc),
|
252
|
+
either individual elements or groups of them. Examples of individual
|
253
|
+
elements would be a search field or a company logo image; examples of
|
254
|
+
element collections would be items in any sort of list, eg: menu items,
|
255
|
+
images in a carousel, etc.
|
256
|
+
|
257
|
+
### Individual Elements
|
258
|
+
|
259
|
+
To interact with individual elements, they need to be defined as part of
|
260
|
+
the relevant page. SitePrism makes this easy:
|
261
|
+
|
262
|
+
```ruby
|
263
|
+
class Home < SitePrism::Page
|
264
|
+
element :search_field, "input[name='q']"
|
265
|
+
end
|
266
|
+
```
|
267
|
+
|
268
|
+
Here we're adding a search field to the Home page. The `element` method
|
269
|
+
takes 2 arguments: the name of the element as a symbol, and a css selector
|
270
|
+
as a string.
|
271
|
+
|
272
|
+
#### Accessing the individual element
|
273
|
+
|
274
|
+
The `element` method will add a number of methods to instances of the
|
275
|
+
particular Page class. The first method to be added is the name of the
|
276
|
+
element. So using the following example:
|
277
|
+
|
278
|
+
```ruby
|
279
|
+
class Home < SitePrism::Page
|
280
|
+
set_url "http://www.google.com"
|
281
|
+
|
282
|
+
element :search_field, "input[name='q']"
|
283
|
+
end
|
284
|
+
```
|
285
|
+
|
286
|
+
... the following shows how to get hold of the search field:
|
287
|
+
|
288
|
+
```ruby
|
289
|
+
@home_page = Home.new
|
290
|
+
@home.load
|
291
|
+
|
292
|
+
@home.search_field #=> will return the capybara element found using the selector
|
293
|
+
@home.search_field.set "the search string" #=> since search_field returns a capybara element, you can use the capybara API to deal with it
|
294
|
+
@home.search_field.text #=> standard method on a capybara element; returns a string
|
295
|
+
```
|
296
|
+
|
297
|
+
#### Testing for the existence of the element
|
298
|
+
|
299
|
+
Another method added to the Page class by the `element` method is the
|
300
|
+
`has_<element name>?` method. Using the same example as above:
|
301
|
+
|
302
|
+
```ruby
|
303
|
+
class Home < SitePrism::Page
|
304
|
+
set_url "http://www.google.com"
|
305
|
+
|
306
|
+
element :search_field, "input[name='q']"
|
307
|
+
end
|
308
|
+
```
|
309
|
+
|
310
|
+
... you can test for the existence of the element on the page like this:
|
311
|
+
|
312
|
+
```ruby
|
313
|
+
@home_page = Home.new
|
314
|
+
@home.load
|
315
|
+
@home.has_search_field? #=> returns true if it exists, false if it doesn't
|
316
|
+
```
|
317
|
+
|
318
|
+
...which makes for nice test code:
|
319
|
+
|
320
|
+
```ruby
|
321
|
+
Then /^the search field exists$/ do
|
322
|
+
@home.should have_search_field
|
323
|
+
end
|
324
|
+
```
|
325
|
+
|
326
|
+
#### Waiting for an element to appear on a page
|
327
|
+
|
328
|
+
The final method added by calling `element` is the `wait_for_<element_name>` method.
|
329
|
+
Calling the method will cause the test to wait for the Capybara's
|
330
|
+
default wait time for the element to exist. It is also possible to use a
|
331
|
+
custom amount of time to wait. Using the same example as above:
|
332
|
+
|
333
|
+
```ruby
|
334
|
+
class Home < SitePrism::Page
|
335
|
+
set_url "http://www.google.com"
|
336
|
+
|
337
|
+
element :search_field, "input[name='q']"
|
338
|
+
end
|
339
|
+
```
|
340
|
+
|
341
|
+
... you can wait for the search field to exist like this:
|
342
|
+
|
343
|
+
```ruby
|
344
|
+
@home_page = Home.new
|
345
|
+
@home.load
|
346
|
+
@home.wait_for_search_field
|
347
|
+
# or...
|
348
|
+
@home.wait_for_search_field(10) #will wait for 10 seconds for the search field to appear
|
349
|
+
```
|
350
|
+
|
351
|
+
#### Summary of what the element method provides:
|
352
|
+
|
353
|
+
Given:
|
354
|
+
|
355
|
+
```ruby
|
356
|
+
class Home < SitePrism::Page
|
357
|
+
element :search_field, "input[name='q']"
|
358
|
+
end
|
359
|
+
```
|
360
|
+
|
361
|
+
...then the following methods are available:
|
362
|
+
|
363
|
+
```ruby
|
364
|
+
@home.search_field
|
365
|
+
@home.has_search_field?
|
366
|
+
@home.wait_for_search_field
|
367
|
+
@home.wait_for_search_field(10)
|
368
|
+
```
|
369
|
+
|
370
|
+
### Element Collections
|
371
|
+
|
372
|
+
Sometimes you don't want to deal with an individual element but rather
|
373
|
+
with a collection of similar elements, for example, a list of names. To
|
374
|
+
enable this, SitePrism provides the `elements` method on the Page class.
|
375
|
+
Here's how it works:
|
376
|
+
|
377
|
+
```ruby
|
378
|
+
class Friends < SitePrism::Page
|
379
|
+
elements :names, "ul#names li a"
|
380
|
+
end
|
381
|
+
```
|
382
|
+
|
383
|
+
Just like the `element` method, the `elements` method takes 2 arguments:
|
384
|
+
the first being the name of the elements as a symbol, the second is the
|
385
|
+
css selector that would return the array of capybara elements.
|
386
|
+
|
387
|
+
#### Accessing the elements
|
388
|
+
|
389
|
+
Just like the `element` method, the `elements` method adds a few methods
|
390
|
+
to the Page class. The first one is of the name of the element
|
391
|
+
collection which returns an array of capybara elements that match the
|
392
|
+
css selector. Using the example above:
|
393
|
+
|
394
|
+
```ruby
|
395
|
+
class Friends < SitePrism::Page
|
396
|
+
elements :names, "ul#names li a"
|
397
|
+
end
|
398
|
+
```
|
399
|
+
|
400
|
+
You can access the element collection like this:
|
401
|
+
|
402
|
+
```ruby
|
403
|
+
@friends_page = Friends.new
|
404
|
+
# ...
|
405
|
+
@friends_page.names #=> [<Capybara::Element>, <Capybara::Element>, <Capybara::Element>]
|
406
|
+
```
|
407
|
+
|
408
|
+
With that you can do all the normal things that are possible with
|
409
|
+
arrays:
|
410
|
+
|
411
|
+
|
412
|
+
```ruby
|
413
|
+
@friends_page.names.each {|name| puts name.text}
|
414
|
+
@friends_page.names.map {|name| name.text}.should == ["Alice", "Bob", "Fred"]
|
415
|
+
@friends_page.names.size.should == 3
|
416
|
+
```
|
417
|
+
|
418
|
+
#### Testing for the existence of the element collection
|
419
|
+
|
420
|
+
Just like the `element` method, the `elements` method adds a method to
|
421
|
+
the page that will allow you to check for the existence of the
|
422
|
+
collection, called `has_<element collection name>?`. As long as there is
|
423
|
+
at least 1 element in the array, the method will return true, otherwise
|
424
|
+
false. For example, with the following page:
|
425
|
+
|
426
|
+
```ruby
|
427
|
+
class Friends < SitePrism::Page
|
428
|
+
elements :names, "ul#names li a"
|
429
|
+
end
|
430
|
+
```
|
431
|
+
|
432
|
+
... the following method is available:
|
433
|
+
|
434
|
+
```ruby
|
435
|
+
@friends_page.has_names? #=> returns true if at least one element is found using the relevant selector
|
436
|
+
```
|
437
|
+
|
438
|
+
...which allows for pretty test code:
|
439
|
+
|
440
|
+
```ruby
|
441
|
+
Then /^there should be some names listed on the page$/ do
|
442
|
+
@friends_page.should have_names
|
443
|
+
end
|
444
|
+
```
|
445
|
+
|
446
|
+
#### Waiting for the element collection
|
447
|
+
|
448
|
+
Just like for an individual element, the tests can be told to wait for
|
449
|
+
the existence of the element collection. The `elements` method adds a
|
450
|
+
`wait_for_<element collection name>` method that will wait for
|
451
|
+
Capybara's default wait time until at least 1 element is found that
|
452
|
+
matches the selector. For example, with the following page:
|
453
|
+
|
454
|
+
```ruby
|
455
|
+
class Friends < SitePrism::Page
|
456
|
+
elements :names, "ul#names li a"
|
457
|
+
end
|
458
|
+
|
459
|
+
```
|
460
|
+
|
461
|
+
... you can wait for the existence of a list of names like this:
|
462
|
+
|
463
|
+
```ruby
|
464
|
+
@friends_page.wait_for_names
|
465
|
+
```
|
466
|
+
|
467
|
+
Again, you can customise the wait time by supplying a number of seconds
|
468
|
+
to wait for:
|
469
|
+
|
470
|
+
```ruby
|
471
|
+
@friends_page.wait_for_names(10)
|
472
|
+
```
|
473
|
+
|
474
|
+
### Checking that all mapped elements are present on the page
|
475
|
+
|
476
|
+
Throughout my time in test automation I keep getting asked to provide the
|
477
|
+
ability to check that all elements that should be on the page are on the
|
478
|
+
page. Why people would want to test this, I don't know. But if that's
|
479
|
+
what you want to do, SitePrism provides the `#all_there?` method that
|
480
|
+
will return true if all mapped elements (and sections... see below) are
|
481
|
+
present in the browser, false if they're not all there.
|
482
|
+
|
483
|
+
```ruby
|
484
|
+
@friends_page.all_there? #=> true/false
|
485
|
+
|
486
|
+
# and...
|
487
|
+
|
488
|
+
Then /^the friends page contains all the expected elements$/ do
|
489
|
+
@friends_page.should be_all_there
|
490
|
+
end
|
491
|
+
|
492
|
+
```
|
493
|
+
|
494
|
+
## Sections
|
495
|
+
|
496
|
+
SitePrism allows you to model sections of a page that appear on multiple
|
497
|
+
pages or that appear a number of times on a page separately from Pages.
|
498
|
+
SitePrism provides the Section class for this task.
|
499
|
+
|
500
|
+
### Individual Sections
|
501
|
+
|
502
|
+
In the same way that SitePrism provides `element` and `elements`, it
|
503
|
+
provides `section` and `sections`. The first returns an instance of a
|
504
|
+
page section, the secont returns an array of section instances, one for
|
505
|
+
each capybara element found by the supplied css selector. What follows
|
506
|
+
is an explanation of `section`.
|
507
|
+
|
508
|
+
|
509
|
+
#### Defining a Section
|
510
|
+
|
511
|
+
A section is similar to a page in that it inherits from a SitePrism
|
512
|
+
class:
|
513
|
+
|
514
|
+
```ruby
|
515
|
+
class MenuSection < SitePrism::Section
|
516
|
+
end
|
517
|
+
```
|
518
|
+
|
519
|
+
At the moment, this section does nothing.
|
520
|
+
|
521
|
+
#### Adding a section to a page
|
522
|
+
|
523
|
+
Pages include sections that's how SitePrism works. Here's a page that
|
524
|
+
includes the above `MenuSection` section:
|
525
|
+
|
526
|
+
```ruby
|
527
|
+
class Home < SitePrism::Page
|
528
|
+
section :menu, MenuSection, "#gbx3"
|
529
|
+
end
|
530
|
+
```
|
531
|
+
|
532
|
+
The way to add a section to a page (or another section -
|
533
|
+
SitePrism allows adding sections to sections) is to call the `section`
|
534
|
+
method. It takes 3 arguments: the first is the name of the section as
|
535
|
+
referred to on the page (sections that appear on multiple pages can be
|
536
|
+
named differently). The second argument is the class of which an
|
537
|
+
instance will be created to represent the page section, and the third
|
538
|
+
argument is a css selector that identifies the root node of the section
|
539
|
+
on this page (note that the css selector can be different for different
|
540
|
+
pages as the whole point of sections is that they can appear in
|
541
|
+
different places on different pages).
|
542
|
+
|
543
|
+
#### Accessing a page's section
|
544
|
+
|
545
|
+
The `section` method (like the `element` method) adds a few methods to
|
546
|
+
the page or section class it was called against. The first method that
|
547
|
+
is added is one that returns an instance of the section, the method name
|
548
|
+
being the first argument to the `section` method. Here's an example:
|
549
|
+
|
550
|
+
```ruby
|
551
|
+
# the section:
|
552
|
+
|
553
|
+
class MenuSection < SitePrism::Section
|
554
|
+
end
|
555
|
+
|
556
|
+
# the page that includes the section:
|
557
|
+
|
558
|
+
class Home < SitePrism::Page
|
559
|
+
section :menu, MenuSection, "#gbx3"
|
560
|
+
end
|
561
|
+
|
562
|
+
# the page and section in action:
|
563
|
+
|
564
|
+
@home = Home.new
|
565
|
+
@home.menu #=> <MenuSection...>
|
566
|
+
```
|
567
|
+
|
568
|
+
When the `menu` method is called against `@home`, an instance of
|
569
|
+
`MenuSection` (the second argument to the `section` method) is returned.
|
570
|
+
The third argument that is passed to the `section` method is the css
|
571
|
+
selector that will be used to find the root element of the section; this
|
572
|
+
root node becomes the 'scope' of the section.
|
573
|
+
|
574
|
+
The following shows that though the same section can appear on multiple
|
575
|
+
pages, it can take a different root node:
|
576
|
+
|
577
|
+
```ruby
|
578
|
+
# define the section that appears on both pages
|
579
|
+
|
580
|
+
class MenuSection < SitePrism::Section
|
581
|
+
end
|
582
|
+
|
583
|
+
# define 2 pages, each containing the same section
|
584
|
+
|
585
|
+
class Home < SitePrism::Page
|
586
|
+
section :menu, MenuSection, "#gbx3"
|
587
|
+
end
|
588
|
+
|
589
|
+
class SearchResults < SitePrism::Page
|
590
|
+
section :menu, MenuSection, "#gbx48"
|
591
|
+
end
|
592
|
+
```
|
593
|
+
|
594
|
+
You can see that the `MenuSection` is used in both the `Home` and
|
595
|
+
`SearchResults` pages, but each has slightly different root node. The
|
596
|
+
capybara element that is found by the css selector becomes the root node
|
597
|
+
for the relevant page's instance of the `MenuSection` section.
|
598
|
+
|
599
|
+
#### Adding elements to a section
|
600
|
+
|
601
|
+
This works just the same as adding elements to a page:
|
602
|
+
|
603
|
+
```ruby
|
604
|
+
class MenuSection < SitePrism::Section
|
605
|
+
element :search, "a.search"
|
606
|
+
element :images, "a.image-search"
|
607
|
+
element :maps, "a.map-search"
|
608
|
+
end
|
609
|
+
```
|
610
|
+
|
611
|
+
Note that the css selectors used to find elements are searched for
|
612
|
+
within the scope of the root element of that section. The search for the
|
613
|
+
element won't be page-wide but it will only look in the section.
|
614
|
+
|
615
|
+
When the section is added to a page...
|
616
|
+
|
617
|
+
```ruby
|
618
|
+
class Home < SitePrism::Page
|
619
|
+
section :menu, MenuSection, "#gbx3"
|
620
|
+
end
|
621
|
+
```
|
622
|
+
|
623
|
+
...then the section's elements can be accessed like this:
|
624
|
+
|
625
|
+
```ruby
|
626
|
+
@home = Home.new
|
627
|
+
@home.load
|
628
|
+
|
629
|
+
@home.menu.search #=> returns a capybara element representing the link to the search page
|
630
|
+
@home.menu.search.click #=> clicks the search link in the home page menu
|
631
|
+
@home.menu.search['href'] #=> returns the value for the href attribute of the capybara element representing the search link
|
632
|
+
@home.menu.has_images? #=> returns true or false based on whether the link is present in the section on the page
|
633
|
+
@home.menu.wait_for_images #=> waits for capybara's default wait time until the element appears in the page section
|
634
|
+
|
635
|
+
```
|
636
|
+
|
637
|
+
...which leads to some pretty test code:
|
638
|
+
|
639
|
+
```ruby
|
640
|
+
Then /^the home page menu contains a link to the various search functions$/ do
|
641
|
+
@home.menu.should have_search
|
642
|
+
@home.menu.search['href'].should include "google.com"
|
643
|
+
@home.menu.should have_images
|
644
|
+
@home.menu.should have_maps
|
645
|
+
end
|
646
|
+
```
|
647
|
+
|
648
|
+
#### Testing for the existence of a section
|
649
|
+
|
650
|
+
Just like elements, it is possible to test for the existence of a
|
651
|
+
section. The `section` method adds a method called `has_<section name>?`
|
652
|
+
to the page or section it's been added to - same idea as what the
|
653
|
+
`has_<element name>?` method. Given the following setup:
|
654
|
+
|
655
|
+
```ruby
|
656
|
+
class MenuSection < SitePrism::Section
|
657
|
+
element :search, "a.search"
|
658
|
+
element :images, "a.image-search"
|
659
|
+
element :maps, "a.map-search"
|
660
|
+
end
|
661
|
+
|
662
|
+
class Home < SitePrism::Page
|
663
|
+
section :menu, MenuSection, "#gbx3"
|
664
|
+
end
|
665
|
+
```
|
666
|
+
|
667
|
+
... you can check whether the section is present on the page or not:
|
668
|
+
|
669
|
+
```ruby
|
670
|
+
@home = Home.new
|
671
|
+
#...
|
672
|
+
#home.has_menu? #=> returns true or false
|
673
|
+
```
|
674
|
+
|
675
|
+
Again, this allows pretty test code:
|
676
|
+
|
677
|
+
```ruby
|
678
|
+
@home.should have_menu
|
679
|
+
@home.should_not have_menu
|
680
|
+
```
|
681
|
+
|
682
|
+
#### Waiting for a section to appear
|
683
|
+
|
684
|
+
The final method added to the page or section by the `section` method is
|
685
|
+
`wait_for_<section name>`. Similar to what `element` does, this method
|
686
|
+
waits for the section to appear - the test will wait up to capybara's
|
687
|
+
default wait time until the root node of the element exists on the
|
688
|
+
page/section that our section was added to. Given the following setup:
|
689
|
+
|
690
|
+
```ruby
|
691
|
+
class MenuSection < SitePrism::Section
|
692
|
+
element :search, "a.search"
|
693
|
+
element :images, "a.image-search"
|
694
|
+
element :maps, "a.map-search"
|
695
|
+
end
|
696
|
+
|
697
|
+
class Home < SitePrism::Page
|
698
|
+
section :menu, MenuSection, "#gbx3"
|
699
|
+
end
|
700
|
+
```
|
701
|
+
|
702
|
+
... we can wait for the menu section to appear on the page like this:
|
703
|
+
|
704
|
+
```ruby
|
705
|
+
@home.wait_for_menu
|
706
|
+
@home.wait_for_menu(10) # waits for 10 seconds instead of capybara's default timeout
|
707
|
+
```
|
708
|
+
|
709
|
+
#### Sections within sections
|
710
|
+
|
711
|
+
You are not limited to adding sections only to pages; you can nest
|
712
|
+
sections within sections within sections within sections!
|
713
|
+
|
714
|
+
```ruby
|
715
|
+
|
716
|
+
# define a page that contains an area that contains a section for both logging in and registration, then modelling each of the sub sections seperately
|
717
|
+
|
718
|
+
class Login < SitePrism::Section
|
719
|
+
element :username, "#username"
|
720
|
+
element :password, "#password"
|
721
|
+
element :sign_in, "button"
|
722
|
+
end
|
723
|
+
|
724
|
+
class Registration < SitePrism::Section
|
725
|
+
element :first_name, "#first_name"
|
726
|
+
element :last_name, "#last_name"
|
727
|
+
element :next_step, "button.next-reg-step"
|
728
|
+
end
|
729
|
+
|
730
|
+
class LoginRegistrationForm < SitePrism::Section
|
731
|
+
section :login, Login, "div.login-area"
|
732
|
+
section :registration, Registration, "div.reg-area"
|
733
|
+
end
|
734
|
+
|
735
|
+
class Home < SitePrism::Page
|
736
|
+
section :login_and_registration, LoginRegistrationForm, "div.login-registration"
|
737
|
+
end
|
738
|
+
|
739
|
+
# how to login (fatuous, but demonstrates the point):
|
740
|
+
|
741
|
+
Then /^I sign in$/ do
|
742
|
+
@home = Home.new
|
743
|
+
@home.load
|
744
|
+
@home.wait_for_login_and_registration
|
745
|
+
@home.should have_login_and_registration
|
746
|
+
@home.login_and_registration.should have_username
|
747
|
+
@home.login_and_registration.login.username.set "bob"
|
748
|
+
@home.login_and_registration.login.password.set "p4ssw0rd"
|
749
|
+
@home.login_and_registration.login.sign_in.click
|
750
|
+
end
|
751
|
+
|
752
|
+
# how to sign up:
|
753
|
+
|
754
|
+
When /^I enter my name into the home page's registration form$/ do
|
755
|
+
@home = Home.new
|
756
|
+
@home.load
|
757
|
+
@home.login_and_registration.should have_first_name
|
758
|
+
@home.login_and_registration.should have_last_name
|
759
|
+
@home.login_and_registration.first_name.set "Bob"
|
760
|
+
# ...
|
761
|
+
end
|
762
|
+
```
|
763
|
+
|
764
|
+
### Section Collections
|
765
|
+
|
766
|
+
An individual section represents a discrete section of a page, but often
|
767
|
+
sections are repeated on a page, an example is a search result listing -
|
768
|
+
each listing contains a title, a url and a description of the content.
|
769
|
+
It makes sense to model this only once and then to be able to access
|
770
|
+
each instance of a search result on a page as an array of SitePrism
|
771
|
+
sections. To achieve this, SitePrism provides the `sections` method that
|
772
|
+
can be called in a page or a section.
|
773
|
+
|
774
|
+
The only difference between `section` and `sections` is that whereas the
|
775
|
+
first returns an instance of the supplied section class, the second
|
776
|
+
returns an array containing as many instances of the section class as
|
777
|
+
there are capybara elements found by the supplied css selector. This is
|
778
|
+
better explained in code :)
|
779
|
+
|
780
|
+
#### Adding a Section collection to a page (or other section)
|
781
|
+
|
782
|
+
Given the following setup:
|
783
|
+
|
784
|
+
```ruby
|
785
|
+
class SearchResultSection < SitePrism::Section
|
786
|
+
element :title, "a.title"
|
787
|
+
element :blurb, "span.result-decription"
|
788
|
+
end
|
789
|
+
|
790
|
+
class SearchResults < SitePrism::Page
|
791
|
+
sections :search_results, SearchResultSection, "#results li"
|
792
|
+
end
|
793
|
+
```
|
794
|
+
|
795
|
+
... it is possible to access each of the search results:
|
796
|
+
|
797
|
+
```ruby
|
798
|
+
@results_page = SearchResults.new
|
799
|
+
# ...
|
800
|
+
@results_page.search_results.each do |search_result|
|
801
|
+
puts search_result.title.text
|
802
|
+
end
|
803
|
+
```
|
804
|
+
|
805
|
+
... which allows for pretty tests:
|
806
|
+
|
807
|
+
```ruby
|
808
|
+
Then /^there are lots of search_results$/ do
|
809
|
+
@results_page.search_results.size.should == 10
|
810
|
+
@results_page.search_results.each do |search_result|
|
811
|
+
search_result.should have_title
|
812
|
+
search_result.blurb.text.should_not be_nil
|
813
|
+
end
|
814
|
+
end
|
815
|
+
```
|
816
|
+
|
817
|
+
The css selector that is passed as the 3rd argument to the
|
818
|
+
`sections` method ("#results li") is used to find a number of capybara
|
819
|
+
elements. Each capybara element found using the css selector is used to
|
820
|
+
create a new instance of the `SearchResultSection` and becomes its root
|
821
|
+
element. So if the css selector finds 3 `li` elements, calling
|
822
|
+
`search_results` will return an array containing 3 instances of
|
823
|
+
`SearchResultSection`, each with one of the `li` elements as it's root
|
824
|
+
element.
|
825
|
+
|
826
|
+
#### Testing for existence of Sections
|
827
|
+
|
828
|
+
Using the example above, it is possible to test for the existence of the
|
829
|
+
sections. As long as there is at least one section in the array, the
|
830
|
+
sections exist. The `sections` method adds a `has_<sections name>?`
|
831
|
+
method to the page/section that our section has been added to. Given the
|
832
|
+
following example:
|
833
|
+
|
834
|
+
```ruby
|
835
|
+
class SearchResultSection < SitePrism::Section
|
836
|
+
element :title, "a.title"
|
837
|
+
element :blurb, "span.result-decription"
|
838
|
+
end
|
839
|
+
|
840
|
+
class SearchResults < SitePrism::Page
|
841
|
+
sections :search_results, SearchResultSection, "#results li"
|
842
|
+
end
|
843
|
+
```
|
844
|
+
|
845
|
+
... here's how to test for the existence of the section:
|
846
|
+
|
847
|
+
```ruby
|
848
|
+
@results_page = SearchResults.new
|
849
|
+
# ...
|
850
|
+
@results_page.has_search_results?
|
851
|
+
```
|
852
|
+
|
853
|
+
...which allows pretty tests:
|
854
|
+
|
855
|
+
```ruby
|
856
|
+
Then /^there are search results on the page$/ do
|
857
|
+
@results.page.should have_search_results
|
858
|
+
end
|
859
|
+
```
|
860
|
+
|
861
|
+
#### Waiting for sections to appear
|
862
|
+
|
863
|
+
The final method added by `sections` to the page/section we're adding
|
864
|
+
our sections to is `wait_for_<sections name>`. It will wait for
|
865
|
+
capybara's default wait time for there to be at least one instance of
|
866
|
+
the section in the array of sections. For example:
|
867
|
+
|
868
|
+
```ruby
|
869
|
+
class SearchResultSection < SitePrism::Section
|
870
|
+
element :title, "a.title"
|
871
|
+
element :blurb, "span.result-decription"
|
872
|
+
end
|
873
|
+
|
874
|
+
class SearchResults < SitePrism::Page
|
875
|
+
sections :search_results, SearchResultSection, "#results li"
|
876
|
+
end
|
877
|
+
```
|
878
|
+
|
879
|
+
... here's how to wait for the section:
|
880
|
+
|
881
|
+
```ruby
|
882
|
+
@results_page = SearchResults.new
|
883
|
+
# ...
|
884
|
+
@results_page.wait_for_search_results
|
885
|
+
@results_page.wait_for_search_results(10) #=> waits for 10 seconds instead of the default capybara timeout
|
886
|
+
```
|
887
|
+
|
888
|
+
|
889
|
+
# Epilogue
|
890
|
+
|
891
|
+
So, we've seen how to use SitePrism to put together page objects made up
|
892
|
+
of pages, elements and sections. But how to organise this stuff? There
|
893
|
+
are a few ways of saving yourself having to create instances of pages
|
894
|
+
all over the place. Here's an example of this common problem:
|
895
|
+
|
896
|
+
```ruby
|
897
|
+
@home = Home.new
|
898
|
+
@home.load
|
899
|
+
@home.search_field.set "Sausages"
|
900
|
+
@home.search_field.search_button.click
|
901
|
+
@results_page = SearchResults.new
|
902
|
+
@results_page.should have_search_result_items
|
903
|
+
```
|
904
|
+
|
905
|
+
The annoyance (and, later, maintenance nightmare) is having to create
|
906
|
+
`@home` and `@results_page`. It would be better to not have to create
|
907
|
+
instances of pages all over your tests.
|
908
|
+
|
909
|
+
The way I've dealt with this problem is to create a class containing
|
910
|
+
methods that return instances of the pages. Eg:
|
911
|
+
|
912
|
+
```ruby
|
913
|
+
# our pages
|
914
|
+
|
915
|
+
class Home < SitePrism::Page
|
916
|
+
#...
|
917
|
+
end
|
918
|
+
|
919
|
+
class SearchResults < SitePrism::Page
|
920
|
+
#...
|
921
|
+
end
|
922
|
+
|
923
|
+
class Maps < SitePrism::Page
|
924
|
+
#...
|
925
|
+
end
|
926
|
+
|
927
|
+
# here's the app class that represents our entire site:
|
928
|
+
|
929
|
+
class App
|
930
|
+
def home
|
931
|
+
Home.new
|
932
|
+
end
|
933
|
+
|
934
|
+
def results_page
|
935
|
+
SearchResults.new
|
936
|
+
end
|
937
|
+
|
938
|
+
def maps
|
939
|
+
Maps.new
|
940
|
+
end
|
941
|
+
end
|
942
|
+
|
943
|
+
# and here's how to use it:
|
944
|
+
|
945
|
+
#first line of the test...
|
946
|
+
Given /^I start on the home page$/ do
|
947
|
+
@app = App.new
|
948
|
+
@app.home.load
|
949
|
+
end
|
950
|
+
|
951
|
+
When /^I search for Sausages$/ do
|
952
|
+
@app.home.search_field.set "sausages"
|
953
|
+
@app.home.search_button.click
|
954
|
+
end
|
955
|
+
|
956
|
+
# etc...
|
957
|
+
```
|
958
|
+
|
959
|
+
The only thing that needs instantiating is the App class - from then on
|
960
|
+
pages don't need to be initialized, they are now returned by methods on
|
961
|
+
@app. Maintenance win!
|
962
|
+
|
@@ -1,26 +1,5 @@
|
|
1
|
-
# Contains methods applicable to both {SitePrism::Page}s and {SitePrism::Section}s. Note that they are mixed into the {SitePrism::Page}
|
2
|
-
# and {SitePrism::Section} classes so the methods below are used as class methods.
|
3
1
|
module SitePrism::ElementContainer
|
4
2
|
|
5
|
-
# Creates two methods; the first method has the same name as the element_name parameter and returns the capybara element
|
6
|
-
# located by the element_locator parameter when the method is called. The second method generated has a name with a format
|
7
|
-
# of: 'has_#\{element_name}?' which returns true if the element as located by the element_locator parameter exists, false
|
8
|
-
# if it doesn't
|
9
|
-
# @param [Symbol] element_name The name of the element
|
10
|
-
# @param [String] element_locator The CSS locator to find the element
|
11
|
-
# @example
|
12
|
-
# class HomePage < SitePrism::Page
|
13
|
-
# element :search_link, 'div.search > a'
|
14
|
-
# end
|
15
|
-
# home = HomePage.new
|
16
|
-
#
|
17
|
-
# #the element method created 2 methods...
|
18
|
-
# home.search_link #=> returns the capybara element located by the element_locator parameter
|
19
|
-
# home.has_search_link? #=> returns true if the capybara element as located by the element_locator exists, false if it doesn't
|
20
|
-
#
|
21
|
-
# #The has_search_link? method allows use of magic matchers in rspec/cucumber:
|
22
|
-
# home.should have_search_link
|
23
|
-
# home.should_not have_search_link
|
24
3
|
def element element_name, element_locator = nil
|
25
4
|
if element_locator.nil?
|
26
5
|
define_method element_name.to_s do
|
@@ -36,20 +15,6 @@ module SitePrism::ElementContainer
|
|
36
15
|
create_waiter element_name, element_locator
|
37
16
|
end
|
38
17
|
|
39
|
-
# Works in the same way as {SitePrism::Page.element} in that it will generate two methods; one to check existence of
|
40
|
-
# the element (in the format 'has_#\{element_name}?'), and another to return not a single element, but an array of elements
|
41
|
-
# found by the css locator
|
42
|
-
# @param [Symbol] collection_name The name of the collection
|
43
|
-
# @param [String] collection_locator The CSS locator that returns the list of elements in the collection
|
44
|
-
# @example
|
45
|
-
# class HomePage < SitePrism::Page
|
46
|
-
# elements :app_links, '.title-links > a'
|
47
|
-
# end
|
48
|
-
# home = HomePage.new
|
49
|
-
#
|
50
|
-
# home.should have_app_links
|
51
|
-
# home.app_links #=> [#<Capybara::Element tag="a">, #<Capybara::Element tag="a">, #<Capybara::Element tag="a">]
|
52
|
-
# home.app_links.map {|link| link.text}.should == ['Finance', 'Maps', 'Blogs']
|
53
18
|
def elements collection_name, collection_locator = nil
|
54
19
|
if collection_locator.nil?
|
55
20
|
define_method collection_name.to_s do
|
@@ -66,31 +31,6 @@ module SitePrism::ElementContainer
|
|
66
31
|
end
|
67
32
|
alias :collection :elements
|
68
33
|
|
69
|
-
# Creates a method that returns an instance of a {SitePrism::Section}. If a page contains a common section (eg: a search area) that
|
70
|
-
# appears on many pages, create a {SitePrism::Section} for it and then expose it in each {SitePrism::Page} that contains the section.
|
71
|
-
# Say a search engine website displays the search field and search button on each page and they always have the same IDs, they should
|
72
|
-
# be extracted into a {SitePrism::Section} that would look something like this:
|
73
|
-
#
|
74
|
-
# class SearchArea < SitePrism::Section
|
75
|
-
# element :search_field, '.q'
|
76
|
-
# element :search_button, '.btnK'
|
77
|
-
# end
|
78
|
-
#
|
79
|
-
# ...then that section could be added to any page as follows:
|
80
|
-
#
|
81
|
-
# class SearchPage < SitePrism::Page
|
82
|
-
# section :search_area, SearchArea, '.tsf-p'
|
83
|
-
# end
|
84
|
-
#
|
85
|
-
# class SearchResultsPage < SitePrism::Page
|
86
|
-
# section :search_again, SearchArea, '.tsf-p table'
|
87
|
-
# end
|
88
|
-
#
|
89
|
-
# The SearchArea section appears on both pages, but can be invoked by methods specific to the page (eg: 'search_area' and 'search_again')
|
90
|
-
# and the root element for the section can be different on the page (eg: '.tsf-p' and '.tsf-p table').
|
91
|
-
# @param [Symbol] the method name to be called against this page or section to return an instance of the {SitePrism::Section} class
|
92
|
-
# @param [Class] the class that models this area of the page
|
93
|
-
# @param [String] the CSS locator for the root element of the section on this page/section
|
94
34
|
def section section_name, section_class, section_locator
|
95
35
|
add_element_name section_name
|
96
36
|
create_existence_checker section_name, section_locator
|
@@ -100,7 +40,6 @@ module SitePrism::ElementContainer
|
|
100
40
|
end
|
101
41
|
end
|
102
42
|
|
103
|
-
# Works in the same way as {SitePrism::Page.section} but instead of it returning one section, it returns an array of them.
|
104
43
|
def sections section_collection_name, section_class, section_collection_locator
|
105
44
|
add_element_name section_collection_name
|
106
45
|
create_existence_checker section_collection_name, section_collection_locator
|
@@ -112,21 +51,17 @@ module SitePrism::ElementContainer
|
|
112
51
|
end
|
113
52
|
end
|
114
53
|
|
115
|
-
# Adds the element name to the list of known elements
|
116
54
|
def add_element_name element_name
|
117
55
|
@element_names ||= []
|
118
56
|
@element_names << element_name
|
119
57
|
end
|
120
58
|
|
121
|
-
# Returns list of known element names
|
122
59
|
def element_names
|
123
60
|
@element_names
|
124
61
|
end
|
125
62
|
|
126
63
|
private
|
127
64
|
|
128
|
-
# Creates a method used to check for the existence of the element whose details are passed to it
|
129
|
-
# @param
|
130
65
|
def create_existence_checker element_name, element_locator
|
131
66
|
method_name = "has_#{element_name.to_s}?"
|
132
67
|
if element_locator.nil?
|
@@ -142,7 +77,6 @@ module SitePrism::ElementContainer
|
|
142
77
|
end
|
143
78
|
end
|
144
79
|
|
145
|
-
# Creates a method used to wait for an element to appear - uses the default capybara wait time
|
146
80
|
def create_waiter element_name, element_locator
|
147
81
|
method_name = "wait_for_#{element_name.to_s}"
|
148
82
|
if element_locator.nil?
|
@@ -1,10 +1,6 @@
|
|
1
|
-
# SitePrism's exceptions...
|
2
1
|
module SitePrism
|
3
|
-
# Raised if you ask a page to load but it hasn't had its url set
|
4
2
|
class NoUrlForPage < StandardError; end
|
5
|
-
# Raised if you check to see if a page is displayed but it hasn't had its url matcher set
|
6
3
|
class NoUrlMatcherForPage < StandardError; end
|
7
|
-
# Raised if you ask for an element that hasn't got a locator (i.e. a pending element)
|
8
4
|
class NoLocatorForElement < StandardError; end
|
9
5
|
end
|
10
6
|
|
data/lib/site_prism/page.rb
CHANGED
@@ -1,90 +1,43 @@
|
|
1
1
|
module SitePrism
|
2
|
-
# Subclasses of {SitePrism::Page} represent pages in your app.
|
3
|
-
# class Home < SitePrism::Page
|
4
|
-
# end
|
5
|
-
#
|
6
|
-
# The above is an example of how to make a class representing the home page. There are a number of properties that can be
|
7
|
-
# set on a page - here is an example of a more fully spec'ed out page:
|
8
|
-
# class Home < SitePrism::Page
|
9
|
-
# set_url "/"
|
10
|
-
# set_url_matcher /\/home.htm$/
|
11
|
-
# end
|
12
2
|
class Page
|
13
3
|
include Capybara::DSL
|
14
4
|
include ElementChecker
|
15
5
|
extend ElementContainer
|
16
6
|
|
17
|
-
# Visits the url associated with this page
|
18
|
-
# @raise [SitePrism::NoUrlForPage] To load a page the url must be set using {.set_url}
|
19
7
|
def load
|
20
8
|
raise SitePrism::NoUrlForPage if url.nil?
|
21
9
|
visit url
|
22
10
|
end
|
23
11
|
|
24
|
-
# Checks to see if we're on this page or not
|
25
|
-
# @return true if the browser's current url matches the {.url_matcher} that has been set, false if it doesn't
|
26
|
-
# @raise [SitePrism::NoUrlMatcherForPage] To check whether we're on this page or not the url matcher must be set using {.set_url_matcher}
|
27
|
-
# @example
|
28
|
-
# class SearchPage < SitePrism::Page
|
29
|
-
# set_url_matcher /\/search.htm$/
|
30
|
-
# end
|
31
|
-
# search_page = SearchPage.new
|
32
|
-
# search_page.load
|
33
|
-
# puts "We're on the search page" if search_page.displayed?
|
34
|
-
# search_page.should be_displayed
|
35
12
|
def displayed?
|
36
13
|
raise SitePrism::NoUrlMatcherForPage if url_matcher.nil?
|
37
14
|
!(page.current_url =~ url_matcher).nil?
|
38
15
|
end
|
39
16
|
|
40
|
-
# Set the url associated with this page
|
41
|
-
# @param [String] page_url the portion of the url that identifies this page when appended onto Capybara's app_host. Calling {SitePrism::Page#load} causes Capybara to visit this page.
|
42
|
-
# @example
|
43
|
-
# class SearchPage < SitePrism::Page
|
44
|
-
# set_url "/search.htm"
|
45
|
-
# end
|
46
17
|
def self.set_url page_url
|
47
18
|
@url = page_url
|
48
19
|
end
|
49
20
|
|
50
|
-
# Set the url matcher associated with this page
|
51
|
-
# @param [Regexp] page_url_matcher a regular expression that when compared to the current browser url will match if we're on this page or not match if we're not on this page
|
52
|
-
# @example
|
53
|
-
# class SearchPage < SitePrism::Page
|
54
|
-
# set_url_matcher /\/search.htm$/
|
55
|
-
# end
|
56
21
|
def self.set_url_matcher page_url_matcher
|
57
22
|
@url_matcher = page_url_matcher
|
58
23
|
end
|
59
24
|
|
60
|
-
# Get the url associated with this page
|
61
|
-
# @see SitePrism::Page#url
|
62
|
-
# @return [String] the url originally set in {.set_url}
|
63
25
|
def self.url
|
64
26
|
@url
|
65
27
|
end
|
66
28
|
|
67
|
-
# Get the url matcher associated with this page
|
68
|
-
# @see SitePrism::Page#url_matcher
|
69
|
-
# @return [Regexp] the url matcher originally set in {.set_url_matcher}
|
70
29
|
def self.url_matcher
|
71
30
|
@url_matcher
|
72
31
|
end
|
73
32
|
|
74
|
-
# Get the url associated with this page
|
75
|
-
# @see SitePrism::Page.url
|
76
33
|
def url
|
77
34
|
self.class.url
|
78
35
|
end
|
79
36
|
|
80
|
-
# Get the url matcher associated with this page
|
81
|
-
# @see SitePrism::Page.url_matcher
|
82
37
|
def url_matcher
|
83
38
|
self.class.url_matcher
|
84
39
|
end
|
85
40
|
|
86
|
-
# Gets the title of the current page
|
87
|
-
# @return [String, nil] the text value of the title element within the page's head block
|
88
41
|
def title
|
89
42
|
title_selector = 'html > head > title'
|
90
43
|
using_wait_time(0) { page.find(title_selector).text if page.has_selector?(title_selector) }
|
@@ -92,22 +45,18 @@ module SitePrism
|
|
92
45
|
|
93
46
|
private
|
94
47
|
|
95
|
-
# Page specific element finder
|
96
48
|
def find_one locator
|
97
49
|
find locator
|
98
50
|
end
|
99
51
|
|
100
|
-
# Page specific elements finder
|
101
52
|
def find_all locator
|
102
53
|
all locator
|
103
54
|
end
|
104
55
|
|
105
|
-
# Page specific element existence check
|
106
56
|
def element_exists? locator
|
107
57
|
has_selector? locator
|
108
58
|
end
|
109
59
|
|
110
|
-
# Page specific element waiter
|
111
60
|
def element_waiter locator
|
112
61
|
wait_until { element_exists? locator }
|
113
62
|
end
|
data/lib/site_prism/section.rb
CHANGED
@@ -23,22 +23,18 @@ module SitePrism
|
|
23
23
|
|
24
24
|
private
|
25
25
|
|
26
|
-
# Section specific element finder
|
27
26
|
def find_one locator
|
28
27
|
@root_element.find locator
|
29
28
|
end
|
30
29
|
|
31
|
-
# Section specific elements finder
|
32
30
|
def find_all locator
|
33
31
|
@root_element.all locator
|
34
32
|
end
|
35
33
|
|
36
|
-
# Section specific element existence check
|
37
34
|
def element_exists? locator
|
38
35
|
@root_element.has_selector? locator
|
39
36
|
end
|
40
37
|
|
41
|
-
# Section specific element waiter
|
42
38
|
def element_waiter locator
|
43
39
|
Capybara.current_session.wait_until { element_exists? locator }
|
44
40
|
end
|
data/lib/site_prism/version.rb
CHANGED
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: site_prism
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0
|
5
|
+
version: "1.0"
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Nat Ritmeyer
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2012-
|
13
|
+
date: 2012-04-19 00:00:00 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: capybara
|
@@ -52,6 +52,7 @@ files:
|
|
52
52
|
- lib/site_prism/version.rb
|
53
53
|
- lib/site_prism.rb
|
54
54
|
- LICENSE
|
55
|
+
- README.md
|
55
56
|
homepage: http://github.com/natritmeyer/site_prism
|
56
57
|
licenses: []
|
57
58
|
|