capybara 0.3.9 → 0.4.0.rc

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.
Files changed (70) hide show
  1. data/History.txt +43 -1
  2. data/README.rdoc +168 -98
  3. data/lib/capybara.rb +77 -15
  4. data/lib/capybara/driver/base.rb +21 -16
  5. data/lib/capybara/driver/celerity_driver.rb +39 -41
  6. data/lib/capybara/driver/culerity_driver.rb +2 -1
  7. data/lib/capybara/driver/node.rb +66 -0
  8. data/lib/capybara/driver/rack_test_driver.rb +66 -67
  9. data/lib/capybara/driver/selenium_driver.rb +43 -47
  10. data/lib/capybara/dsl.rb +44 -6
  11. data/lib/capybara/node.rb +185 -24
  12. data/lib/capybara/node/actions.rb +170 -0
  13. data/lib/capybara/node/finders.rb +150 -0
  14. data/lib/capybara/node/matchers.rb +360 -0
  15. data/lib/capybara/rails.rb +1 -0
  16. data/lib/capybara/selector.rb +52 -0
  17. data/lib/capybara/server.rb +68 -87
  18. data/lib/capybara/session.rb +221 -207
  19. data/lib/capybara/spec/driver.rb +45 -35
  20. data/lib/capybara/spec/public/test.js +1 -1
  21. data/lib/capybara/spec/session.rb +28 -53
  22. data/lib/capybara/spec/session/all_spec.rb +7 -3
  23. data/lib/capybara/spec/session/check_spec.rb +50 -52
  24. data/lib/capybara/spec/session/click_button_spec.rb +9 -0
  25. data/lib/capybara/spec/session/click_link_or_button_spec.rb +37 -0
  26. data/lib/capybara/spec/session/current_url_spec.rb +7 -0
  27. data/lib/capybara/spec/session/find_button_spec.rb +4 -2
  28. data/lib/capybara/spec/session/find_by_id_spec.rb +4 -2
  29. data/lib/capybara/spec/session/find_field_spec.rb +7 -3
  30. data/lib/capybara/spec/session/find_link_spec.rb +5 -3
  31. data/lib/capybara/spec/session/find_spec.rb +71 -6
  32. data/lib/capybara/spec/session/has_field_spec.rb +1 -1
  33. data/lib/capybara/spec/session/has_selector_spec.rb +129 -0
  34. data/lib/capybara/spec/session/has_xpath_spec.rb +4 -4
  35. data/lib/capybara/spec/session/javascript.rb +25 -5
  36. data/lib/capybara/spec/session/select_spec.rb +16 -2
  37. data/lib/capybara/spec/session/unselect_spec.rb +8 -1
  38. data/lib/capybara/spec/session/within_spec.rb +5 -5
  39. data/lib/capybara/spec/views/form.erb +65 -1
  40. data/lib/capybara/spec/views/popup_one.erb +8 -0
  41. data/lib/capybara/spec/views/popup_two.erb +8 -0
  42. data/lib/capybara/spec/views/with_html.erb +5 -0
  43. data/lib/capybara/spec/views/within_popups.erb +25 -0
  44. data/lib/capybara/{save_and_open_page.rb → util/save_and_open_page.rb} +3 -3
  45. data/lib/capybara/util/timeout.rb +27 -0
  46. data/lib/capybara/version.rb +1 -1
  47. data/spec/capybara_spec.rb +18 -8
  48. data/spec/driver/celerity_driver_spec.rb +10 -14
  49. data/spec/driver/culerity_driver_spec.rb +4 -3
  50. data/spec/driver/rack_test_driver_spec.rb +39 -2
  51. data/spec/driver/remote_culerity_driver_spec.rb +5 -7
  52. data/spec/driver/remote_selenium_driver_spec.rb +7 -10
  53. data/spec/driver/selenium_driver_spec.rb +3 -2
  54. data/spec/dsl_spec.rb +5 -14
  55. data/spec/save_and_open_page_spec.rb +19 -19
  56. data/spec/server_spec.rb +22 -10
  57. data/spec/session/celerity_session_spec.rb +17 -21
  58. data/spec/session/culerity_session_spec.rb +3 -3
  59. data/spec/session/rack_test_session_spec.rb +2 -2
  60. data/spec/session/selenium_session_spec.rb +2 -2
  61. data/spec/spec_helper.rb +27 -6
  62. data/spec/{wait_until_spec.rb → timeout_spec.rb} +14 -14
  63. metadata +88 -46
  64. data/lib/capybara/searchable.rb +0 -54
  65. data/lib/capybara/spec/session/click_spec.rb +0 -24
  66. data/lib/capybara/spec/session/locate_spec.rb +0 -65
  67. data/lib/capybara/wait_until.rb +0 -28
  68. data/lib/capybara/xpath.rb +0 -179
  69. data/spec/searchable_spec.rb +0 -66
  70. data/spec/xpath_spec.rb +0 -180
