terminus 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. data/README.rdoc +27 -89
  2. data/bin/terminus +7 -23
  3. data/lib/capybara/driver/terminus.rb +30 -11
  4. data/lib/terminus.rb +33 -22
  5. data/lib/terminus/application.rb +13 -7
  6. data/lib/terminus/browser.rb +110 -28
  7. data/lib/terminus/controller.rb +51 -20
  8. data/lib/terminus/host.rb +22 -0
  9. data/lib/terminus/node.rb +23 -4
  10. data/lib/terminus/proxy.rb +62 -0
  11. data/lib/terminus/proxy/driver_body.rb +63 -0
  12. data/lib/terminus/proxy/external.rb +25 -0
  13. data/lib/terminus/proxy/rewrite.rb +20 -0
  14. data/lib/terminus/public/icon.png +0 -0
  15. data/lib/terminus/public/loader.js +1 -0
  16. data/lib/terminus/public/style.css +43 -0
  17. data/lib/terminus/public/syn/browsers.js +150 -0
  18. data/lib/terminus/public/syn/drag/drag.js +322 -0
  19. data/lib/terminus/public/syn/key.js +905 -0
  20. data/lib/terminus/public/syn/mouse.js +284 -0
  21. data/lib/terminus/public/syn/synthetic.js +830 -0
  22. data/lib/{public → terminus/public}/terminus.js +109 -40
  23. data/lib/terminus/server.rb +5 -12
  24. data/lib/terminus/timeouts.rb +2 -2
  25. data/lib/{views/bookmarklet.erb → terminus/views/bootstrap.erb} +17 -12
  26. data/lib/terminus/views/index.erb +21 -0
  27. data/lib/terminus/views/infinite.html +16 -0
  28. data/spec/reports/chrome.txt +748 -0
  29. data/spec/reports/firefox.txt +748 -0
  30. data/spec/reports/opera.txt +748 -0
  31. data/spec/reports/safari.txt +748 -0
  32. data/spec/spec_helper.rb +18 -14
  33. data/spec/terminus_driver_spec.rb +7 -5
  34. data/spec/terminus_session_spec.rb +5 -18
  35. metadata +71 -57
  36. data/lib/public/loader.js +0 -1
  37. data/lib/public/style.css +0 -49
  38. data/lib/public/syn.js +0 -2355
  39. data/lib/views/index.erb +0 -32
