page-object 0.6.9 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.rvmrc +1 -1
- data/ChangeLog +9 -0
- data/Guardfile +4 -5
- data/cucumber.yml +1 -0
- data/features/html/indexed_property.html +38 -0
- data/features/indexed_property.feature +83 -0
- data/features/step_definitions/indexed_property_steps.rb +79 -0
- data/features/support/url_helper.rb +4 -0
- data/features/table.feature +17 -1
- data/lib/page-object.rb +7 -2
- data/lib/page-object/accessors.rb +43 -14
- data/lib/page-object/indexed_properties.rb +37 -0
- data/lib/page-object/nested_elements.rb +1 -1
- data/lib/page-object/page_factory.rb +15 -0
- data/lib/page-object/platforms/selenium_webdriver/table.rb +2 -2
- data/lib/page-object/platforms/selenium_webdriver/table_row.rb +2 -1
- data/lib/page-object/platforms/watir_webdriver/table.rb +4 -2
- data/lib/page-object/platforms/watir_webdriver/table_row.rb +2 -1
- data/lib/page-object/version.rb +1 -1
- data/page-object.gemspec +1 -1
- data/spec/page-object/page_factory_spec.rb +20 -0
- data/spec/page-object/watir_accessors_spec.rb +28 -20
- metadata +59 -16
data/.rvmrc
CHANGED
@@ -1 +1 @@
|
|
1
|
-
rvm 1.9.3-
|
1
|
+
rvm 1.9.3-p194@page-object --create
|
data/ChangeLog
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
=== Version 0.7.0 / 2012-6-30
|
2
|
+
* Enhancements
|
3
|
+
* Updated Table [] method to return a row that has matching partial text in any column (Thanks George Shakhnazaryan)
|
4
|
+
* Updated TableRow [] method to return column that matching partial text in any column (Thanks George Shakhnazaryan)
|
5
|
+
* Added if_page to PageFactory (Thanks Gregory Shayko)
|
6
|
+
* Added index_property for accessing sets of related fields (Thanks robkid)
|
7
|
+
* Updated to use selenium-webdriver 2.24.0
|
8
|
+
|
9
|
+
|
1
10
|
=== Version 0.6.9 / 2012-6-12
|
2
11
|
* Enhancements
|
3
12
|
* Added select_value method to SelectList
|
data/Guardfile
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
# A sample Guardfile
|
2
2
|
# More info at https://github.com/guard/guard#readme
|
3
3
|
|
4
|
-
features_to_run = 'features'
|
5
4
|
|
6
5
|
guard 'rspec', :cli => '--color --format Fuubar' do
|
7
6
|
watch(%r{^spec/.+_spec\.rb$})
|
@@ -12,10 +11,10 @@ guard 'rspec', :cli => '--color --format Fuubar' do
|
|
12
11
|
watch('spec/spec_helper.rb') { "spec" }
|
13
12
|
end
|
14
13
|
|
15
|
-
guard 'cucumber', :notification => true, :all_after_pass => false, :all_on_start => false, :cli => '--profile
|
14
|
+
guard 'cucumber', :notification => true, :all_after_pass => false, :all_on_start => false, :cli => '--profile focus' do
|
16
15
|
watch(%r{^features/.+\.feature$})
|
17
|
-
watch(%r{^features/support/.+$}) {
|
16
|
+
watch(%r{^features/support/.+$}) { features }
|
18
17
|
watch(%r{^features/step_definitions/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'features' }
|
19
|
-
watch(%r{^lib/.+\.rb$}) {
|
20
|
-
watch(%r{^cucumber.yml$}) {
|
18
|
+
watch(%r{^lib/.+\.rb$}) { features }
|
19
|
+
watch(%r{^cucumber.yml$}) { features }
|
21
20
|
end
|
data/cucumber.yml
CHANGED
@@ -5,4 +5,5 @@ std_opts = "--no-source --color --format Cucumber::Formatter::Fuubar"
|
|
5
5
|
default: DRIVER=WATIR <%= std_opts %> --tags ~@selenium_only
|
6
6
|
watir: DRIVER=WATIR <%= std_opts %> --tags ~@selenium_only
|
7
7
|
selenium: DRIVER=SELENIUM <%= std_opts %> --tags ~@watir_only
|
8
|
+
focus: DRIVER=SELENIUM <%= std_opts %> --tags ~@watir_only --tags @focus
|
8
9
|
|
@@ -0,0 +1,38 @@
|
|
1
|
+
<html>
|
2
|
+
<head>
|
3
|
+
<title>Indexed Property Page</title>
|
4
|
+
</head>
|
5
|
+
<body>
|
6
|
+
<form method="get" action="success.html">
|
7
|
+
<table id="table_id" name align="table_name" class="table_class" border="1">
|
8
|
+
<tr>
|
9
|
+
<td><input type="text" id="table[123].text" name="tableName[123].text" size="20"/></td>
|
10
|
+
<td><input type="radio" id="table[123].radio" value="123"/></td>
|
11
|
+
<td><input type="checkbox" id="table[123].check" value="1"/></td>
|
12
|
+
<td><textarea id="table[123].area" rows="2" cols="20"></textarea></td>
|
13
|
+
<td><input id="table[123].button" type="submit" value="Click 123"/></td>
|
14
|
+
</tr>
|
15
|
+
<tr>
|
16
|
+
<td><input type="text" id="table[foo].text" name="tableName[foo].text" size="20"/></td>
|
17
|
+
<td><input type="radio" id="table[foo].radio" value="foo"/></td>
|
18
|
+
<td><input type="checkbox" id="table[foo].check" value="2"/></td>
|
19
|
+
<td><textarea id="table[foo].area" rows="2" cols="20"></textarea></td>
|
20
|
+
<td><input id="table[foo].button" type="submit" value="Click foo"/></td>
|
21
|
+
</tr>
|
22
|
+
<tr>
|
23
|
+
<td><input type="text" id="table[12test].text" name="tableName[12test].text" size="20"/></td>
|
24
|
+
<td><input type="radio" id="table[12test].radio" value="12test"/></td>
|
25
|
+
<td><input type="checkbox" id="table[12test].check" value="3"/></td>
|
26
|
+
<td><textarea id="table[12test].area" rows="2" cols="20"></textarea></td>
|
27
|
+
<td><input id="table[12test].button" type="submit" value="Click 12test"/></td>
|
28
|
+
</tr>
|
29
|
+
</table>
|
30
|
+
|
31
|
+
<div>
|
32
|
+
<input type="text" id="nottable[123].text" size="20"/><br/>
|
33
|
+
<input type="text" id="nottable[foo].text" size="20"/><br/>
|
34
|
+
<input type="text" id="nottable[12test].text" size="20"/>
|
35
|
+
</div>
|
36
|
+
</form>
|
37
|
+
</body>
|
38
|
+
</html>
|
@@ -0,0 +1,83 @@
|
|
1
|
+
Feature: Indexed Property
|
2
|
+
In order to interact with recurring sequences of elements with an index
|
3
|
+
Testers will need access and interrogation ability
|
4
|
+
|
5
|
+
Background:
|
6
|
+
Given I am on the indexed property page
|
7
|
+
|
8
|
+
Scenario Outline: Locating indexed text fields in a table on the Page by id
|
9
|
+
When I search for the elements for index "<index>"
|
10
|
+
And I type "I found it" into the table's indexed text field by id
|
11
|
+
Then The table's indexed text field by id should contain "I found it"
|
12
|
+
|
13
|
+
Examples:
|
14
|
+
| index |
|
15
|
+
| foo |
|
16
|
+
| 123 |
|
17
|
+
| 12test |
|
18
|
+
|
19
|
+
Scenario Outline: Locating indexed text fields in a table on the Page by name
|
20
|
+
When I search for the elements for index "<index>"
|
21
|
+
And I type "I found it" into the table's indexed text field by name
|
22
|
+
Then The table's indexed text field by name should contain "I found it"
|
23
|
+
|
24
|
+
Examples:
|
25
|
+
| index |
|
26
|
+
| foo |
|
27
|
+
| 123 |
|
28
|
+
| 12test |
|
29
|
+
|
30
|
+
Scenario Outline: Locating indexed radio buttons in a table on the Page
|
31
|
+
When I search for the elements for index "<index>"
|
32
|
+
And I select the indexed radio button
|
33
|
+
Then The indexed radio button should be selected
|
34
|
+
|
35
|
+
Examples:
|
36
|
+
| index |
|
37
|
+
| foo |
|
38
|
+
| 123 |
|
39
|
+
| 12test |
|
40
|
+
|
41
|
+
Scenario Outline: Locating indexed checkboxes in a table on the Page
|
42
|
+
When I search for the elements for index "<index>"
|
43
|
+
And I check the indexed checkbox
|
44
|
+
Then The indexed checkbox should be checked
|
45
|
+
|
46
|
+
Examples:
|
47
|
+
| index |
|
48
|
+
| foo |
|
49
|
+
| 123 |
|
50
|
+
| 12test |
|
51
|
+
|
52
|
+
Scenario Outline: Locating indexed text areas in a table on the Page
|
53
|
+
When I search for the elements for index "<index>"
|
54
|
+
And I type "I found it" into the table's indexed text area
|
55
|
+
Then The table's indexed text area should contain "I found it"
|
56
|
+
|
57
|
+
Examples:
|
58
|
+
| index |
|
59
|
+
| foo |
|
60
|
+
| 123 |
|
61
|
+
| 12test |
|
62
|
+
|
63
|
+
Scenario Outline: Locating indexed buttons in a table on the Page
|
64
|
+
When I search for the elements for index "<index>"
|
65
|
+
Then I should see that the indexed button exists
|
66
|
+
And I should be able to click the indexed button
|
67
|
+
|
68
|
+
Examples:
|
69
|
+
| index |
|
70
|
+
| foo |
|
71
|
+
| 123 |
|
72
|
+
| 12test |
|
73
|
+
|
74
|
+
Scenario Outline: Locating indexed text fields outside a table on the Page
|
75
|
+
When I search for the elements for index "<index>"
|
76
|
+
And I type "I found it" into the regular indexed text field by id
|
77
|
+
Then The regular indexed text field by id should contain "I found it"
|
78
|
+
|
79
|
+
Examples:
|
80
|
+
| index |
|
81
|
+
| foo |
|
82
|
+
| 123 |
|
83
|
+
| 12test |
|
@@ -0,0 +1,79 @@
|
|
1
|
+
class IndexedPropertyPage
|
2
|
+
include PageObject
|
3
|
+
|
4
|
+
indexed_property :table, [[:text_field, :text, {:id => 'table[%s].text'}],
|
5
|
+
[:text_field, :text_name, {:name => 'tableName[%s].text'}],
|
6
|
+
[:radio_button, :radio, {:id => 'table[%s].radio'}],
|
7
|
+
[:checkbox, :check, {:id => 'table[%s].check'}],
|
8
|
+
[:text_area, :area, {:id => 'table[%s].area'}],
|
9
|
+
[:button, :button, {:id => 'table[%s].button'}]]
|
10
|
+
|
11
|
+
indexed_property :nottable, [[:text_field, :text, {:id => 'nottable[%s].text'}]]
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
Given /^I am on the indexed property page$/ do
|
16
|
+
@page = IndexedPropertyPage.new(@browser)
|
17
|
+
@page.navigate_to(UrlHelper.indexed)
|
18
|
+
end
|
19
|
+
|
20
|
+
When /^I search for the elements for index "([^\"]*)"$/ do |index|
|
21
|
+
@index = index
|
22
|
+
end
|
23
|
+
|
24
|
+
Then /^I type "([^\"]*)" into the table's indexed text field by id$/ do |val|
|
25
|
+
@page.table[@index].text = val
|
26
|
+
end
|
27
|
+
|
28
|
+
Then /^The table's indexed text field by id should contain "([^\"]*)"$/ do |val|
|
29
|
+
@page.table[@index].text.should == val
|
30
|
+
end
|
31
|
+
|
32
|
+
Then /^I type "([^\"]*)" into the table's indexed text field by name$/ do |val|
|
33
|
+
@page.table[@index].text_name = val
|
34
|
+
end
|
35
|
+
|
36
|
+
Then /^The table's indexed text field by name should contain "([^\"]*)"$/ do |val|
|
37
|
+
@page.table[@index].text_name.should == val
|
38
|
+
end
|
39
|
+
|
40
|
+
Then /^I select the indexed radio button$/ do
|
41
|
+
@page.table[@index].select_radio
|
42
|
+
end
|
43
|
+
|
44
|
+
Then /^The indexed radio button should be selected$/ do
|
45
|
+
@page.table[@index].radio_selected?.should == true
|
46
|
+
end
|
47
|
+
|
48
|
+
Then /^I check the indexed checkbox$/ do
|
49
|
+
@page.table[@index].check_check
|
50
|
+
end
|
51
|
+
|
52
|
+
Then /^The indexed checkbox should be checked$/ do
|
53
|
+
@page.table[@index].check_checked?.should == true
|
54
|
+
end
|
55
|
+
|
56
|
+
Then /^I type "([^\"]*)" into the table's indexed text area$/ do |val|
|
57
|
+
@page.table[@index].area = val
|
58
|
+
end
|
59
|
+
|
60
|
+
Then /^The table's indexed text area should contain "([^\"]*)"$/ do |val|
|
61
|
+
@page.table[@index].area.should == val
|
62
|
+
end
|
63
|
+
|
64
|
+
Then /^I should see that the indexed button exists$/ do
|
65
|
+
@page.table[@index].button?.should == true
|
66
|
+
end
|
67
|
+
|
68
|
+
Then /^I should be able to click the indexed button$/ do
|
69
|
+
@page.table[@index].button
|
70
|
+
end
|
71
|
+
|
72
|
+
Then /^I type "([^\"]*)" into the regular indexed text field by id$/ do |val|
|
73
|
+
@page.nottable[@index].text = val
|
74
|
+
end
|
75
|
+
|
76
|
+
Then /^The regular indexed text field by id should contain "([^\"]*)"$/ do |val|
|
77
|
+
@page.nottable[@index].text.should == val
|
78
|
+
end
|
79
|
+
|
data/features/table.feature
CHANGED
@@ -26,13 +26,29 @@ Feature: Table
|
|
26
26
|
And the data for the first row should be "Data1" and "Data2"
|
27
27
|
And the data for the last row should be "Data3" and "Data4"
|
28
28
|
|
29
|
-
Scenario: Retrieve data from a table using
|
29
|
+
Scenario: Retrieve data from a table using a row header
|
30
30
|
When I retrieve a table element
|
31
31
|
Then the data for row "Data3" should be "Data3" and "Data4"
|
32
|
+
|
33
|
+
Scenario: Retrieve data from a table using a partial row header
|
34
|
+
When I retrieve a table element
|
35
|
+
Then the data for row "ata3" should be "Data3" and "Data4"
|
36
|
+
|
37
|
+
Scenario: Retrieve data from a table using a row header in the 2nd column
|
38
|
+
When I retrieve a table element
|
39
|
+
Then the data for row "Data4" should be "Data3" and "Data4"
|
40
|
+
|
41
|
+
Scenario: Retrieve data from a table using a partial row header in the 2nd column
|
42
|
+
When I retrieve a table element
|
43
|
+
Then the data for row "ata4" should be "Data3" and "Data4"
|
32
44
|
|
33
45
|
Scenario: Retrieve data from a table using a column header
|
34
46
|
When I retrieve a table element
|
35
47
|
Then the data for column "Data2" and row "2" should be "Data4"
|
48
|
+
|
49
|
+
Scenario: Retrieve data from a table using a partial column header
|
50
|
+
When I retrieve a table element
|
51
|
+
Then the data for column "ata2" and row "2" should be "Data4"
|
36
52
|
|
37
53
|
Scenario: Retrieve data from a table using both headers
|
38
54
|
When I retrieve a table element
|
data/lib/page-object.rb
CHANGED
@@ -5,6 +5,7 @@ require 'page-object/element_locators'
|
|
5
5
|
require 'page-object/nested_elements'
|
6
6
|
require 'page-object/page_populator'
|
7
7
|
require 'page-object/javascript_framework_facade'
|
8
|
+
require 'page-object/indexed_properties'
|
8
9
|
|
9
10
|
require 'selenium/webdriver/common/error'
|
10
11
|
#
|
@@ -53,12 +54,16 @@ module PageObject
|
|
53
54
|
# @param [bool] open the page if page_url is set
|
54
55
|
#
|
55
56
|
def initialize(browser, visit=false)
|
56
|
-
|
57
|
-
include_platform_driver(browser)
|
57
|
+
initialize_browser(browser)
|
58
58
|
goto if visit && respond_to?(:goto)
|
59
59
|
initialize_page if respond_to?(:initialize_page)
|
60
60
|
end
|
61
61
|
|
62
|
+
def initialize_browser(browser)
|
63
|
+
@browser = browser
|
64
|
+
include_platform_driver(browser)
|
65
|
+
end
|
66
|
+
|
62
67
|
# @private
|
63
68
|
def self.included(cls)
|
64
69
|
cls.extend PageObject::Accessors
|
@@ -34,10 +34,10 @@ module PageObject
|
|
34
34
|
# @example Specify 'Google' as the expected title of a page
|
35
35
|
# expected_title "Google"
|
36
36
|
# page.has_expected_title?
|
37
|
-
#
|
37
|
+
#
|
38
38
|
def expected_title(expected_title)
|
39
39
|
define_method("has_expected_title?") do
|
40
|
-
has_expected_title = expected_title
|
40
|
+
has_expected_title = expected_title === title
|
41
41
|
raise "Expected title '#{expected_title}' instead of '#{title}'" unless has_expected_title
|
42
42
|
has_expected_title
|
43
43
|
end
|
@@ -59,7 +59,7 @@ module PageObject
|
|
59
59
|
self.respond_to? "#{element_name}_element" and self.send("#{element_name}_element").when_present timeout
|
60
60
|
end
|
61
61
|
end
|
62
|
-
|
62
|
+
|
63
63
|
#
|
64
64
|
# Identify an element as existing within a frame or iframe. A frame parameter
|
65
65
|
# is passed to the block and must be passed to the other calls to PageObject.
|
@@ -88,8 +88,8 @@ module PageObject
|
|
88
88
|
# another to retrieve text from a text field, another to return the text
|
89
89
|
# field element, another to check the text field's existence.
|
90
90
|
#
|
91
|
-
# @example
|
92
|
-
# text_field(:first_name, :id => "first_name")
|
91
|
+
# @example
|
92
|
+
# text_field(:first_name, :id => "first_name")
|
93
93
|
# # will generate 'first_name', 'first_name=', 'first_name_element',
|
94
94
|
# # 'first_name?' methods
|
95
95
|
#
|
@@ -126,7 +126,7 @@ module PageObject
|
|
126
126
|
end
|
127
127
|
alias_method "#{name}_text_field".to_sym, "#{name}_element".to_sym
|
128
128
|
end
|
129
|
-
|
129
|
+
|
130
130
|
#
|
131
131
|
# adds three methods to the page object - one to get the text from a hidden field,
|
132
132
|
# another to retrieve the hidden field element, and another to check the hidden
|
@@ -207,7 +207,7 @@ module PageObject
|
|
207
207
|
#
|
208
208
|
# adds four methods - one to select an item in a drop-down,
|
209
209
|
# another to fetch the currently selected item text, another
|
210
|
-
# to retrieve the select list element, and another to check the
|
210
|
+
# to retrieve the select list element, and another to check the
|
211
211
|
# drop down's existence.
|
212
212
|
#
|
213
213
|
# @example
|
@@ -295,7 +295,7 @@ module PageObject
|
|
295
295
|
#
|
296
296
|
# @example
|
297
297
|
# checkbox(:active, :name => "is_active")
|
298
|
-
# # will generate 'check_active', 'uncheck_active', 'active_checked?',
|
298
|
+
# # will generate 'check_active', 'uncheck_active', 'active_checked?',
|
299
299
|
# # 'active_element', and 'active?' methods
|
300
300
|
#
|
301
301
|
# @param [Symbol] the name used for the generated methods
|
@@ -335,14 +335,14 @@ module PageObject
|
|
335
335
|
|
336
336
|
#
|
337
337
|
# adds five methods - one to select, another to clear,
|
338
|
-
# another to return if a radio button is selected,
|
338
|
+
# another to return if a radio button is selected,
|
339
339
|
# another method to return a PageObject::Elements::RadioButton
|
340
340
|
# object representing the radio button element, and another to check
|
341
341
|
# the radio button's existence.
|
342
342
|
#
|
343
343
|
# @example
|
344
344
|
# radio_button(:north, :id => "north")
|
345
|
-
# # will generate 'select_north', 'clear_north', 'north_selected?',
|
345
|
+
# # will generate 'select_north', 'clear_north', 'north_selected?',
|
346
346
|
# # 'north_element', and 'north?' methods
|
347
347
|
#
|
348
348
|
# @param [Symbol] the name used for the generated methods
|
@@ -712,9 +712,9 @@ module PageObject
|
|
712
712
|
end
|
713
713
|
alias_method "#{name}_ordered_list".to_sym, "#{name}_element".to_sym
|
714
714
|
end
|
715
|
-
|
715
|
+
|
716
716
|
#
|
717
|
-
# adds three methods - one to retrieve the text of a h1 element, another to
|
717
|
+
# adds three methods - one to retrieve the text of a h1 element, another to
|
718
718
|
# retrieve a h1 element, and another to check for it's existence.
|
719
719
|
#
|
720
720
|
# @example
|
@@ -746,7 +746,7 @@ module PageObject
|
|
746
746
|
end
|
747
747
|
alias_method "#{name}_h1".to_sym, "#{name}_element".to_sym
|
748
748
|
end
|
749
|
-
|
749
|
+
|
750
750
|
#
|
751
751
|
# adds three methods - one to retrieve the text of a h2 element, another
|
752
752
|
# to retrieve a h2 element, and another to check for it's existence.
|
@@ -1049,8 +1049,37 @@ module PageObject
|
|
1049
1049
|
end
|
1050
1050
|
define_method("#{name}?") do
|
1051
1051
|
self.send("#{name}_element").exists?
|
1052
|
-
end
|
1052
|
+
end
|
1053
1053
|
end
|
1054
1054
|
|
1055
|
+
#
|
1056
|
+
# adds a method that will return an indexed property. The property will respond to
|
1057
|
+
# the [] method with an object that has a set of normal page_object properties that
|
1058
|
+
# correspond to the definitions included in the identifier_list parameter, with the
|
1059
|
+
# "what" of the "how and what" substituted based on the index provided to the []
|
1060
|
+
# method.
|
1061
|
+
#
|
1062
|
+
# @example
|
1063
|
+
# indexed_property(:title, [
|
1064
|
+
# [:text_field, :field_1, :id => 'table[%s].field_1'],
|
1065
|
+
# [:button, :button_1, :id => 'table[%s].button_1'],
|
1066
|
+
# [:text_field, :field_2, :name => 'table[%s].field_2']
|
1067
|
+
# ])
|
1068
|
+
# # will generate a title method that responds to []. title['foo'] will return an object
|
1069
|
+
# # that responds to the normal methods expected for two text_fields and a button with the
|
1070
|
+
# # given names, using the given how and what with 'foo' substituted for the %s. title[123]
|
1071
|
+
# # will do the same, using the integer 123 instead.
|
1072
|
+
#
|
1073
|
+
# @param [Symbol] the name used for the generated method
|
1074
|
+
# @param [Array] definitions an array of definitions to define on the indexed property. Each
|
1075
|
+
# entry in the array should contain two symbols and a hash, corresponding to one of the standard
|
1076
|
+
# page_object properties with a single substitution marker in each value in the hash,
|
1077
|
+
# e.g. [:text_field, :field_1, :id => 'table[%s].field_1']
|
1078
|
+
#
|
1079
|
+
def indexed_property (name, identifier_list)
|
1080
|
+
define_method("#{name}") do
|
1081
|
+
IndexedProperties::TableOfElements.new(@browser, identifier_list)
|
1082
|
+
end
|
1083
|
+
end
|
1055
1084
|
end
|
1056
1085
|
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module PageObject
|
2
|
+
module IndexedProperties
|
3
|
+
class RowOfElements
|
4
|
+
include PageObject
|
5
|
+
include LoadsPlatform
|
6
|
+
extend Accessors
|
7
|
+
|
8
|
+
def initialize (browser, index, identifier_list)
|
9
|
+
initialize_browser(browser)
|
10
|
+
|
11
|
+
identifier_list.each do |identifier|
|
12
|
+
type = identifier[0]
|
13
|
+
name = identifier[1]
|
14
|
+
how_and_what = identifier[2].clone # Cannot modify the original...
|
15
|
+
how_and_what.each do |key, value|
|
16
|
+
how_and_what[key] = value % index
|
17
|
+
end
|
18
|
+
self.class.send type, name, how_and_what
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class TableOfElements
|
24
|
+
include PageObject
|
25
|
+
include LoadsPlatform
|
26
|
+
|
27
|
+
def initialize (browser, identifier_list)
|
28
|
+
initialize_browser(browser)
|
29
|
+
@identifier_list = identifier_list
|
30
|
+
end
|
31
|
+
|
32
|
+
def [] (index)
|
33
|
+
RowOfElements.new(@browser, index, @identifier_list)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -62,6 +62,21 @@ module PageObject
|
|
62
62
|
|
63
63
|
# Support 'on' for readability of usage
|
64
64
|
alias_method :on, :on_page
|
65
|
+
|
66
|
+
#
|
67
|
+
# Create a page object if and only if the current page is the same page to be created
|
68
|
+
#
|
69
|
+
# @param [PageObject] a class that has included the PageObject module
|
70
|
+
# @param [block] an optional block to be called
|
71
|
+
# @return [PageObject] the newly created page object
|
72
|
+
#
|
73
|
+
def if_page(page_class, &block)
|
74
|
+
return @current_page unless @current_page.class == page_class
|
75
|
+
on_page(page_class, false, &block)
|
76
|
+
end
|
77
|
+
|
78
|
+
# Support 'if' for readability of usage
|
79
|
+
alias_method :if, :if_page
|
65
80
|
|
66
81
|
#
|
67
82
|
# Navigate to a specific page following a predefined path.
|
@@ -6,7 +6,7 @@ module PageObject
|
|
6
6
|
#
|
7
7
|
# Return the PageObject::Elements::TableRow for the index provided. Index
|
8
8
|
# is zero based. If the index provided is a String then it
|
9
|
-
# will be matched with the text from the
|
9
|
+
# will be matched with the text from any column. The text can be a substring of the full column text.
|
10
10
|
#
|
11
11
|
# @return [PageObject::Elements::TableRow]
|
12
12
|
#
|
@@ -37,7 +37,7 @@ module PageObject
|
|
37
37
|
def find_index_by_title(row_title, eles)
|
38
38
|
eles.find_index do |row|
|
39
39
|
columns = row.find_elements(:xpath, ".//child::td|th")
|
40
|
-
columns.
|
40
|
+
columns.any? { |col| col.text.include? row_title }
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
@@ -8,6 +8,7 @@ module PageObject
|
|
8
8
|
# Return the PageObject::Elements::TableCell for the index provided. Index
|
9
9
|
# is zero based. If the index provided is a String then it
|
10
10
|
# will be matched with the text from the columns in the first row.
|
11
|
+
# The text can be a substring of the full column text.
|
11
12
|
#
|
12
13
|
def [](idx)
|
13
14
|
els = table_cells
|
@@ -28,7 +29,7 @@ module PageObject
|
|
28
29
|
def find_index_by_title(title)
|
29
30
|
table = parent
|
30
31
|
table = table.parent if parent.element.tag_name == 'tbody'
|
31
|
-
table[0].find_index {|column| column.text
|
32
|
+
table[0].find_index { |column| column.text.include? title }
|
32
33
|
end
|
33
34
|
|
34
35
|
def table_cells
|
@@ -7,7 +7,7 @@ module PageObject
|
|
7
7
|
#
|
8
8
|
# Return the PageObject::Elements::TableRow for the index provided. Index
|
9
9
|
# is zero based. If the index provided is a String then it
|
10
|
-
# will be matched with the text from the
|
10
|
+
# will be matched with the text from any column. The text can be a substring of the full column text.
|
11
11
|
#
|
12
12
|
# @return [PageObject::Elements::TableRow]
|
13
13
|
#
|
@@ -27,7 +27,9 @@ module PageObject
|
|
27
27
|
private
|
28
28
|
|
29
29
|
def find_index_by_title(row_title)
|
30
|
-
element.rows.find_index
|
30
|
+
element.rows.find_index do |row|
|
31
|
+
row.cells.any? { |col| col.text.include? row_title }
|
32
|
+
end
|
31
33
|
end
|
32
34
|
|
33
35
|
end
|
@@ -7,6 +7,7 @@ module PageObject
|
|
7
7
|
# Return the PageObject::Elements::TableCell for the index provided. Index
|
8
8
|
# is zero based. If the index provided is a String then it
|
9
9
|
# will be matched with the text from the columns in the first row.
|
10
|
+
# The text can be a substring of the full column text.
|
10
11
|
#
|
11
12
|
def [](idx)
|
12
13
|
idx = find_index_by_title(idx) if idx.kind_of?(String)
|
@@ -26,7 +27,7 @@ module PageObject
|
|
26
27
|
def find_index_by_title(title)
|
27
28
|
table = element.parent
|
28
29
|
first_row = table[0]
|
29
|
-
first_row.cells.find_index {|column| column.text
|
30
|
+
first_row.cells.find_index {|column| column.text.include? title }
|
30
31
|
end
|
31
32
|
|
32
33
|
end
|
data/lib/page-object/version.rb
CHANGED
data/page-object.gemspec
CHANGED
@@ -20,7 +20,7 @@ Gem::Specification.new do |s|
|
|
20
20
|
s.require_paths = ["lib"]
|
21
21
|
|
22
22
|
s.add_dependency 'watir-webdriver', '>= 0.6.1'
|
23
|
-
s.add_dependency 'selenium-webdriver', '>= 2.
|
23
|
+
s.add_dependency 'selenium-webdriver', '>= 2.24.0'
|
24
24
|
|
25
25
|
s.add_development_dependency 'rspec', '>= 2.6.0'
|
26
26
|
s.add_development_dependency 'cucumber', '< 1.2.0'
|
@@ -72,6 +72,26 @@ describe PageObject::PageFactory do
|
|
72
72
|
current_page.should === page
|
73
73
|
end
|
74
74
|
|
75
|
+
it "should not execute block if page is not @current_page" do
|
76
|
+
@world.instance_variable_set "@current_page", TestPageWithDirectUrl.new(@world.browser)
|
77
|
+
@world.if_page(FactoryTestPage) do |page|
|
78
|
+
fail
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
it "should return the @current_page if asking for another page" do
|
83
|
+
expected = TestPageWithDirectUrl.new(@world.browser)
|
84
|
+
@world.instance_variable_set "@current_page", expected
|
85
|
+
@world.if_page(FactoryTestPage).should == expected
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should execute the block when we ask if it is the correct page" do
|
89
|
+
@world.instance_variable_set "@current_page", FactoryTestPage.new(@world.browser)
|
90
|
+
@world.if_page(FactoryTestPage) do |page|
|
91
|
+
page.should be_instance_of FactoryTestPage
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
75
95
|
it "should raise an error when you do not provide a default route" do
|
76
96
|
expect { PageObject::PageFactory.routes = {:another => []} }.to raise_error
|
77
97
|
end
|
@@ -119,7 +119,7 @@ describe PageObject::Accessors do
|
|
119
119
|
let(:watir_browser) { mock_watir_browser }
|
120
120
|
let(:watir_page_object) { WatirAccessorsTestPageObject.new(watir_browser) }
|
121
121
|
let(:block_page_object) { WatirBlockPageObject.new(watir_browser) }
|
122
|
-
|
122
|
+
|
123
123
|
context "goto a page" do
|
124
124
|
|
125
125
|
it "should navigate to a page when requested" do
|
@@ -151,12 +151,20 @@ describe PageObject::Accessors do
|
|
151
151
|
end
|
152
152
|
|
153
153
|
context "validating the page title" do
|
154
|
-
|
155
154
|
it "should validate the title" do
|
156
155
|
watir_browser.should_receive(:title).and_return("Expected Title")
|
157
156
|
watir_page_object.should have_expected_title
|
158
157
|
end
|
159
158
|
|
159
|
+
it "should validate the by regexp" do
|
160
|
+
class RegexpExpectedTitle
|
161
|
+
include PageObject
|
162
|
+
expected_title /\w+ \w+/
|
163
|
+
end
|
164
|
+
watir_browser.should_receive(:title).and_return("Expected Title")
|
165
|
+
RegexpExpectedTitle.new(watir_browser).should have_expected_title
|
166
|
+
end
|
167
|
+
|
160
168
|
it "should raise error when it does not have expected title" do
|
161
169
|
watir_browser.should_receive(:title).twice.and_return("Not Expected")
|
162
170
|
expect { watir_page_object.has_expected_title? }.to raise_error
|
@@ -351,7 +359,7 @@ describe PageObject::Accessors do
|
|
351
359
|
mock_driver_for :audio
|
352
360
|
default_identifier.default_el?
|
353
361
|
end
|
354
|
-
|
362
|
+
|
355
363
|
end
|
356
364
|
|
357
365
|
context "link accessors" do
|
@@ -366,7 +374,7 @@ describe PageObject::Accessors do
|
|
366
374
|
block_page_object.continue_element.should == "link"
|
367
375
|
end
|
368
376
|
end
|
369
|
-
|
377
|
+
|
370
378
|
it "should select a link" do
|
371
379
|
watir_browser.stub_chain(:link, :click)
|
372
380
|
watir_page_object.google_search
|
@@ -531,7 +539,7 @@ describe PageObject::Accessors do
|
|
531
539
|
watir_browser.should_receive(:set)
|
532
540
|
watir_page_object.check_active
|
533
541
|
end
|
534
|
-
|
542
|
+
|
535
543
|
it "should clear a check box element" do
|
536
544
|
watir_browser.should_receive(:checkbox).and_return(watir_browser)
|
537
545
|
watir_browser.should_receive(:clear)
|
@@ -816,50 +824,50 @@ describe PageObject::Accessors do
|
|
816
824
|
element.should be_instance_of PageObject::Elements::OrderedList
|
817
825
|
end
|
818
826
|
end
|
819
|
-
|
827
|
+
|
820
828
|
describe "h1 accessors" do
|
821
829
|
context "when called on a page object" do
|
822
830
|
it "should generate accessor methods" do
|
823
831
|
watir_page_object.should respond_to(:heading1)
|
824
832
|
watir_page_object.should respond_to(:heading1_element)
|
825
833
|
end
|
826
|
-
|
834
|
+
|
827
835
|
it "should call a block on the element method when present" do
|
828
836
|
block_page_object.heading1_element.should == "h1"
|
829
837
|
end
|
830
838
|
end
|
831
|
-
|
839
|
+
|
832
840
|
it "should retrieve the text from the h1" do
|
833
841
|
watir_browser.should_receive(:h1).and_return(watir_browser)
|
834
842
|
watir_browser.should_receive(:text).and_return("value")
|
835
|
-
watir_page_object.heading1.should == "value"
|
843
|
+
watir_page_object.heading1.should == "value"
|
836
844
|
end
|
837
|
-
|
845
|
+
|
838
846
|
it "should retrieve the element from the page" do
|
839
847
|
watir_browser.should_receive(:h1).and_return(watir_browser)
|
840
848
|
element = watir_page_object.heading1_element
|
841
849
|
element.should be_instance_of PageObject::Elements::Heading
|
842
850
|
end
|
843
851
|
end
|
844
|
-
|
852
|
+
|
845
853
|
describe "h2 accessors" do
|
846
854
|
context "when called on a page object" do
|
847
855
|
it "should generate accessor methods" do
|
848
856
|
watir_page_object.should respond_to(:heading2)
|
849
857
|
watir_page_object.should respond_to(:heading2_element)
|
850
858
|
end
|
851
|
-
|
859
|
+
|
852
860
|
it "should call a block on the element method when present" do
|
853
861
|
block_page_object.heading2_element.should == "h2"
|
854
862
|
end
|
855
863
|
end
|
856
|
-
|
864
|
+
|
857
865
|
it "should retrieve the text from the h2" do
|
858
866
|
watir_browser.should_receive(:h2).and_return(watir_browser)
|
859
867
|
watir_browser.should_receive(:text).and_return("value")
|
860
|
-
watir_page_object.heading2.should == "value"
|
868
|
+
watir_page_object.heading2.should == "value"
|
861
869
|
end
|
862
|
-
|
870
|
+
|
863
871
|
it "should retrieve the element from the page" do
|
864
872
|
watir_browser.should_receive(:h2).and_return(watir_browser)
|
865
873
|
element = watir_page_object.heading2_element
|
@@ -882,7 +890,7 @@ describe PageObject::Accessors do
|
|
882
890
|
it "should retrieve the text from the h3" do
|
883
891
|
watir_browser.should_receive(:h3).and_return(watir_browser)
|
884
892
|
watir_browser.should_receive(:text).and_return("value")
|
885
|
-
watir_page_object.heading3.should == "value"
|
893
|
+
watir_page_object.heading3.should == "value"
|
886
894
|
end
|
887
895
|
|
888
896
|
it "should retrieve the element from the page" do
|
@@ -907,7 +915,7 @@ describe PageObject::Accessors do
|
|
907
915
|
it "should retrieve the text from the h4" do
|
908
916
|
watir_browser.should_receive(:h4).and_return(watir_browser)
|
909
917
|
watir_browser.should_receive(:text).and_return("value")
|
910
|
-
watir_page_object.heading4.should == "value"
|
918
|
+
watir_page_object.heading4.should == "value"
|
911
919
|
end
|
912
920
|
|
913
921
|
it "should retrieve the element from the page" do
|
@@ -932,7 +940,7 @@ describe PageObject::Accessors do
|
|
932
940
|
it "should retrieve the text from the h5" do
|
933
941
|
watir_browser.should_receive(:h5).and_return(watir_browser)
|
934
942
|
watir_browser.should_receive(:text).and_return("value")
|
935
|
-
watir_page_object.heading5.should == "value"
|
943
|
+
watir_page_object.heading5.should == "value"
|
936
944
|
end
|
937
945
|
|
938
946
|
it "should retrieve the element from the page" do
|
@@ -957,7 +965,7 @@ describe PageObject::Accessors do
|
|
957
965
|
it "should retrieve the text from the h6" do
|
958
966
|
watir_browser.should_receive(:h6).and_return(watir_browser)
|
959
967
|
watir_browser.should_receive(:text).and_return("value")
|
960
|
-
watir_page_object.heading6.should == "value"
|
968
|
+
watir_page_object.heading6.should == "value"
|
961
969
|
end
|
962
970
|
|
963
971
|
it "should retrieve the element from the page" do
|
@@ -983,7 +991,7 @@ describe PageObject::Accessors do
|
|
983
991
|
it "should retrieve the text from the p" do
|
984
992
|
watir_browser.should_receive(:p).and_return(watir_browser)
|
985
993
|
watir_browser.should_receive(:text).and_return("value")
|
986
|
-
watir_page_object.first_para.should == "value"
|
994
|
+
watir_page_object.first_para.should == "value"
|
987
995
|
end
|
988
996
|
|
989
997
|
it "should retrieve the element from the page" do
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: page-object
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-06-
|
12
|
+
date: 2012-06-30 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: watir-webdriver
|
16
|
-
requirement:
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,21 +21,31 @@ dependencies:
|
|
21
21
|
version: 0.6.1
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements:
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 0.6.1
|
25
30
|
- !ruby/object:Gem::Dependency
|
26
31
|
name: selenium-webdriver
|
27
|
-
requirement:
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
28
33
|
none: false
|
29
34
|
requirements:
|
30
35
|
- - ! '>='
|
31
36
|
- !ruby/object:Gem::Version
|
32
|
-
version: 2.
|
37
|
+
version: 2.24.0
|
33
38
|
type: :runtime
|
34
39
|
prerelease: false
|
35
|
-
version_requirements:
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 2.24.0
|
36
46
|
- !ruby/object:Gem::Dependency
|
37
47
|
name: rspec
|
38
|
-
requirement:
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
39
49
|
none: false
|
40
50
|
requirements:
|
41
51
|
- - ! '>='
|
@@ -43,10 +53,15 @@ dependencies:
|
|
43
53
|
version: 2.6.0
|
44
54
|
type: :development
|
45
55
|
prerelease: false
|
46
|
-
version_requirements:
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 2.6.0
|
47
62
|
- !ruby/object:Gem::Dependency
|
48
63
|
name: cucumber
|
49
|
-
requirement:
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
50
65
|
none: false
|
51
66
|
requirements:
|
52
67
|
- - <
|
@@ -54,10 +69,15 @@ dependencies:
|
|
54
69
|
version: 1.2.0
|
55
70
|
type: :development
|
56
71
|
prerelease: false
|
57
|
-
version_requirements:
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - <
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: 1.2.0
|
58
78
|
- !ruby/object:Gem::Dependency
|
59
79
|
name: yard
|
60
|
-
requirement:
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
61
81
|
none: false
|
62
82
|
requirements:
|
63
83
|
- - ! '>='
|
@@ -65,10 +85,15 @@ dependencies:
|
|
65
85
|
version: 0.7.2
|
66
86
|
type: :development
|
67
87
|
prerelease: false
|
68
|
-
version_requirements:
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: 0.7.2
|
69
94
|
- !ruby/object:Gem::Dependency
|
70
95
|
name: rack
|
71
|
-
requirement:
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
72
97
|
none: false
|
73
98
|
requirements:
|
74
99
|
- - ! '>='
|
@@ -76,7 +101,12 @@ dependencies:
|
|
76
101
|
version: '1.0'
|
77
102
|
type: :development
|
78
103
|
prerelease: false
|
79
|
-
version_requirements:
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '1.0'
|
80
110
|
description: Page Object DSL that works with both Watir and Selenium
|
81
111
|
email:
|
82
112
|
- jeff.morgan@leandog.com
|
@@ -114,6 +144,7 @@ files:
|
|
114
144
|
- features/html/iframes.html
|
115
145
|
- features/html/images/circle.png
|
116
146
|
- features/html/images/submit.gif
|
147
|
+
- features/html/indexed_property.html
|
117
148
|
- features/html/modal.html
|
118
149
|
- features/html/modal_1.html
|
119
150
|
- features/html/modal_2.html
|
@@ -126,6 +157,7 @@ files:
|
|
126
157
|
- features/html/static_elements.html
|
127
158
|
- features/html/success.html
|
128
159
|
- features/image.feature
|
160
|
+
- features/indexed_property.feature
|
129
161
|
- features/javascript.feature
|
130
162
|
- features/label.feature
|
131
163
|
- features/link.feature
|
@@ -157,6 +189,7 @@ files:
|
|
157
189
|
- features/step_definitions/headings_steps.rb
|
158
190
|
- features/step_definitions/hidden_field_steps.rb
|
159
191
|
- features/step_definitions/image_steps.rb
|
192
|
+
- features/step_definitions/indexed_property_steps.rb
|
160
193
|
- features/step_definitions/javascript_steps.rb
|
161
194
|
- features/step_definitions/label_steps.rb
|
162
195
|
- features/step_definitions/link_steps.rb
|
@@ -216,6 +249,7 @@ files:
|
|
216
249
|
- lib/page-object/elements/text_area.rb
|
217
250
|
- lib/page-object/elements/text_field.rb
|
218
251
|
- lib/page-object/elements/unordered_list.rb
|
252
|
+
- lib/page-object/indexed_properties.rb
|
219
253
|
- lib/page-object/javascript/jquery.rb
|
220
254
|
- lib/page-object/javascript/prototype.rb
|
221
255
|
- lib/page-object/javascript/yui.rb
|
@@ -311,15 +345,21 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
311
345
|
- - ! '>='
|
312
346
|
- !ruby/object:Gem::Version
|
313
347
|
version: '0'
|
348
|
+
segments:
|
349
|
+
- 0
|
350
|
+
hash: -1451627293781447713
|
314
351
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
315
352
|
none: false
|
316
353
|
requirements:
|
317
354
|
- - ! '>='
|
318
355
|
- !ruby/object:Gem::Version
|
319
356
|
version: '0'
|
357
|
+
segments:
|
358
|
+
- 0
|
359
|
+
hash: -1451627293781447713
|
320
360
|
requirements: []
|
321
361
|
rubyforge_project: page-object
|
322
|
-
rubygems_version: 1.8.
|
362
|
+
rubygems_version: 1.8.24
|
323
363
|
signing_key:
|
324
364
|
specification_version: 3
|
325
365
|
summary: Page Object DSL for browser testing
|
@@ -343,6 +383,7 @@ test_files:
|
|
343
383
|
- features/html/iframes.html
|
344
384
|
- features/html/images/circle.png
|
345
385
|
- features/html/images/submit.gif
|
386
|
+
- features/html/indexed_property.html
|
346
387
|
- features/html/modal.html
|
347
388
|
- features/html/modal_1.html
|
348
389
|
- features/html/modal_2.html
|
@@ -355,6 +396,7 @@ test_files:
|
|
355
396
|
- features/html/static_elements.html
|
356
397
|
- features/html/success.html
|
357
398
|
- features/image.feature
|
399
|
+
- features/indexed_property.feature
|
358
400
|
- features/javascript.feature
|
359
401
|
- features/label.feature
|
360
402
|
- features/link.feature
|
@@ -386,6 +428,7 @@ test_files:
|
|
386
428
|
- features/step_definitions/headings_steps.rb
|
387
429
|
- features/step_definitions/hidden_field_steps.rb
|
388
430
|
- features/step_definitions/image_steps.rb
|
431
|
+
- features/step_definitions/indexed_property_steps.rb
|
389
432
|
- features/step_definitions/javascript_steps.rb
|
390
433
|
- features/step_definitions/label_steps.rb
|
391
434
|
- features/step_definitions/link_steps.rb
|