@@ -1,9 +1,5 @@
1
1
  require 'capybara/spec/test_app'
2
2
 
3
- Dir[File.dirname(__FILE__)+'/driver/*'].each { |group|
4
- require group
5
- }
6
-
7
3
  shared_examples_for 'driver' do
8
4
 
9
5
  describe '#visit' do
@@ -18,11 +14,6 @@ shared_examples_for 'driver' do
18
14
  @driver.visit('/foo')
19
15
  @driver.current_url.should include('/foo')
20
16
  end
21
-
22
- it 'should show the correct location' do
23
- @driver.visit('/foo')
24
- @driver.current_path.should == '/foo'
25
- end
26
17
  end
27
18
 
28
19
  describe '#body' do
@@ -49,11 +40,8 @@ shared_examples_for 'driver' do
49
40
  end
50
41
 
51
42
  it "should extract node attributes" do
52
- @driver.find('//a')[0][:href].should == '/with_simple_html'
53
43
  @driver.find('//a')[0][:class].should == 'simple'
54
- @driver.find('//a')[1][:href].should == '/foo'
55
44
  @driver.find('//a')[1][:id].should == 'foo'
56
- @driver.find('//a')[1][:rel].should be_nil
57
45
  end
58
46
 
59
47
  it "should extract boolean node attributes" do
@@ -84,26 +72,6 @@ shared_examples_for 'driver' do
84
72
  end
85
73
  end
86
74
  end
87
-
88
- describe "node relative searching" do
89
- before do
90
- @driver.visit('/tables')
91
- @node = @driver.find('//body').first
92
- end
93
-
94
- it "should be able to navigate/search child node" do
95
- @node.all('//table').size.should == 5
96
- @node.find('//form').all('.//table').size.should == 1
97
- @node.find('//form').find('.//table//caption').text.should == 'Agent'
98
- if @driver.class == Capybara::Driver::Selenium
99
- pending("Selenium gets this wrong, see http://code.google.com/p/selenium/issues/detail?id=403") do
100
- @node.find('//form').all('//table').size.should == 5
101
- end
102
- else
103
- @node.find('//form').all('//table').size.should == 5
104
- end
105
- end
106
- end
107
75
  end
108
76
 
109
77
  shared_examples_for "driver with javascript support" do
@@ -117,10 +85,11 @@ shared_examples_for "driver with javascript support" do
117
85
 
118
86
  describe '#drag_to' do
119
87
  it "should drag and drop an object" do
88
+ pending "drag/drop is currently broken under celerity/culerity" if @driver.is_a?(Capybara::Driver::Celerity)
120
89
  draggable = @driver.find('//div[@id="drag"]').first
121
90
  droppable = @driver.find('//div[@id="drop"]').first
122
91
  draggable.drag_to(droppable)
123
- @driver.find('//div[contains(., "Dropped!")]').should_not be_nil
92
+ @driver.find('//div[contains(., "Dropped!")]').should_not be_empty
124
93
  end
125
94
  end
126
95
 
@@ -185,8 +154,49 @@ shared_examples_for "driver with frame support" do
185
154
  end
186
155
  end
187
156
 