@@ -5,27 +5,28 @@ Terminus = {
5
5
  if (this._client) return;
6
6
 
7
7
  this._pageId = Faye.random();
8
-
9
8
  this._id = window.name = window.name || Faye.random();
10
9
 
11
10
  this.Registry.initialize();
12
11
  this.Worker.initialize();
12
+ this.AjaxMonitor.initialize();
13
13
 
14
- var client = this._client = new Faye.Client(endpoint);
14
+ Faye.Event.on(window, 'beforeunload', function() { Terminus.disabled = true });
15
15
 
16
- this._client.subscribe('/terminus/commands', function(message) {
17
- this.execute(message.command);
18
- }, this);
16
+ var client = this._client = new Faye.Client(endpoint);
19
17
 
20
- this._client.subscribe('/terminus/clients/' + this._id, function(message) {
18
+ var subscription = this._client.subscribe('/terminus/clients/' + this.getId(), function(message) {
21
19
  var command = message.command,
22
20
  method = command.shift(),
23
21
  driver = this.Driver,
24
22
  worker = this.Worker,
23
+ posted = false,
25
24
  self = this;
26
25
 
27
26
  command.push(function(result) {
27
+ if (posted) return;
28
28
  self.postResult(message.commandId, result);
29
+ posted = true;
29
30
  });
30
31
 
31
32
  worker.monitor = true;
@@ -33,39 +34,48 @@ Terminus = {
33
34
  worker.monitor = false;
34
35
  }, this);
35
36
 
36
- var self = this;
37
- setTimeout(function() { self.ping() }, 100);
37
+ subscription.callback(this.ping, this);
38
+ },
39
+
40
+ getId: function() {
41
+ try { return window.opener.Terminus.getId() + '/' + this._id }
42
+ catch (e) { return this._id }
38
43
  },
39
44
 
40
45
  browserDetails: function() {
41
46
  return {
42
- id: this._id,
43
- page: this._pageId,
44
- ua: navigator.userAgent,
45
- url: window.location.href
47
+ id: this.getId(),
48
+ parent: (parent && parent !== window) ? parent.name : null,
49
+ page: this._pageId,
50
+ ua: navigator.userAgent,
51
+ url: window.location.href,
52
+ infinite: !!window.TERMINUS_INFINITE_REDIRECT
46
53
  };
47
54
  },
48
55
 
56
+ getAttribute: function(node, name) {
57
+ return Terminus.isIE ? node.getAttributeNode(name).nodeValue
58
+ : node.getAttribute(name);
59
+ },
60
+
49
61
  ping: function() {
62
+ if (this.disabled) return;
63
+
50
64
  this._client.publish('/terminus/ping', this.browserDetails());
51
65
  var self = this;
52
66
  setTimeout(function() { self.ping() }, 3000);
53
67
  },
54
68
 
55
69
  postResult: function(commandId, result) {
56
- if (!commandId) return;
70
+ if (this.disabled || !commandId) return;
57
71
 
58
72
  this._client.publish('/terminus/results', {
59
- id: this._id,
73
+ id: this.getId(),
60
74
  commandId: commandId,
61
75
  result: result
62
76
  });
63
77
  },
64
78
 
65
- execute: function(command) {
66
- eval(command);
67
- },
68
-
69
79
  Driver: {
70
80
  _node: function(id) {
71
81
  return Terminus.Registry.get(id);
@@ -77,10 +87,13 @@ Terminus = {
77
87
  if (name === 'checked' || name === 'selected')
78
88
  return callback(!!node[name]);
79
89
 
80
- if (Terminus.isIE)
81
- return callback(node.getAttributeNode(name).nodeValue);
82
-
83
- callback(node.getAttribute(name));
90
+ callback(Terminus.getAttribute(node, name));
91
+ },
92
+
93
+ set_attribute: function(nodeId, name, value, callback) {
94
+ var node = this._node(nodeId);
95
+ node.setAttribute(name, value);
96
+ callback(true);
84
97
  },
85
98
 
86
99
  body: function(callback) {
@@ -89,11 +102,7 @@ Terminus = {
89
102
  '<html>\n' + html.innerHTML + '\n</html>\n');
90
103
  },
91
104
 
92
- source: function(callback) {
93
- callback(Terminus.originalSource);
94
- },
95
-
96
- reset: function(callback) {
105
+ clear_cookies: function(callback) {
97
106
  var cookies = document.cookie.split(';'), name;
98
107
 
99
108
  var expiry = new Date();
@@ -106,9 +115,19 @@ Terminus = {
106
115
  callback();
107
116
  },
108
117
 
109
- click: function(nodeId, callback) {
110
- var element = this._node(nodeId);
118
+ click: function(nodeId, options, callback) {
119
+ var element = this._node(nodeId),
120
+ timeout = options.resynchronization_timeout;
121
+
111
122
  Syn.trigger('click', {}, element);
123
+
124
+ if (options.resynchronize === false) return callback();
125
+
126
+ if (timeout)
127
+ Terminus.Worker._setTimeout.call(window, function() {
128
+ callback('failed to resynchronize, ajax request timed out');
129
+ }, 1000 * timeout);
130
+
112
131
  Terminus.Worker.callback(callback);
113
132
  },
114
133
 
@@ -140,10 +159,15 @@ Terminus = {
140
159
  return callback(list);
141
160
  },
142
161
 
162
+ frame_src: function(name, callback) {
163
+ var frame = document.getElementById(name);
164
+ callback(frame.src);
165
+ },
166
+
143
167
  is_visible: function(nodeId, callback) {
144
168
  var node = this._node(nodeId);
145
169
 
146
- while (node.tagName.toLowerCase() !== 'body') {
170
+ while (node.tagName && node.tagName.toLowerCase() !== 'body') {
147
171
  if (node.style.display === 'none' || node.type === 'hidden')
148
172
  return callback(false);
149
173
  node = node.parentNode;
@@ -159,16 +183,24 @@ Terminus = {
159
183
  },
160
184
 
161
185
  set: function(nodeId, value, callback) {
162
- var field = this._node(nodeId);
186
+ var field = this._node(nodeId),
187
+ max = Terminus.getAttribute(field, 'maxlength');
188
+
163
189
  if (field.type === 'file') return callback('not_allowed');
164
190
 
165
191
  Syn.trigger('focus', {}, field);
166
192
  Syn.trigger('click', {}, field);
167
193
 
168
194
  switch (typeof value) {
169
- case 'string': field.value = value; break;
170
- case 'boolean': field.checked = value; break;
195
+ case 'string':
196
+ if (max) value = value.substr(0, parseInt(max));
197
+ field.value = value;
198
+ break;
199
+ case 'boolean':
200
+ field.checked = value;
201
+ break;
171
202
  }
203
+ Syn.trigger('change', {}, field);
172
204
  callback();
173
205
  },
174
206
 
@@ -177,9 +209,12 @@ Terminus = {
177
209
  },
178
210
 
179
211
  text: function(nodeId, callback) {
180
- var node = this._node(nodeId),
181
- text = node.textContent || node.innerText || '';
212
+ var node = this._node(nodeId),
213
+ text = node.textContent || node.innerText || '',
214
+ scripts = node.getElementsByTagName('script'),
215
+ i = scripts.length;
182
216
 
217
+ while (i--) text = text.replace(scripts[i].textContent || scripts[i].innerText, '');
183
218
  text = text.replace(/^\s*|\s*$/g, '');
184
219
  callback(text);
185
220
  },
@@ -244,8 +279,10 @@ Terminus = {
244
279
  },
245
280
 
246
281
  callback: function(callback, scope) {
247
- if (this._pending === 0) return callback.call(scope);
248
- else this._callbacks.push([callback, scope]);
282
+ if (this._pending === 0)
283
+ this._setTimeout.call(window, function() { callback.call(scope) }, 0);
284
+ else
285
+ this._callbacks.push([callback, scope]);
249
286
  },
250
287
 
251
288
  suspend: function() {
@@ -278,14 +315,12 @@ Terminus = {
278
315
  };
279
316
 
280
317
  window.setTimeout = function(callback, delay) {
281
- var id = timeout(function() {
318
+ var id = timeout.call(window, function() {
282
319
  try {
283
320
  switch (typeof callback) {
284
321
  case 'function': callback(); break;
285
322
  case 'string': eval(callback); break;
286
323
  }
287
- } catch (e) {
288
- throw e;
289
324
  } finally {
290
325
  finish(id);
291
326
  }
@@ -302,6 +337,40 @@ Terminus = {
302
337
  finish(id);
303
338
  return clear(id);
304
339
  };
340
+
341
+ this._setTimeout = timeout;
342
+ }
343
+ },
344
+
345
+ AjaxMonitor: {
346
+ initialize: function() {
347
+ if (window.jQuery) this._patchJquery();
348
+ },
349
+
350
+ _patchJquery: function() {
351
+ var ajax = jQuery.ajax;
352
+ jQuery.ajax = function(url, settings) {
353
+ var options = ((typeof url === 'string') ? settings : url) || {},
354
+ complete = options.complete,
355
+ monitor = Terminus.Worker.monitor;
356
+
357
+ options.complete = function() {
358
+ var result;
359
+ try {
360
+ result = complete.apply(this, arguments);
361
+ } finally {
362
+ if (monitor) Terminus.Worker.resume();
363
+ }
364
+ return result;
365
+ };
366
+
367
+ if (monitor) Terminus.Worker.suspend();
368
+
369
+ if (typeof url === 'string')
370
+ return ajax.call(jQuery, url, options);
371
+ else
372
+ return ajax.call(jQuery, options);
373
+ };
305
374
  }
306
375
  }
307
376
  };
@@ -5,10 +5,6 @@ module Terminus
5
5
  @options = options
6
6
  end
7
7
 
8
- def execute(script, &callback)
9
- messenger.publish('/terminus/commands', :command => script)
10
- end
11
-
12
8
  def running?
13
9
  not @server.nil?
14
10
  end
@@ -16,7 +12,6 @@ module Terminus
16
12
  def run!
17
13
  return if running?
18
14
  handler = Rack::Handler.get('thin')
19
- Terminus.ensure_reactor_running
20
15
  handler.run(app, :Port => @options[:port]) { |s| @server = s }
21
16
  end
22
17
 
@@ -29,13 +24,11 @@ module Terminus
29
24
  private
30
25
 
31
26
  def app
32
- return @app if defined?(@app)
33
- frontend = Application.new
34
- @app = Faye::RackAdapter.new(frontend, :mount => FAYE_MOUNT, :timeout => 15)
35
- end
36
-
37
- def messenger
38
- app.get_client
27
+ @app ||= Rack::Builder.new {
28
+ use Terminus::Proxy
29
+ use Faye::RackAdapter, :mount => FAYE_MOUNT, :timeout => 15
30
+ run Application.new
31
+ }.to_app
39
32
  end
40
33
 
41
34
  end
@@ -5,7 +5,7 @@ module Terminus
5
5
  end
6
6
 
7
7
  include Faye::Timeouts
8
- TIMEOUT = 10
8
+ TIMEOUT = 30
9
9
 
10
10
  def wait_with_timeout(name, duration = TIMEOUT, &predicate)
11
11
  result, time_out = nil, false
@@ -13,7 +13,7 @@ module Terminus
13
13
 
14
14
  while !result and !time_out
15
15
  result = predicate.call
16
- sleep 0.1
16
+ sleep 0.001
17
17
  end
18
18
 
19
19
  raise TimeoutError.new("Waited #{duration}s but could not get a #{name}") if time_out
@@ -2,10 +2,8 @@
2
2
  var faye = '<%= ::Terminus::FAYE_MOUNT %>',
3
3
  host = '<%= host %>';
4
4
 
5
- var html = document.getElementsByTagName('html')[0],
6
- source = '<html>\n' + html.innerHTML + '\n</html>\n';
7
-
8
5
  JSCLASS_PATH = host + '/js.class/';
6
+ SYN_FILES = ['synthetic', 'mouse', 'browsers', 'key', 'drag/drag'];
9
7
 
10
8
  var withPackageManager = function(callback) {
11
9
  if (window.JS && JS.Packages) return callback();
@@ -28,21 +26,28 @@
28
26
  };
29
27
 
30
28
  withPackageManager(function() {
31
- JS.Packages(function() {
32
- this.file(host + faye + '/client.js')
33
- .provides('Faye', 'Faye.Client')
34
- .setup(function() { Faye.Client.prototype.MAX_DELAY = 0 });
29
+ JS.Packages(function() { with(this) {
30
+ loader(function(callback) {
31
+ load(host + faye + '/client.js', callback);
32
+ }).provides('Faye', 'Faye.Client');
35
33
 
36
- this.file(host + '/syn.js')
37
- .provides('Syn');
34
+ loader(function(callback) {
35
+ if (!window.steal) window.steal = {then: function(fn) { fn() }};
36
+ var inject = function() {
37
+ var synFile = SYN_FILES.shift();
38
+ if (!synFile) return callback();
39
+ load(host + '/syn/' + synFile + '.js', inject);
40
+ };
41
+ inject();
42
+
43
+ }).provides('Syn');
38
44
 
39
- this.file(host + '/terminus.js')
45
+ file(host + '/terminus.js')
40
46
  .requires('Faye.Client', 'document.evaluate', 'Syn')
41
47
  .provides('Terminus');
42
- });
48
+ }});
43
49
 
44
50
  JS.require('Terminus', function() {
45
- Terminus.originalSource = source;
46
51
  Terminus.connect(host + faye);
47
52
  });
48
53
  });
@@ -0,0 +1,21 @@
1
+ <!doctype html>
2
+
3
+ <html>
4
+ <head>
5
+ <meta http-equiv="content-type" content="text/html; charset=utf-8">
6
+ <link rel="stylesheet" type="text/css" href="/style.css">
7
+ <title>Terminus</title>
8
+ </head>
9
+ <body>
10
+
11
+ <div class="bg"></div>
12
+
13
+ <h1><a href="javascript:<%= bootstrap %>">Terminus</a></h1>
14
+
15
+ <p><a href="http://terminus.jcoglan.com">Terminus</a><br>
16
+ Copyright &copy; 2010&ndash;2011 <a href="http://jcoglan.com">James Coglan</a><br>
17
+ Released under the MIT license</p>
18
+
19
+ </body>
20
+ </html>
21
+
@@ -0,0 +1,16 @@
1
+ <!doctype html>
2
+ <html>
3
+ <head>
4
+ <meta http-equiv="Content-type" content="text/html; charset=utf-8">
5
+ <title>Infinite Redirect Detected</title>
6
+ </head>
7
+ <body>
8
+
9
+ <h1>Infinite Redirect Detected</h1>
10
+
11
+ <script type="text/javascript">
12
+ TERMINUS_INFINITE_REDIRECT = true
13
+ </script>
14
+
15
+ </body>
16
+ </html>
@@ -0,0 +1,748 @@
1
+
2
+ Capybara::Session
3
+ with non-existant driver
4
+ should raise an error
5
+
6
+ Capybara::Driver::Terminus
7
+ it should behave like driver
8
+ #visit
9
+ should move to another page
10
+ should show the correct URL
11
+ #body
12
+ should return text reponses
13
+ should return the full response html
14
+ encoding of response between ascii and utf8
15
+ should be valid with html entities
16
+ should be valid without html entities
17
+ #find
18
+ with xpath selector
19
+ should extract node texts
20
+ should extract node attributes
21
+ should extract boolean node attributes
22
+ should allow retrieval of the value
23
+ should allow assignment of field value
24
+ should extract node tag name
25
+ should extract node visibility
26
+ should extract node checked state
27
+ should extract node selected state
28
+ should return document text on /html selector
29
+ it should behave like driver with header support
30
+ should make headers available through response_headers
31
+ it should behave like driver with status code support
32
+ should make the status code available through status_code
33
+ it should behave like driver with javascript support
34
+ #find
35
+ should find dynamically changed nodes
36
+ #drag_to
37
+ should drag and drop an object
38
+ #evaluate_script
39
+ should return the value of the executed script
40
+ it should behave like driver with resynchronization support
41
+ #find
42
+ with synchronization turned on
43
+ should wait for all ajax requests to finish
44
+ with resynchronization turned off
45
+ should not wait for ajax requests to finish
46
+ with short synchronization timeout
47
+ should raise an error
48
+ it should behave like driver with frame support
49
+ #within_frame
50
+ should find the div in frameOne
51
+ should find the div in FrameTwo
52
+ should find the text div in the main window after finding text in frameOne
53
+ should find the text div in the main window after finding text in frameTwo
54
+ it should behave like driver with support for window switching
55
+ #within_window
56
+ should find the div in firstPopup
57
+ should find the div in secondPopup
58
+ should find the divs in both popups
59
+ should find the div in the main window after finding a div in a popup
60
+ it should behave like driver with cookies support
61
+ #reset!
62
+ should set and clean cookies
63
+ it should behave like driver with infinite redirect detection
64
+ should follow 5 redirects
65
+ should not follow more than 5 redirects
66
+
67
+ Capybara::Session
68
+ with terminus driver
69
+ it should behave like session
70
+ should encode complex field names, like array[][value]
71
+ #visit
72
+ should fetch a response from the driver
73
+ #body
74
+ should return the unmodified page body
75
+ #html
76
+ should return the unmodified page body
77
+ #source
78
+ should return the unmodified page source
79
+ #reset_session!
80
+ removes cookies
81
+ resets current host
82
+ resets current path
83
+ resets page body
84
+ it should behave like all
85
+ #all
86
+ should find all elements using the given locator
87
+ should return an empty array when nothing was found
88
+ should accept an XPath instance
89
+ with css selectors
90
+ should find all elements using the given selector
91
+ should find all elements when given a list of selectors
92
+ with xpath selectors
93
+ should find the first element using the given locator
94
+ with css as default selector
95
+ should find the first element using the given locator
96
+ with visible filter
97
+ should only find visible nodes
98
+ should only find invisible nodes
99
+ within a scope
100
+ should find any element using the given locator
101
+ it should behave like first
102
+ #first
103
+ should find the first element using the given locator
104
+ should return nil when nothing was found
105
+ should accept an XPath instance
106
+ with css selectors
107
+ should find the first element using the given selector
108
+ with xpath selectors
109
+ should find the first element using the given locator
110
+ with css as default selector
111
+ should find the first element using the given locator
112
+ with visible filter
113
+ should only find visible nodes if true given
114
+ should include invisible nodes if false given
115
+ with prefer visible elements
116
+ should find invisible elements if no visible element exists
117
+ should prefer visible elements over invisible elements
118
+ should return the first invisible element if no visible elements exist
119
+ find visible links normally
120
+ without prefer visible elements
121
+ should find invisible elements if no visible element exists
122
+ should not prefer visible elements over invisible elements
123
+ within a scope
124
+ should find the first element using the given locator
125
+ it should behave like attach_file
126
+ #attach_file
127
+ with normal form
128
+ should set a file path by id (FAILED - 1)
129
+ should set a file path by label (FAILED - 2)
130
+ with multipart form
131
+ should set a file path by id (FAILED - 3)
132
+ should set a file path by label (FAILED - 4)
133
+ should not break if no file is submitted
134
+ should send content type text/plain when uploading a text file (FAILED - 5)
135
+ should send content type image/jpeg when uploading an image (FAILED - 6)
136
+ should not break when using HTML5 multiple file input (FAILED - 7)
137
+ with a locator that doesn't exist
138
+ should raise an error
139
+ with a path that doesn't exist
140
+ should raise an error
141
+ it should behave like check
142
+ #check
143
+ should check a checkbox by id
144
+ should check a checkbox by label
145
+ 'checked' attribute
146
+ should be true if checked
147
+ should be false if unchecked
148
+ checking
149
+ should not change an already checked checkbox
150
+ should check an unchecked checkbox
151
+ unchecking
152
+ should not change an already unchecked checkbox
153
+ should uncheck a checked checkbox
154
+ with a locator that doesn't exist
155
+ should raise an error
156
+ it should behave like choose
157
+ #choose
158
+ should choose a radio button by id
159
+ should choose a radio button by label
160
+ with a locator that doesn't exist
161
+ should raise an error
162
+ it should behave like click_link_or_button
163
+ #click
164
+ should click on a link
165
+ should click on a button
166
+ should click on a button with no type attribute
167
+ should be aliased as click_on
168
+ with a locator that doesn't exist
169
+ should raise an error
170
+ it should behave like click_button
171
+ #click_button
172
+ should serialize and send valueless buttons that were clicked
173
+ should not send image buttons that were not clicked
174
+ should serialize and send GET forms
175
+ should follow redirects
176
+ should post pack to the same URL when no action given
177
+ should post pack to the same URL when blank action given
178
+ with multiple values with the same name
179
+ should use the latest given value
180
+ with a form that has a relative url as an action
181
+ should post to the correct url
182
+ with a form that has no action specified
183
+ should post to the correct url
184
+ with value given on a submit button
185
+ on a form with HTML5 fields
186
+ should serialise and submit search fields
187
+ should serialise and submit email fields
188
+ should serialise and submit url fields
189
+ should serialise and submit tel fields
190
+ should serialise and submit color fields
191
+ on an HTML4 form
192
+ should serialize and submit text fields
193
+ should escape fields when submitting
194
+ should serialize and submit password fields
195
+ should serialize and submit hidden fields
196
+ should not serialize fields from other forms
197
+ should submit the button that was clicked, but not other buttons
198
+ should serialize radio buttons
199
+ should serialize check boxes
200
+ should serialize text areas
201
+ should serialize select tag with values
202
+ should serialize select tag without values
203
+ should serialize first option for select tag with no selection
204
+ should not serialize a select tag without options
205
+ should not submit disabled fields
206
+ with id given on a submit button
207
+ should submit the associated form
208
+ should work with partial matches
209
+ with title given on a submit button
210
+ should submit the associated form
211
+ should work with partial matches
212
+ with alt given on an image button
213
+ should submit the associated form
214
+ should work with partial matches
215
+ with value given on an image button
216
+ should submit the associated form
217
+ should work with partial matches
218
+ with id given on an image button
219
+ should submit the associated form
220
+ with title given on an image button
221
+ should submit the associated form
222
+ should work with partial matches
223
+ with text given on a button defined by <button> tag
224
+ should submit the associated form
225
+ should work with partial matches
226
+ should prefer exact matches over partial matches
227
+ with id given on a button defined by <button> tag
228
+ should submit the associated form
229
+ should serialize and send GET forms
230
+ with value given on a button defined by <button> tag
231
+ should submit the associated form
232
+ should work with partial matches
233
+ should prefer exact matches over partial matches
234
+ with title given on a button defined by <button> tag
235
+ should submit the associated form
236
+ should work with partial matches
237
+ with a locator that doesn't exist
238
+ should raise an error
239
+ it should behave like click_link
240
+ #click_link
241
+ should follow redirects
242
+ should follow redirects
243
+ should add query string to current URL with naked query string
244
+ should do nothing on anchor links
245
+ should do nothing on URL+anchor links for the same page
246
+ should follow link on URL+anchor links for a different page
247
+ raise an error with links with no href
248
+ with id given
249
+ should take user to the linked page
250
+ with text given
251
+ should take user to the linked page
252
+ should accept partial matches
253
+ should prefer exact matches over partial matches
254
+ with title given
255
+ should take user to the linked page
256
+ should accept partial matches
257
+ should prefer exact matches over partial matches
258
+ with alternative text given to a contained image
259
+ should take user to the linked page
260
+ should take user to the linked page
261
+ should prefer exact matches over partial matches
262
+ with a locator that doesn't exist
263
+ should raise an error
264
+ it should behave like fill_in
265
+ #fill_in
266
+ should fill in a text field by id
267
+ should fill in a text field by name
268
+ should fill in a text field by label without for (FAILED - 8)
269
+ should fill in a url field by label without for
270
+ should favour exact label matches over partial matches
271
+ should fill in a textarea by id
272
+ should fill in a textarea by label
273
+ should fill in a textarea by name
274
+ should fill in a password field by id
275
+ should fill in a field with a custom type
276
+ should fill in a field without a type
277
+ should fill in a text field respecting its maxlength attribute
278
+ should fill in a password field by name
279
+ should fill in a password field by label
280
+ should fill in a password field by name
281
+ should prefer exact matches over partial matches
282
+ should throw an exception if a hash containing 'with' is not provided
283
+ with ignore_hidden_fields
284
+ should not find a hidden field
285
+ with a locator that doesn't exist
286
+ should raise an error
287
+ it should behave like find_button
288
+ #find_button
289
+ should find any field
290
+ should raise error if the field doesn't exist
291
+ it should behave like find_field
292
+ #find_field
293
+ should find any field
294
+ should raise error if the field doesn't exist
295
+ should be aliased as 'field_labeled' for webrat compatibility
296
+ it should behave like find_link
297
+ #find_link
298
+ should find any field
299
+ should raise error if the field doesn't exist
300
+ it should behave like find_by_id
301
+ #find_by_id
302
+ should find any element by id
303
+ should raise error if no element with id is found
304
+ it should behave like find
305
+ #find
306
+ should find the first element using the given locator
307
+ should find the first element using the given locator and options
308
+ should raise ElementNotFound with specified fail message if nothing was found
309
+ should raise ElementNotFound with a useful default message if nothing was found
310
+ should accept an XPath instance and respect the order of paths
311
+ the returned node
312
+ should act like a session object
313
+ should scope CSS selectors
314
+ with css selectors
315
+ should find the first element using the given locator
316
+ with id selectors
317
+ should find the first element using the given locator
318
+ with xpath selectors
319
+ should find the first element using the given locator
320
+ with custom selector
321
+ should use the custom selector
322
+ with custom selector with :for option
323
+ should use the selector when it matches the :for option
324
+ with custom selector with failure_message option
325
+ should raise an error with the failure message if the element is not found
326
+ should pass the selector as the second argument
327
+ with css as default selector
328
+ should find the first element using the given locator
329
+ within a scope
330
+ should find the first element using the given locator
331
+ it should behave like has_content
332
+ #has_content?
333
+ should be true if the given content is on the page at least once
334
+ should be true if scoped to an element which has the content
335
+ should be false if scoped to an element which does not have the content
336
+ should ignore tags
337
+ should ignore extra whitespace and newlines
338
+ should be false if the given content is not on the page
339
+ should handle single quotes in the content
340
+ should handle double quotes in the content
341
+ should handle mixed single and double quotes in the content
342
+ #has_no_content?
343
+ should be false if the given content is on the page at least once
344
+ should be false if scoped to an element which has the content
345
+ should be true if scoped to an element which does not have the content
346
+ should ignore tags
347
+ should be true if the given content is not on the page
348
+ should handle single quotes in the content
349
+ should handle double quotes in the content
350
+ should handle mixed single and double quotes in the content
351
+ it should behave like has_css
352
+ #has_css?
353
+ should be true if the given selector is on the page
354
+ should be false if the given selector is not on the page
355
+ should respect scopes
356
+ with between
357
+ should be true if the content occurs within the range given
358
+ should be false if the content occurs more or fewer times than range
359
+ should be false if the content isn't on the page at all
360
+ with count
361
+ should be true if the content is on the page the given number of times
362
+ should be false if the content occurs the given number of times
363
+ should be false if the content isn't on the page at all
364
+ should coerce count to an integer
365
+ with maximum
366
+ should be true when content occurs same or fewer times than given
367
+ should be false when content occurs more times than given
368
+ should be false if the content isn't on the page at all
369
+ should coerce maximum to an integer
370
+ with minimum
371
+ should be true when content occurs same or more times than given
372
+ should be false when content occurs fewer times than given
373
+ should be false if the content isn't on the page at all
374
+ should coerce minimum to an integer
375
+ with text
376
+ should discard all matches where the given string is not contained
377
+ should discard all matches where the given regexp is not matched
378
+ #has_no_css?
379
+ should be false if the given selector is on the page
380
+ should be true if the given selector is not on the page
381
+ should respect scopes
382
+ with between
383
+ should be false if the content occurs within the range given
384
+ should be true if the content occurs more or fewer times than range
385
+ should be true if the content isn't on the page at all
386
+ with count
387
+ should be false if the content is on the page the given number of times
388
+ should be true if the content is on the page the given number of times
389
+ should be true if the content isn't on the page at all
390
+ should coerce count to an integer
391
+ with maximum
392
+ should be false when content occurs same or fewer times than given
393
+ should be true when content occurs more times than given
394
+ should be true if the content isn't on the page at all
395
+ should coerce maximum to an integer
396
+ with minimum
397
+ should be false when content occurs more times than given
398
+ should be true when content occurs fewer times than given
399
+ should be true if the content isn't on the page at all
400
+ should coerce minimum to an integer
401
+ with text
402
+ should discard all matches where the given string is not contained
403
+ should discard all matches where the given regexp is not matched
404
+ it should behave like has_css
405
+ #has_css?
406
+ should be true if the given selector is on the page
407
+ should be false if the given selector is not on the page
408
+ should respect scopes
409
+ with between
410
+ should be true if the content occurs within the range given
411
+ should be false if the content occurs more or fewer times than range
412
+ should be false if the content isn't on the page at all
413
+ with count
414
+ should be true if the content is on the page the given number of times
415
+ should be false if the content occurs the given number of times
416
+ should be false if the content isn't on the page at all
417
+ should coerce count to an integer
418
+ with maximum
419
+ should be true when content occurs same or fewer times than given
420
+ should be false when content occurs more times than given
421
+ should be false if the content isn't on the page at all
422
+ should coerce maximum to an integer
423
+ with minimum
424
+ should be true when content occurs same or more times than given
425
+ should be false when content occurs fewer times than given
426
+ should be false if the content isn't on the page at all
427
+ should coerce minimum to an integer
428
+ with text
429
+ should discard all matches where the given string is not contained
430
+ should discard all matches where the given regexp is not matched
431
+ #has_no_css?
432
+ should be false if the given selector is on the page
433
+ should be true if the given selector is not on the page
434
+ should respect scopes
435
+ with between
436
+ should be false if the content occurs within the range given
437
+ should be true if the content occurs more or fewer times than range
438
+ should be true if the content isn't on the page at all
439
+ with count
440
+ should be false if the content is on the page the given number of times
441
+ should be true if the content is on the page the given number of times
442
+ should be true if the content isn't on the page at all
443
+ should coerce count to an integer
444
+ with maximum
445
+ should be false when content occurs same or fewer times than given
446
+ should be true when content occurs more times than given
447
+ should be true if the content isn't on the page at all
448
+ should coerce maximum to an integer
449
+ with minimum
450
+ should be false when content occurs more times than given
451
+ should be true when content occurs fewer times than given
452
+ should be true if the content isn't on the page at all
453
+ should coerce minimum to an integer
454
+ with text
455
+ should discard all matches where the given string is not contained
456
+ should discard all matches where the given regexp is not matched
457
+ it should behave like has_selector
458
+ #has_selector?
459
+ should be true if the given selector is on the page
460
+ should be false if the given selector is not on the page
461
+ should use default selector
462
+ should respect scopes
463
+ with count
464
+ should be true if the content is on the page the given number of times
465
+ should be false if the content is on the page the given number of times
466
+ should be false if the content isn't on the page at all
467
+ with text
468
+ should discard all matches where the given string is not contained
469
+ should discard all matches where the given regexp is not matched
470
+ #has_no_selector?
471
+ should be false if the given selector is on the page
472
+ should be true if the given selector is not on the page
473
+ should use default selector
474
+ should respect scopes
475
+ with count
476
+ should be false if the content is on the page the given number of times
477
+ should be true if the content is on the page the wrong number of times
478
+ should be true if the content isn't on the page at all
479
+ with text
480
+ should discard all matches where the given string is contained
481
+ should discard all matches where the given regexp is matched
482
+ it should behave like has_xpath
483
+ #has_xpath?
484
+ should be true if the given selector is on the page
485
+ should be false if the given selector is not on the page
486
+ should use xpath even if default selector is CSS
487
+ should respect scopes
488
+ with count
489
+ should be true if the content is on the page the given number of times
490
+ should be false if the content is on the page the given number of times
491
+ should be false if the content isn't on the page at all
492
+ with text
493
+ should discard all matches where the given string is not contained
494
+ should discard all matches where the given regexp is not matched
495
+ #has_no_xpath?
496
+ should be false if the given selector is on the page
497
+ should be true if the given selector is not on the page
498
+ should use xpath even if default selector is CSS
499
+ should respect scopes
500
+ with count
501
+ should be false if the content is on the page the given number of times
502
+ should be true if the content is on the page the wrong number of times
503
+ should be true if the content isn't on the page at all
504
+ with text
505
+ should discard all matches where the given string is contained
506
+ should discard all matches where the given regexp is matched
507
+ it should behave like has_link
508
+ #has_link?
509
+ should be true if the given link is on the page
510
+ should be false if the given link is not on the page
511
+ #has_no_link?
512
+ should be false if the given link is on the page
513
+ should be true if the given link is not on the page
514
+ it should behave like has_button
515
+ #has_button?
516
+ should be true if the given button is on the page
517
+ should be false if the given button is not on the page
518
+ #has_no_button?
519
+ should be true if the given button is on the page
520
+ should be false if the given button is not on the page
521
+ it should behave like has_field
522
+ #has_field
523
+ should be true if the field is on the page
524
+ should be false if the field is not on the page
525
+ with value
526
+ should be true if a field with the given value is on the page
527
+ should be false if the given field is not on the page
528
+ should be true after the field has been filled in with the given value
529
+ should be false after the field has been filled in with a different value
530
+ #has_no_field
531
+ should be false if the field is on the page
532
+ should be true if the field is not on the page
533
+ with value
534
+ should be false if a field with the given value is on the page
535
+ should be true if the given field is not on the page
536
+ should be false after the field has been filled in with the given value
537
+ should be true after the field has been filled in with a different value
538
+ #has_checked_field?
539
+ should be true if a checked field is on the page
540
+ should be false if an unchecked field is on the page
541
+ should be false if no field is on the page
542
+ should be true after an unchecked checkbox is checked
543
+ should be false after a checked checkbox is unchecked
544
+ should be true after an unchecked radio button is chosen
545
+ should be false after another radio button in the group is chosen
546
+ #has_no_checked_field?
547
+ should be false if a checked field is on the page
548
+ should be true if an unchecked field is on the page
549
+ should be true if no field is on the page
550
+ #has_unchecked_field?
551
+ should be false if a checked field is on the page
552
+ should be true if an unchecked field is on the page
553
+ should be false if no field is on the page
554
+ should be false after an unchecked checkbox is checked
555
+ should be true after a checked checkbox is unchecked
556
+ should be false after an unchecked radio button is chosen
557
+ should be true after another radio button in the group is chosen
558
+ #has_no_unchecked_field?
559
+ should be true if a checked field is on the page
560
+ should be false if an unchecked field is on the page
561
+ should be true if no field is on the page
562
+ it should behave like has_select
563
+ #has_select?
564
+ should be true if the field is on the page
565
+ should be false if the field is not on the page
566
+ with selected value
567
+ should be true if a field with the given value is on the page
568
+ should be false if the given field is not on the page
569
+ should be true after the given value is selected
570
+ should be false after a different value is selected
571
+ should be true after the given values are selected
572
+ should be false after one of the values is unselected
573
+ with options
574
+ should be true if a field with the given options is on the page
575
+ should be false if the given field is not on the page
576
+ #has_no_select?
577
+ should be false if the field is on the page
578
+ should be true if the field is not on the page
579
+ with selected value
580
+ should be false if a field with the given value is on the page
581
+ should be true if the given field is not on the page
582
+ should be false after the given value is selected
583
+ should be true after a different value is selected
584
+ should be false after the given values are selected
585
+ should be true after one of the values is unselected
586
+ with options
587
+ should be false if a field with the given options is on the page
588
+ should be true if the given field is not on the page
589
+ it should behave like has_table
590
+ #has_table?
591
+ should be true if the field is on the page
592
+ should be false if the field is not on the page
593
+ with rows
594
+ should be true if a table with the given rows is on the page
595
+ should be true if the given rows are incomplete
596
+ should be false if the given table is not on the page
597
+ should be false if the given rows contain incorrect elements
598
+ should be false if the given rows are incorrectly ordered
599
+ should be false if the only some of the given rows are correct
600
+ should be false if the given rows are out of order
601
+ #has_no_table?
602
+ should be false if the field is on the page
603
+ should be true if the field is not on the page
604
+ with rows
605
+ should be false if a table with the given rows is on the page
606
+ should be false if the given rows are incomplete
607
+ should be true if the given table is not on the page
608
+ should be true if the given rows contain incorrect elements
609
+ should be true if the given rows are incorrectly ordered
610
+ should be true if the only some of the given rows are correct
611
+ should be true if the given rows are out of order
612
+ it should behave like select
613
+ #select
614
+ should return value of the first option
615
+ should return value of the selected option
616
+ should return the value attribute rather than content if present
617
+ should select an option from a select box by id
618
+ should select an option from a select box by label
619
+ should select an option without giving a select box
620
+ should favour exact matches to option labels
621
+ should escape quotes
622
+ should obey from
623
+ show match labels with preceding or trailing whitespace
624
+ with a locator that doesn't exist
625
+ should raise an error
626
+ with an option that doesn't exist
627
+ should raise an error
628
+ with multiple select
629
+ should return an empty value
630
+ should return value of the selected options
631
+ should select one option
632
+ should select multiple options
633
+ should remain selected if already selected
634
+ should return value attribute rather than content if present
635
+ it should behave like text
636
+ #text
637
+ should print the text of the page
638
+ with css as default selector
639
+ should print the text of the page
640
+ it should behave like uncheck
641
+ #uncheck
642
+ should uncheck a checkbox by id
643
+ should uncheck a checkbox by label
644
+ it should behave like unselect
645
+ #unselect
646
+ with multiple select
647
+ should unselect an option from a select box by id
648
+ should unselect an option without a select box
649
+ should unselect an option from a select box by label
650
+ should favour exact matches to option labels
651
+ should escape quotes
652
+ with single select
653
+ should raise an error
654
+ with a locator that doesn't exist
655
+ should raise an error
656
+ with an option that doesn't exist
657
+ should raise an error
658
+ it should behave like within
659
+ #within
660
+ with CSS selector
661
+ should click links in the given scope
662
+ should accept additional options
663
+ with XPath selector
664
+ should click links in the given scope
665
+ with the default selector
666
+ should use XPath
667
+ with the default selector set to CSS
668
+ should use CSS
669
+ with click_link
670
+ should click links in the given scope
671
+ should raise an error if the scope is not found on the page
672
+ should restore the scope when an error is raised
673
+ with nested scopes
674
+ should respect the inner scope
675
+ should respect the outer scope
676
+ with forms
677
+ should fill in a field and click a button
678
+ #within_fieldset
679
+ should restrict scope to a fieldset given by id
680
+ should restrict scope to a fieldset given by legend
681
+ #within_table
682
+ should restrict scope to a fieldset given by id
683
+ should restrict scope to a fieldset given by legend
684
+ it should behave like current_url
685
+ #current_url
686
+ should return the current url
687
+ #current_path
688
+ should show the correct location
689
+ it should behave like current_host
690
+ #current_host
691
+ is affected by visiting a page directly
692
+ returns to the app host when visiting a relative url
693
+ is affected by setting Capybara.app_host
694
+ is unaffected by following a relative link
695
+ is affected by following an absolute link
696
+ is unaffected by posting through a relative form
697
+ is affected by posting through an absolute form
698
+ it should behave like session with headers support
699
+ #response_headers
700
+ should return response headers
701
+ it should behave like session with status code support
702
+ #status_code
703
+ should return response codes
704
+ it should behave like session with javascript support
705
+ all JS specs
706
+ Node#drag_to
707
+ should drag and drop an object
708
+ #find
709
+ should allow triggering of custom JS events
710
+ #body
711
+ should return the current state of the page
712
+ #source
713
+ should return the original, unmodified source of the page
714
+ #evaluate_script
715
+ should evaluate the given script and return whatever it produces
716
+ #execute_script
717
+ should execute the given script and return nothing
718
+ #find
719
+ should wait for asynchronous load
720
+ #wait_until
721
+ should wait for block to return true
722
+ should raise Capybara::TimeoutError if block doesn't return true within timeout
723
+ should accept custom timeout in seconds
724
+ should default to Capybara.default_wait_time before timeout
725
+ #click_link_or_button
726
+ should wait for asynchronous load
727
+ #click_link
728
+ should wait for asynchronous load
729
+ #click_button
730
+ should wait for asynchronous load
731
+ #fill_in
732
+ should wait for asynchronous load
733
+ #check
734
+ should trigger associated events
735
+ #has_xpath?
736
+ should wait for content to appear
737
+ #has_no_xpath?
738
+ should wait for content to disappear
739
+ #has_css?
740
+ should wait for content to appear
741
+ #has_no_xpath?
742
+ should wait for content to disappear
743
+ #has_content?
744
+ should wait for content to appear
745
+ #has_no_content?
746
+ should wait for content to disappear
747
+
748
+ 498 examples, 8 failures