mechwarrior 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +52 -0
- data/lib/capybara/mechanize/driver.rb +118 -0
- data/lib/capybara/mechanize/form.rb +43 -0
- data/lib/capybara/mechanize/node.rb +100 -0
- data/lib/capybara/mechanize.rb +13 -0
- data/lib/mechwarrior/cucumber.rb +5 -0
- data/lib/mechwarrior/version.rb +3 -0
- data/lib/mechwarrior.rb +5 -0
- data/spec/mechanize_driver_spec.rb +20 -0
- data/spec/mechanize_session_spec.rb +34 -0
- data/spec/spec_helper.rb +26 -0
- metadata +155 -0
data/README.md
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
Mechwarrior
|
2
|
+
===========
|
3
|
+
|
4
|
+
A Mechanize based Capybara driver, designed to get round the rack-test limitation of not being able to visit external (i.e. not the app your testing) websites.
|
5
|
+
|
6
|
+
Installation
|
7
|
+
------------
|
8
|
+
|
9
|
+
1. `gem install 'mechwarrior'`
|
10
|
+
|
11
|
+
2. `require 'mechwarrior/cucumber'` in cucumbers env.rb
|
12
|
+
|
13
|
+
3. Tag your steps with either @mechanize or @external
|
14
|
+
|
15
|
+
Dependencies
|
16
|
+
------------
|
17
|
+
capybara ">= 1.0.0"
|
18
|
+
mechanize "~> 2.0.0"
|
19
|
+
|
20
|
+
|
21
|
+
Licence
|
22
|
+
---------
|
23
|
+
|
24
|
+
Copyright (c) 2011, Chris Lowder, http://github.com/clowder
|
25
|
+
|
26
|
+
All rights reserved.
|
27
|
+
|
28
|
+
Redistribution and use in source and binary forms, with or without
|
29
|
+
modification, are permitted provided that the following conditions are met:
|
30
|
+
|
31
|
+
* Redistributions of source code must retain the above copyright notice, this
|
32
|
+
list of conditions and the following disclaimer.
|
33
|
+
|
34
|
+
* Redistributions in binary form must reproduce the above copyright notice,
|
35
|
+
this list of conditions and the following disclaimer in the documentation
|
36
|
+
and/or other materials provided with the distribution.
|
37
|
+
|
38
|
+
* Neither the name of http://github.com/clowder nor the names of its contributors may
|
39
|
+
be used to endorse or promote products derived from this software without
|
40
|
+
specific prior written permission.
|
41
|
+
|
42
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
43
|
+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
44
|
+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
45
|
+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
46
|
+
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
47
|
+
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
48
|
+
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
49
|
+
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
50
|
+
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
51
|
+
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
52
|
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
@@ -0,0 +1,118 @@
|
|
1
|
+
require 'mechanize'
|
2
|
+
|
3
|
+
class Capybara::Mechanize::Driver < Capybara::Driver::Base
|
4
|
+
attr_reader :app, :rack_server, :options
|
5
|
+
|
6
|
+
def initialize(app, options={})
|
7
|
+
raise ArgumentError, "Mechanize requires a rack application, but none was given" unless app
|
8
|
+
|
9
|
+
@app = app
|
10
|
+
@options = options
|
11
|
+
@rack_server = Capybara::Server.new(@app)
|
12
|
+
@rack_server.boot if Capybara.run_server
|
13
|
+
end
|
14
|
+
|
15
|
+
def browser
|
16
|
+
unless @browser
|
17
|
+
@browser = Mechanize.new
|
18
|
+
@browser.follow_meta_refresh
|
19
|
+
end
|
20
|
+
@browser
|
21
|
+
end
|
22
|
+
|
23
|
+
def visit(path)
|
24
|
+
browser.get(url(path))
|
25
|
+
end
|
26
|
+
|
27
|
+
def follow(_method, path, attributes={})
|
28
|
+
return if is_javascript_hashy_path?(path)
|
29
|
+
|
30
|
+
absolute_url = make_absolute_url(path)
|
31
|
+
|
32
|
+
if _method == :get
|
33
|
+
browser.get(absolute_url, [], self.current_url)
|
34
|
+
else
|
35
|
+
browser.send(_method, absolute_url, attributes)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def submit(form_node, button_node)
|
40
|
+
form = Capybara::Mechanize::Form.new(form_node, browser)
|
41
|
+
button = Mechanize::Form::Button.new(button_node)
|
42
|
+
|
43
|
+
form.action = form.action || self.current_url
|
44
|
+
|
45
|
+
browser.submit(form, button)
|
46
|
+
end
|
47
|
+
|
48
|
+
def current_url
|
49
|
+
current_page? ? current_page.uri.to_s : ''
|
50
|
+
end
|
51
|
+
|
52
|
+
def response_headers
|
53
|
+
current_page? ? current_page.header : {}
|
54
|
+
end
|
55
|
+
|
56
|
+
def status_code
|
57
|
+
current_page? ? current_page.code.to_i : nil
|
58
|
+
end
|
59
|
+
|
60
|
+
def find(selector)
|
61
|
+
dom.search(selector).map { |node| Capybara::Mechanize::Node.new(self, node) }
|
62
|
+
end
|
63
|
+
|
64
|
+
def source
|
65
|
+
current_page? ? current_page.body : ''
|
66
|
+
end
|
67
|
+
alias :body :source
|
68
|
+
|
69
|
+
def dom
|
70
|
+
current_page? ? current_page.root : Nokogiri::HTML(nil)
|
71
|
+
end
|
72
|
+
|
73
|
+
def reset!
|
74
|
+
@browser = nil
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
def url(path)
|
80
|
+
rack_server.url(path)
|
81
|
+
end
|
82
|
+
|
83
|
+
def current_page
|
84
|
+
browser.current_page
|
85
|
+
end
|
86
|
+
|
87
|
+
def current_page?
|
88
|
+
!browser.current_page.nil?
|
89
|
+
end
|
90
|
+
|
91
|
+
def current_page_is_external?
|
92
|
+
current_page.uri.host != (Capybara.app_host || rack_server.host)
|
93
|
+
end
|
94
|
+
|
95
|
+
def request_path
|
96
|
+
browser.current_page.uri.path
|
97
|
+
end
|
98
|
+
|
99
|
+
def make_absolute_url(path)
|
100
|
+
return path unless URI.parse(path).relative?
|
101
|
+
|
102
|
+
path = "#{ request_path }#{ path }" if is_query_string?(path)
|
103
|
+
|
104
|
+
if current_page? && current_page_is_external?
|
105
|
+
current_page.uri.merge(path).to_s
|
106
|
+
else
|
107
|
+
url(path)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def is_query_string?(path)
|
112
|
+
path.start_with?('?')
|
113
|
+
end
|
114
|
+
|
115
|
+
def is_javascript_hashy_path?(path)
|
116
|
+
path.gsub(/^#{request_path}/, '').start_with?('#')
|
117
|
+
end
|
118
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'mechanize'
|
2
|
+
|
3
|
+
class Capybara::Mechanize::Form < Mechanize::Form
|
4
|
+
|
5
|
+
def initialize(node, mech=nil, page=nil)
|
6
|
+
super(strip_disabled_nodes(node), mech, page)
|
7
|
+
normalize_uploads
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def strip_disabled_nodes(form_node)
|
13
|
+
stripped_form_node = form_node.clone
|
14
|
+
stripped_form_node.search('*[disabled=disabled]').remove
|
15
|
+
stripped_form_node
|
16
|
+
end
|
17
|
+
|
18
|
+
def normalize_uploads
|
19
|
+
if self.enctype.downcase =~ /^multipart\/form-data/
|
20
|
+
assign_files_to_uploads
|
21
|
+
else
|
22
|
+
create_dummy_fields
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def assign_files_to_uploads
|
27
|
+
self.file_uploads.each do |upload|
|
28
|
+
file_path = upload.node["value"]
|
29
|
+
upload.file_name = file_path if !file_path.nil? && file_path != ''
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def create_dummy_fields
|
34
|
+
self.file_uploads.each do |upload|
|
35
|
+
file_path = upload.node["value"]
|
36
|
+
|
37
|
+
if !file_path.nil? && file_path != ''
|
38
|
+
new_field = Mechanize::Form::Field.new(upload.node, File.basename(file_path))
|
39
|
+
self.fields << new_field
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
class Capybara::Mechanize::Node < Capybara::Driver::Node
|
2
|
+
def text
|
3
|
+
native.text
|
4
|
+
end
|
5
|
+
|
6
|
+
def [](name)
|
7
|
+
string_node[name]
|
8
|
+
end
|
9
|
+
|
10
|
+
def value
|
11
|
+
string_node.value
|
12
|
+
end
|
13
|
+
|
14
|
+
def set(value)
|
15
|
+
if tag_name == 'input' and type == 'radio'
|
16
|
+
other_radios_xpath = XPath.generate { |x| x.anywhere(:input)[x.attr(:name).equals(self[:name])] }.to_s
|
17
|
+
driver.dom.xpath(other_radios_xpath).each { |node| node.remove_attribute("checked") }
|
18
|
+
native['checked'] = 'checked'
|
19
|
+
elsif tag_name == 'input' and type == 'checkbox'
|
20
|
+
if value && !native['checked']
|
21
|
+
native['checked'] = 'checked'
|
22
|
+
elsif !value && native['checked']
|
23
|
+
native.remove_attribute('checked')
|
24
|
+
end
|
25
|
+
elsif tag_name == 'input'
|
26
|
+
if (type == 'text' || type == 'password') && self[:maxlength]
|
27
|
+
value = value[0...self[:maxlength].to_i]
|
28
|
+
end
|
29
|
+
native['value'] = value.to_s
|
30
|
+
elsif tag_name == "textarea"
|
31
|
+
native.content = value.to_s
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def select_option
|
36
|
+
if select_node['multiple'] != 'multiple'
|
37
|
+
select_node.find(".//option[@selected]").each { |node| node.native.remove_attribute("selected") }
|
38
|
+
end
|
39
|
+
native["selected"] = 'selected'
|
40
|
+
end
|
41
|
+
|
42
|
+
def unselect_option
|
43
|
+
if select_node['multiple'] != 'multiple'
|
44
|
+
raise Capybara::UnselectNotAllowed, "Cannot unselect option from single select box."
|
45
|
+
end
|
46
|
+
native.remove_attribute('selected')
|
47
|
+
end
|
48
|
+
|
49
|
+
def click
|
50
|
+
if tag_name == 'a'
|
51
|
+
method = self["data-method"] || :get
|
52
|
+
driver.follow(method, self[:href].to_s)
|
53
|
+
elsif (tag_name == 'input' && %w(submit image).include?(type)) || ((tag_name == 'button') && type.nil? || type == "submit")
|
54
|
+
driver.submit(form, self)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def tag_name
|
59
|
+
native.node_name
|
60
|
+
end
|
61
|
+
|
62
|
+
def visible?
|
63
|
+
string_node.visible?
|
64
|
+
end
|
65
|
+
|
66
|
+
def checked?
|
67
|
+
string_node.checked?
|
68
|
+
end
|
69
|
+
|
70
|
+
def selected?
|
71
|
+
string_node.selected?
|
72
|
+
end
|
73
|
+
|
74
|
+
def path
|
75
|
+
native.path
|
76
|
+
end
|
77
|
+
|
78
|
+
def find(locator)
|
79
|
+
native.xpath(locator).map { |n| self.class.new(driver, n) }
|
80
|
+
end
|
81
|
+
|
82
|
+
private
|
83
|
+
|
84
|
+
def string_node
|
85
|
+
@string_node ||= Capybara::Node::Simple.new(native)
|
86
|
+
end
|
87
|
+
|
88
|
+
# a reference to the select node if this is an option node
|
89
|
+
def select_node
|
90
|
+
find('./ancestor::select').first
|
91
|
+
end
|
92
|
+
|
93
|
+
def type
|
94
|
+
native[:type]
|
95
|
+
end
|
96
|
+
|
97
|
+
def form
|
98
|
+
native.ancestors('form').first
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'capybara'
|
2
|
+
|
3
|
+
module Capybara
|
4
|
+
module Mechanize
|
5
|
+
autoload :Driver, 'capybara/mechanize/driver'
|
6
|
+
autoload :Node, 'capybara/mechanize/node'
|
7
|
+
autoload :Form, 'capybara/mechanize/form'
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
Capybara.register_driver :mechanize do |app|
|
12
|
+
Capybara::Mechanize::Driver.new(app)
|
13
|
+
end
|
data/lib/mechwarrior.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe Capybara::Mechanize::Driver do
|
5
|
+
before do
|
6
|
+
@driver = TestSessions::Mechanize.driver
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should throw an error when no rack app is given" do
|
10
|
+
running do
|
11
|
+
Capybara::Mechanize::Driver.new(nil)
|
12
|
+
end.should raise_error(ArgumentError)
|
13
|
+
end
|
14
|
+
|
15
|
+
it_should_behave_like "driver"
|
16
|
+
it_should_behave_like "driver with header support"
|
17
|
+
it_should_behave_like "driver with status code support"
|
18
|
+
it_should_behave_like "driver with cookies support"
|
19
|
+
|
20
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Capybara::Session do
|
4
|
+
context 'with Mechanize driver' do
|
5
|
+
before do
|
6
|
+
@session = TestSessions::Mechanize
|
7
|
+
end
|
8
|
+
|
9
|
+
describe '#driver' do
|
10
|
+
it "should be a Mechanize driver" do
|
11
|
+
@session.driver.should be_an_instance_of(Capybara::Mechanize::Driver)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe '#mode' do
|
16
|
+
it "should remember the mode" do
|
17
|
+
@session.mode.should == :mechanize
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe '#click_link' do
|
22
|
+
it "should use data-method if available" do
|
23
|
+
@session.visit "/with_html"
|
24
|
+
@session.click_link "A link with data-method"
|
25
|
+
@session.body.should include('The requested object was deleted')
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
it_should_behave_like "session"
|
30
|
+
it_should_behave_like "session without javascript support"
|
31
|
+
it_should_behave_like "session with headers support"
|
32
|
+
it_should_behave_like "session with status code support"
|
33
|
+
end
|
34
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
$:.unshift(File.expand_path('../lib', File.dirname(__FILE__)))
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require "bundler/setup"
|
5
|
+
|
6
|
+
require 'rspec'
|
7
|
+
require 'mechwarrior'
|
8
|
+
|
9
|
+
RSpec.configure do |config|
|
10
|
+
config.before do
|
11
|
+
Capybara.configure do |config|
|
12
|
+
config.default_selector = :xpath
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
require 'capybara/spec/driver'
|
18
|
+
require 'capybara/spec/session'
|
19
|
+
|
20
|
+
alias :running :lambda
|
21
|
+
|
22
|
+
Capybara.default_wait_time = 0 # less timeout so tests run faster
|
23
|
+
|
24
|
+
module TestSessions
|
25
|
+
Mechanize = Capybara::Session.new(:mechanize, TestApp)
|
26
|
+
end
|
metadata
ADDED
@@ -0,0 +1,155 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: mechwarrior
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.0.1
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Chris Lowder
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2011-07-25 00:00:00 +01:00
|
14
|
+
default_executable:
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: capybara
|
18
|
+
prerelease: false
|
19
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
20
|
+
none: false
|
21
|
+
requirements:
|
22
|
+
- - ">="
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: 1.0.0
|
25
|
+
type: :runtime
|
26
|
+
version_requirements: *id001
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: mechanize
|
29
|
+
prerelease: false
|
30
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
31
|
+
none: false
|
32
|
+
requirements:
|
33
|
+
- - ~>
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: 2.0.0
|
36
|
+
type: :runtime
|
37
|
+
version_requirements: *id002
|
38
|
+
- !ruby/object:Gem::Dependency
|
39
|
+
name: sinatra
|
40
|
+
prerelease: false
|
41
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: 0.9.4
|
47
|
+
type: :development
|
48
|
+
version_requirements: *id003
|
49
|
+
- !ruby/object:Gem::Dependency
|
50
|
+
name: rspec
|
51
|
+
prerelease: false
|
52
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: 2.0.0
|
58
|
+
type: :development
|
59
|
+
version_requirements: *id004
|
60
|
+
- !ruby/object:Gem::Dependency
|
61
|
+
name: launchy
|
62
|
+
prerelease: false
|
63
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
64
|
+
none: false
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 0.3.5
|
69
|
+
type: :development
|
70
|
+
version_requirements: *id005
|
71
|
+
- !ruby/object:Gem::Dependency
|
72
|
+
name: yard
|
73
|
+
prerelease: false
|
74
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
75
|
+
none: false
|
76
|
+
requirements:
|
77
|
+
- - ">="
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: 0.5.8
|
80
|
+
type: :development
|
81
|
+
version_requirements: *id006
|
82
|
+
- !ruby/object:Gem::Dependency
|
83
|
+
name: fuubar
|
84
|
+
prerelease: false
|
85
|
+
requirement: &id007 !ruby/object:Gem::Requirement
|
86
|
+
none: false
|
87
|
+
requirements:
|
88
|
+
- - ">="
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: 0.0.1
|
91
|
+
type: :development
|
92
|
+
version_requirements: *id007
|
93
|
+
- !ruby/object:Gem::Dependency
|
94
|
+
name: cucumber
|
95
|
+
prerelease: false
|
96
|
+
requirement: &id008 !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ">="
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: "0.10"
|
102
|
+
type: :development
|
103
|
+
version_requirements: *id008
|
104
|
+
description: A Mechanize based Capybara driver.
|
105
|
+
email:
|
106
|
+
- clowder@gmail.com
|
107
|
+
executables: []
|
108
|
+
|
109
|
+
extensions: []
|
110
|
+
|
111
|
+
extra_rdoc_files:
|
112
|
+
- README.md
|
113
|
+
files:
|
114
|
+
- lib/capybara/mechanize/driver.rb
|
115
|
+
- lib/capybara/mechanize/form.rb
|
116
|
+
- lib/capybara/mechanize/node.rb
|
117
|
+
- lib/capybara/mechanize.rb
|
118
|
+
- lib/mechwarrior/cucumber.rb
|
119
|
+
- lib/mechwarrior/version.rb
|
120
|
+
- lib/mechwarrior.rb
|
121
|
+
- spec/mechanize_driver_spec.rb
|
122
|
+
- spec/mechanize_session_spec.rb
|
123
|
+
- spec/spec_helper.rb
|
124
|
+
- README.md
|
125
|
+
has_rdoc: true
|
126
|
+
homepage: http://github.com/clowder/mechwarrior
|
127
|
+
licenses: []
|
128
|
+
|
129
|
+
post_install_message:
|
130
|
+
rdoc_options:
|
131
|
+
- --main
|
132
|
+
- README.md
|
133
|
+
require_paths:
|
134
|
+
- lib
|
135
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
136
|
+
none: false
|
137
|
+
requirements:
|
138
|
+
- - ">="
|
139
|
+
- !ruby/object:Gem::Version
|
140
|
+
version: "0"
|
141
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
142
|
+
none: false
|
143
|
+
requirements:
|
144
|
+
- - ">="
|
145
|
+
- !ruby/object:Gem::Version
|
146
|
+
version: "0"
|
147
|
+
requirements: []
|
148
|
+
|
149
|
+
rubyforge_project:
|
150
|
+
rubygems_version: 1.6.2
|
151
|
+
signing_key:
|
152
|
+
specification_version: 3
|
153
|
+
summary: A Mechanize based Capybara driver, designed to get round the rack-test limitation of not being able to visit external (i.e. not the app your testing) websites.
|
154
|
+
test_files: []
|
155
|
+
|