157
+ shared_examples_for "driver with support for window switching" do
158
+ describe '#within_window' do
159
+ before(:each) do
160
+ @driver.visit('/within_popups')
161
+ end
162
+ after(:each) do
163
+ @driver.within_window("firstPopup") do
164
+ @driver.evaluate_script('window.close()')
165
+ end
166
+ @driver.within_window("secondPopup") do
167
+ @driver.evaluate_script('window.close()')
168
+ end
169
+ end
170
+
171
+ it "should find the div in firstPopup" do
172
+ @driver.within_window("firstPopup") do
173
+ @driver.find("//*[@id='divInPopupOne']")[0].text.should eql 'This is the text of divInPopupOne'
174
+ end
175
+ end
176
+ it "should find the div in secondPopup" do
177
+ @driver.within_window("secondPopup") do
178
+ @driver.find("//*[@id='divInPopupTwo']")[0].text.should eql 'This is the text of divInPopupTwo'
179
+ end
180
+ end
181
+ it "should find the divs in both popups" do
182
+ @driver.within_window("secondPopup") do
183
+ @driver.find("//*[@id='divInPopupTwo']")[0].text.should eql 'This is the text of divInPopupTwo'
184
+ end
185
+ @driver.within_window("firstPopup") do
186
+ @driver.find("//*[@id='divInPopupOne']")[0].text.should eql 'This is the text of divInPopupOne'
187
+ end
188
+ end
189
+ it "should find the div in the main window after finding a div in a popup" do
190
+ @driver.within_window("secondPopup") do
191
+ @driver.find("//*[@id='divInPopupTwo']")[0].text.should eql 'This is the text of divInPopupTwo'
192
+ end
193
+ @driver.find("//*[@id='divInMainWindow']")[0].text.should eql 'This is the text for divInMainWindow'
194
+ end
195
+ end
196
+ end
197
+
188
198
  shared_examples_for "driver with cookies support" do
189
- describe "#cleanup" do
199
+ describe "#reset!" do
190
200
  it "should set and clean cookies" do
191
201
  @driver.visit('/get_cookie')
192
202
  @driver.body.should_not include('test_cookie')
@@ -197,7 +207,7 @@ shared_examples_for "driver with cookies support" do
197
207
  @driver.visit('/get_cookie')
198
208
  @driver.body.should include('test_cookie')
199
209
 
200
- @driver.cleanup!
210
+ @driver.reset!
201
211
  @driver.visit('/get_cookie')
202
212
  @driver.body.should_not include('test_cookie')
203
213
  end
@@ -11,7 +11,7 @@ $(function() {
11
11
  $('#clickable').click(function() {
12
12
  var link = $(this);
13
13
  setTimeout(function() {
14
- $(link).after('<a href="#">Has been clicked</a>');
14
+ $(link).after('<a id="has-been-clicked" href="#">Has been clicked</a>');
15
15
  $(link).after('<input type="submit" value="New Here">');
16
16
  $(link).after('<input type="text" id="new_field">');
17
17
  $('#change').remove();
@@ -1,15 +1,17 @@
1
1
  require 'capybara/spec/test_app'
2
2
  require 'nokogiri'
3
3
 
4
- Dir[File.dirname(__FILE__)+'/session/*'].each { |group|
5
- require group
6
- }
4
+ Dir[File.dirname(__FILE__)+'/session/*'].each { |group| require group }
7
5
 
8
6
  shared_examples_for "session" do
9
7
  def extract_results(session)
10
8
  YAML.load Nokogiri::HTML(session.body).xpath("//pre[@id='results']").first.text
11
9
  end
12
10
 
11
+ after do
12
+ @session.reset!
13
+ end
14
+
13
15
  describe '#app' do
14
16
  it "should remember the application" do
15
17
  @session.app.should == TestApp
@@ -24,14 +26,14 @@ shared_examples_for "session" do
24
26
  @session.body.should include('Another World')
25
27
  end
26
28
  end
27
-
29
+
28
30
  describe '#body' do
29
31
  it "should return the unmodified page body" do
30
32
  @session.visit('/')
31
33
  @session.body.should include('Hello world!')
32
34
  end
33
35
  end
34
-
36
+
35
37
  describe '#source' do
36
38
  it "should return the unmodified page source" do
37
39
  @session.visit('/')
@@ -39,57 +41,11 @@ shared_examples_for "session" do
39
41
  end
40
42
  end
41
43
 
42
- describe '#scope_to' do
43
- let(:scope) { @session.scope_to("//p[@id='first']") }
44
- let(:more_scope) { scope.scope_to("//a[@id='foo']") }
45
-
46
- before do
47
- @session.visit('/with_html')
48
- end
49
-
50
- it 'has a simple link' do
51
- scope.should have_xpath("//a[@class='simple']")
52
- end
53
-
54
- it 'does not have a redirect link' do
55
- scope.should have_no_xpath("//a[@id='red']")
56
- end
57
-
58
- it 'does have a redirect link' do
59
- @session.should have_xpath("//a[@id='red']")
60
- end
61
-
62
- it 'does not share scopes' do
63
- @session.should have_xpath("//a[@id='red']")
64
- scope.should have_no_xpath("//a[@id='red']")
65
- @session.should have_xpath("//a[@id='red']")
66
- end
67
-
68
- context 'more_scope' do
69
- it 'has the text for foo' do
70
- more_scope.should have_content('ullamco')
71
- end
72
-
73
- it 'does not have a simple link' do
74
- more_scope.should have_no_xpath("//a[@class='simple']")
75
- end
76
-
77
- it 'has not overridden scope' do
78
- scope.should have_xpath("//a[@class='simple']")
79
- end
80
-
81
- it 'has not overridden session' do
82
- @session.should have_xpath("//p[@id='second']")
83
- end
84
- end
85
-
86
- end
87
-
88
44
  it_should_behave_like "all"
89
45
  it_should_behave_like "attach_file"
90
46
  it_should_behave_like "check"
91
47
  it_should_behave_like "choose"
92
- it_should_behave_like "click"
48
+ it_should_behave_like "click_link_or_button"
93
49
  it_should_behave_like "click_button"
94
50
  it_should_behave_like "click_link"
95
51
  it_should_behave_like "fill_in"
@@ -101,6 +57,7 @@ shared_examples_for "session" do
101
57
  it_should_behave_like "has_content"
102
58
  it_should_behave_like "has_css"
103
59
  it_should_behave_like "has_css"
60
+ it_should_behave_like "has_selector"
104
61
  it_should_behave_like "has_xpath"
105
62
  it_should_behave_like "has_link"
106
63
  it_should_behave_like "has_button"
@@ -110,9 +67,27 @@ shared_examples_for "session" do
110
67
  it_should_behave_like "select"
111
68
  it_should_behave_like "uncheck"
112
69
  it_should_behave_like "unselect"
113
- it_should_behave_like "locate"
114
70
  it_should_behave_like "within"
115
71
  it_should_behave_like "current_url"
72
+
73
+ it "should encode complex field names, like array[][value]" do
74
+ @session.visit('/form')
75
+ @session.fill_in('address1_city', :with =>'Paris')
76
+ @session.fill_in('address1_street', :with =>'CDG')
77
+ @session.fill_in('address2_city', :with => 'Mikolaiv')
78
+ @session.fill_in('address2_street', :with => 'PGS')
79
+ @session.click_button "awesome"
80
+
81
+ addresses=extract_results(@session)["addresses"]
82
+ addresses.should have(2).addresses
83
+
84
+ addresses[0]["street"].should == 'CDG'
85
+ addresses[0]["city"].should == 'Paris'
86
+
87
+ addresses[1]["street"].should == 'PGS'
88
+ addresses[1]["city"].should == 'Mikolaiv'
89
+ end
90
+
116
91
  end
117
92
 
118
93
 
@@ -16,16 +16,20 @@ shared_examples_for "all" do
16
16
 
17
17
  it "should accept an XPath instance" do
18
18
  @session.visit('/form')
19
- @xpath = Capybara::XPath.text_field('Name')
19
+ @xpath = XPath::HTML.fillable_field('Name')
20
20
  @result = @session.all(@xpath).map { |r| r.value }
21
21
  @result.should include('Smith', 'John', 'John Smith')
22
22
  end
23
23
 
24
24
  context "with css selectors" do
25
- it "should find the first element using the given locator" do
25
+ it "should find all elements using the given selector" do
26
26
  @session.all(:css, 'h1').first.text.should == 'This is a test'
27
27
  @session.all(:css, "input[id='test_field']").first[:value].should == 'monkey'
28
28
  end
29
+
30
+ it "should find all elements when given a list of selectors" do
31
+ @session.all(:css, 'h1, p').should have(4).elements
32
+ end
29
33
  end
30
34
 
31
35
  context "with xpath selectors" do
@@ -61,7 +65,7 @@ shared_examples_for "all" do
61
65
 
62
66
  it "should find any element using the given locator" do
63
67
  @session.within(:xpath, "//div[@id='for_bar']") do
64
- @session.all('//li').should have(2).elements
68
+ @session.all('.//li').should have(2).elements
65
69
  end
66
70
  end
67
71
  end
@@ -1,67 +1,65 @@
1
- module CheckSpec
2
- shared_examples_for "check" do
3
-
4
- describe "#check" do
5
- before do
6
- @session.visit('/form')
1
+ shared_examples_for "check" do
2
+
3
+ describe "#check" do
4
+ before do
5
+ @session.visit('/form')
6
+ end
7
+
8
+ describe "'checked' attribute" do
9
+ it "should be true if checked" do
10
+ @session.check("Terms of Use")
11
+ @session.find(:xpath, "//input[@id='form_terms_of_use']")['checked'].should be_true
7
12
  end
8
13
 
9
- describe "'checked' attribute" do
10
- it "should be true if checked" do
11
- @session.check("Terms of Use")
12
- @session.find(:xpath, "//input[@id='form_terms_of_use']")['checked'].should be_true
13
- end
14
-
15
- it "should be false if unchecked" do
16
- @session.find(:xpath, "//input[@id='form_terms_of_use']")['checked'].should be_false
17
- end
14
+ it "should be false if unchecked" do
15
+ @session.find(:xpath, "//input[@id='form_terms_of_use']")['checked'].should be_false
18
16
  end
17
+ end
19
18
 
20
- describe "checking" do
21
- it "should not change an already checked checkbox" do
22
- @session.find(:xpath, "//input[@id='form_pets_dog']")['checked'].should be_true
23
- @session.check('form_pets_dog')
24
- @session.find(:xpath, "//input[@id='form_pets_dog']")['checked'].should be_true
25
- end
26
-
27
- it "should check an unchecked checkbox" do
28
- @session.find(:xpath, "//input[@id='form_pets_cat']")['checked'].should be_false
29
- @session.check('form_pets_cat')
30
- @session.find(:xpath, "//input[@id='form_pets_cat']")['checked'].should be_true
31
- end
19
+ describe "checking" do
20
+ it "should not change an already checked checkbox" do
21
+ @session.find(:xpath, "//input[@id='form_pets_dog']")['checked'].should be_true
22
+ @session.check('form_pets_dog')
23
+ @session.find(:xpath, "//input[@id='form_pets_dog']")['checked'].should be_true
32
24
  end
33
25
 
34
- describe "unchecking" do
35
- it "should not change an already unchecked checkbox" do
36
- @session.find(:xpath, "//input[@id='form_pets_cat']")['checked'].should be_false
37
- @session.uncheck('form_pets_cat')
38
- @session.find(:xpath, "//input[@id='form_pets_cat']")['checked'].should be_false
39
- end
40
-
41
- it "should uncheck a checked checkbox" do
42
- @session.find(:xpath, "//input[@id='form_pets_dog']")['checked'].should be_true
43
- @session.uncheck('form_pets_dog')
44
- @session.find(:xpath, "//input[@id='form_pets_dog']")['checked'].should be_false
45
- end
26
+ it "should check an unchecked checkbox" do
27
+ @session.find(:xpath, "//input[@id='form_pets_cat']")['checked'].should be_false
28
+ @session.check('form_pets_cat')
29
+ @session.find(:xpath, "//input[@id='form_pets_cat']")['checked'].should be_true
46
30
  end
31
+ end
47
32
 
48
- it "should check a checkbox by id" do
49
- @session.check("form_pets_cat")
50
- @session.click_button('awesome')
51
- extract_results(@session)['pets'].should include('dog', 'cat', 'hamster')
33
+ describe "unchecking" do
34
+ it "should not change an already unchecked checkbox" do
35
+ @session.find(:xpath, "//input[@id='form_pets_cat']")['checked'].should be_false
36
+ @session.uncheck('form_pets_cat')
37
+ @session.find(:xpath, "//input[@id='form_pets_cat']")['checked'].should be_false
52
38
  end
53
39
 
54
- it "should check a checkbox by label" do
55
- @session.check("Cat")
56
- @session.click_button('awesome')
57
- extract_results(@session)['pets'].should include('dog', 'cat', 'hamster')
40
+ it "should uncheck a checked checkbox" do
41
+ @session.find(:xpath, "//input[@id='form_pets_dog']")['checked'].should be_true
42
+ @session.uncheck('form_pets_dog')
43
+ @session.find(:xpath, "//input[@id='form_pets_dog']")['checked'].should be_false
58
44
  end
45
+ end
46
+
47
+ it "should check a checkbox by id" do
48
+ @session.check("form_pets_cat")
49
+ @session.click_button('awesome')
50
+ extract_results(@session)['pets'].should include('dog', 'cat', 'hamster')
51
+ end
52
+
53
+ it "should check a checkbox by label" do
54
+ @session.check("Cat")
55
+ @session.click_button('awesome')
56
+ extract_results(@session)['pets'].should include('dog', 'cat', 'hamster')
57
+ end
59
58
 
60
- context "with a locator that doesn't exist" do
61
- it "should raise an error" do
62
- running { @session.check('does not exist') }.should raise_error(Capybara::ElementNotFound)
63
- end
59
+ context "with a locator that doesn't exist" do
60
+ it "should raise an error" do
61
+ running { @session.check('does not exist') }.should raise_error(Capybara::ElementNotFound)
64
62
  end
65
63
  end
66
64
  end
67
- end
65
+ end
@@ -99,6 +99,15 @@ shared_examples_for "click_button" do
99
99
  it "should not serialize a select tag without options" do
100
100
  @results['tendency'].should be_nil
101
101
  end
102
+
103
+ it "should not submit disabled fields" do
104
+ @results['disabled_text_field'].should be_nil
105
+ @results['disabled_textarea'].should be_nil
106
+ @results['disabled_checkbox'].should be_nil
107
+ @results['disabled_radio'].should be_nil
108
+ @results['disabled_select'].should be_nil
109
+ @results['disabled_file'].should be_nil
110
+ end
102
111
  end
103
112
  end
104
113
 
@@ -0,0 +1,37 @@
1
+ shared_examples_for "click_link_or_button" do
2
+ describe '#click' do
3
+ it "should click on a link" do
4
+ @session.visit('/with_html')
5
+ @session.click_link_or_button('labore')
6
+ @session.body.should include('Bar')
7
+ end
8
+
9
+ it "should click on a button" do
10
+ @session.visit('/form')
11
+ @session.click_link_or_button('awe123')
12
+ extract_results(@session)['first_name'].should == 'John'
13
+ end
14
+
15
+ it "should click on a button with no type attribute" do
16
+ @session.visit('/form')
17
+ @session.click_link_or_button('no_type')
18
+ extract_results(@session)['first_name'].should == 'John'
19
+ end
20
+
21
+ it "should be aliased as click for backward compatibility" do
22
+ Capybara.should_receive(:deprecate).with("click", "click_link_or_button")
23
+ @session.visit('/form')
24
+ @session.click('awe123')
25
+ extract_results(@session)['first_name'].should == 'John'
26
+ end
27
+
28
+ context "with a locator that doesn't exist" do
29
+ it "should raise an error" do
30
+ @session.visit('/with_html')
31
+ running do
32
+ @session.click_link_or_button('does not exist')
33
+ end.should raise_error(Capybara::ElementNotFound)
34
+ end
35
+ end
36
+ end
37
+ end