wvanbergen-rspec_form_matcher 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ /coverage
2
+ /tmp
3
+ /doc
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Willem van Bergen
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,72 @@
1
+ = RSpec FormMatcher
2
+
3
+ An RSpec matcher that checks views for the presence of a form, including
4
+ the presence of specified input fields that should be within the form tag.
5
+ This can be especially useful to test forms that submit to an external
6
+ website and thus cannot be included in a Cucumber story.
7
+
8
+ == Setup
9
+
10
+ Install the gem:
11
+
12
+ gem install wvanbergen-rspec_form_matcher -s http://gems.github.com
13
+
14
+ And include it in your <tt>spec_helper.rb</tt>:
15
+
16
+ require 'rspec_form_matcher'
17
+ Spec::Runner.configure do |config|
18
+ config.include Spec::Matchers::FormMatcher, :type => :views
19
+ end
20
+
21
+ The <b>libxml-ruby</b> gem is required to perform the XPath Query that is used
22
+ for checking the form.
23
+
24
+ == Example
25
+
26
+ With following HTML snippet:
27
+
28
+ <form action="http://example.com/submit" method="post">
29
+ <input type="hidden" name="foo" value="bar" />
30
+ <input type="submit" />
31
+ </form>
32
+ <input type="hidden" name="outside" value="form" />
33
+
34
+ Consider the following specs:
35
+
36
+ response.should have_form(:post => 'http://example.com/submit') # succeeds
37
+ response.should have_form(:put => 'http://example.com/submit') # fails
38
+ response.should have_form(:post => 'http://other.com/submit') # fails
39
+
40
+ response.should have_form(:post => 'http://example.com/submit').with(
41
+ :hidden, 'foo', 'bar').and_with(:submit_button) # succeeds
42
+
43
+ response.should have_form(:post => 'http://example.com/submit').with(
44
+ :hidden, 'outside', 'form').and_with(:submit_button) # fails
45
+
46
+ An alternative syntax using a block is available, which is more suitable
47
+ to check complex forms. Note the use of curly braces instead of do ... end,
48
+ to make sure that the block binds to the <tt>have_form</tt> call.
49
+
50
+ response.should have_form(:post => 'http://example.com/submit') { |form|
51
+ form.hidden 'foo', 'bar'
52
+ form.submit_button
53
+ }
54
+
55
+ See the <tt>spec/form_matcher_spec.rb</tt> file for more examples.
56
+
57
+ == Supported checks
58
+
59
+ have_form(method => action) {
60
+ form.hidden('name') # hidden field with name 'name'
61
+ form.hidden('name', 'value') # field with value
62
+
63
+ form.text('username') # named text input
64
+ form.text('username', 'default') # checks default value
65
+ form.password('password') # named password field
66
+
67
+ form.checkbox('name', 'value') # checkbox with value
68
+ form.checkbox('name[]', 'value1', 'value2') # array of checkboxes
69
+ form.radio('name', 'value1', 'value2', ...) # radiobuttons
70
+
71
+ form.submit_button # makes sure the form can be submitted
72
+ }
data/Rakefile ADDED
@@ -0,0 +1,24 @@
1
+ require 'spec/rake/spectask'
2
+
3
+ desc "Run all RSpec examples and report the result"
4
+ Spec::Rake::SpecTask.new(:spec) do |t|
5
+ t.spec_files = Dir['spec/**/*_spec.rb']
6
+ t.spec_opts << '--format specdoc'
7
+ t.rcov = true
8
+ end
9
+
10
+ def gemspec_file
11
+ Dir['*.gemspec'].first
12
+ end
13
+
14
+ namespace(:gem) do
15
+ task(:manifest) do
16
+ # update the spec file
17
+ spec = File.read(gemspec_file)
18
+ spec.gsub!(/^(\s+\w+\.files\s*=\s*)[^\s].*$/) do
19
+ $1 + `git ls-files`.split("\n").inspect
20
+ end
21
+
22
+ File.open(gemspec_file, 'w') { |f| f << spec }
23
+ end
24
+ end
@@ -0,0 +1,159 @@
1
+ module Spec
2
+ module Matchers
3
+ module FormMatcher
4
+ class HaveForm
5
+ attr_reader :action, :method, :field, :submit_button
6
+
7
+ def initialize(action = nil)
8
+ case action
9
+ when Hash then action.each { |m, a| @method, @action = m, a }
10
+ when String, Regexp then @action = action
11
+ end
12
+
13
+ @tags = []
14
+ @checks = []
15
+ end
16
+
17
+ def with(method, *args)
18
+ self.send(method, *args)
19
+ end
20
+
21
+ alias :and_with :with
22
+
23
+ def input(type, field_name, value = nil)
24
+ attributes = { :type => type, :name => field_name }
25
+ attributes[:value] = value if value
26
+ tag('input', attributes)
27
+ end
28
+
29
+ def tag(tag, attributes = {})
30
+ @checks << tag_xpath(tag, attributes)
31
+ return self
32
+ end
33
+
34
+ def hidden(field_name, value = nil)
35
+ input(:hidden, field_name, value)
36
+ end
37
+
38
+ def submit_button
39
+ button_xpath = tag_xpath('button', :type => 'submit')
40
+ input_xpath = tag_xpath('input', :type => 'submit')
41
+ image_xpath = tag_xpath('input', :type => 'image')
42
+ @checks << "#{input_xpath} or #{button_xpath} or #{image_xpath}"
43
+ return self
44
+ end
45
+
46
+ def text(field_name, value = nil)
47
+ input(:text, field_name, value)
48
+ end
49
+
50
+ def radio(field_name, *values)
51
+ if values.empty?
52
+ input(:radio, field_name)
53
+ else
54
+ values.each { |v| input(:radio, field_name, v) }
55
+ end
56
+ return self
57
+ end
58
+
59
+ def password(field_name, value = nil)
60
+ input(:password, field_name, value)
61
+ end
62
+
63
+ def checkbox(field_name, *values)
64
+ if values.empty?
65
+ input(:checkbox, field_name)
66
+ else
67
+ values.each { |v| input(:checkbox, field_name, v) }
68
+ end
69
+ return self
70
+ end
71
+
72
+ def matches?(stringlike)
73
+ @document = document(stringlike)
74
+ @xpath = build_xpath_query
75
+ check_xpath!
76
+ end
77
+
78
+ def failure_message
79
+ "Specified form (XPath: << #{@xpath} >>) not found in document: \n#{@document.to_s}"
80
+ end
81
+
82
+ def negative_failure_message
83
+ "Unexpectedly found specified form (XPath: << #{@xpath} >>) in document: \n#{@document.to_s}"
84
+ end
85
+
86
+ protected
87
+
88
+ def tag_xpath(tag, attributes = {})
89
+ field_xpath = "descendant::#{tag}"
90
+ attributes.each { |k, v| field_xpath << "[@#{k}='#{v}']" }
91
+ return field_xpath
92
+ end
93
+
94
+ def build_xpath_query
95
+ form_xpath = "//form"
96
+ form_xpath << "[@method='#{method.to_s.downcase}']" if @method # fn:lower-case(@method)
97
+ form_xpath << "[@action='#{@action}']" if @action
98
+ form_xpath << "[#{@checks.join('][')}]" unless @checks.empty?
99
+
100
+ # puts form_xpath
101
+ return form_xpath
102
+ end
103
+ end
104
+
105
+ def have_form(options = {})
106
+ form_matcher = HaveForm.new(options)
107
+ yield(form_matcher) if block_given?
108
+ return form_matcher
109
+ end
110
+
111
+ module REXML
112
+ def check_xpath!
113
+ !@document.elements[@xpath].nil?
114
+ end
115
+
116
+ def document(subject)
117
+ if String === subject
118
+ ::REXML::Document.new(subject).root
119
+ elsif subject.respond_to?(:body)
120
+ ::REXML::Document.new(subject.body).root
121
+ elsif ::REXML::Element === subject
122
+ subject
123
+ else
124
+ raise "Cannot handle this XML input type"
125
+ end
126
+ end
127
+ end
128
+
129
+ module LibXML
130
+ def check_xpath!
131
+ !@document.find_first(@xpath).nil?
132
+ end
133
+
134
+ def document(subject)
135
+ if String === subject
136
+ XML::HTMLParser.string(subject).parse
137
+ elsif subject.respond_to?(:body)
138
+ XML::HTMLParser.string(subject.body).parse
139
+ elsif XML::Node === subject
140
+ subject
141
+ elsif XML::Document === subject
142
+ subject
143
+ else
144
+ raise "Cannot handle this XML input type"
145
+ end
146
+ end
147
+ end
148
+
149
+ begin
150
+ require 'xml'
151
+ HaveForm.send(:include, LibXML)
152
+ rescue LoadError => e
153
+ require 'rexml/document'
154
+ HaveForm.send(:include, REXML)
155
+ end
156
+
157
+ end
158
+ end
159
+ end
@@ -0,0 +1,23 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'rspec_form_matcher'
3
+ s.version = '0.1.0'
4
+ s.date = '2009-08-28'
5
+
6
+ s.summary = "RSpec matcher to check forms including their fields."
7
+ s.description = <<-eos
8
+ The RSpec form matcher will check a string to see whether a specified form exists with the correct action and method.
9
+ Moreover, it will check whether the specified fields actually occur within this form tag.
10
+ eos
11
+
12
+ s.author = 'Willem van Bergen'
13
+ s.email = 'willem@vanbergen.org'
14
+ s.homepage = 'http://github.com/wvanbergen/rspec_form_matcher'
15
+
16
+ s.add_dependency('rspec', ['>= 1.2.4'])
17
+
18
+ s.rdoc_options << '--title' << s.name << '--main' << 'README.rdoc' << '--line-numbers' << '--inline-source'
19
+ s.extra_rdoc_files = ['README.rdoc']
20
+
21
+ s.files = [".gitignore", "LICENSE", "README.rdoc", "Rakefile", "lib/rspec_form_matcher.rb", "rspec_form_matcher.gemspec", "spec/form_matcher_spec.rb", "spec/spec_helper.rb"]
22
+ s.test_files = s.files.select { |file| file =~ /^spec\/.*_spec\.rb$/ }
23
+ end
@@ -0,0 +1,108 @@
1
+ require "#{File.dirname(__FILE__)}/spec_helper.rb"
2
+
3
+ describe Spec::Matchers::FormMatcher do
4
+
5
+ before(:all) do
6
+ @correct_form = <<-eos
7
+ <html>
8
+ <form action="/endpoint" method="post">
9
+ <input type="hidden" name="foo" value="bar" />
10
+
11
+ <input type="radio" name="choice" value="1" />
12
+ <input type="radio" name="choice" value="2" />
13
+
14
+ <input type="hidden" name="select" value="0" />
15
+ <input type="checkbox" name="select" value="1" />
16
+
17
+ <input type="text" name="username" />
18
+ <input type="password" name="password" />
19
+
20
+ <button type="submit"> Submit! </button>
21
+ </form>
22
+ </html>
23
+ eos
24
+
25
+ @wrong_form = <<-eos
26
+ <html>
27
+ <form action="/endpoint" method="post"></form>
28
+
29
+ <input type="hidden" name="foo" value="bar" />
30
+
31
+ <input type="radio" name="choice" value="1" />
32
+ <input type="radio" name="choice" value="2" />
33
+
34
+ <input type="hidden" name="select" value="0" />
35
+ <input type="checkbox" name="select" value="1" />
36
+
37
+ <input type="text" name="username" />
38
+ <input type="password" name="password" />
39
+
40
+ <button type="submit"> Submit! </button>
41
+ </html>
42
+ eos
43
+
44
+ end
45
+
46
+ it "should assert the presence of the form correctly" do
47
+ @correct_form.should have_form(:post => '/endpoint')
48
+ end
49
+
50
+ it "should not assert the presence of the form with a wrong HTTP method" do
51
+ @correct_form.should_not have_form(:put => '/endpoint')
52
+ end
53
+
54
+ it "should not assert the presence of the form with a wrong action" do
55
+ @correct_form.should_not have_form(:post => '/different_endpoint')
56
+ end
57
+
58
+ it "should assert the submit button" do
59
+ @correct_form.should have_form(:post => '/endpoint').with(:submit_button)
60
+ end
61
+
62
+ it "should not assert the submit button if it is outside the form tag" do
63
+ @wrong_form.should_not have_form(:post => '/endpoint').with(:submit_button)
64
+ end
65
+
66
+ it "should assert the hidden field 'foo' without value" do
67
+ @correct_form.should have_form(:post => '/endpoint').with(:hidden, 'foo')
68
+ end
69
+
70
+ it "should assert the hidden field 'foo' when it is outside the form tag" do
71
+ @wrong_form.should_not have_form(:post => '/endpoint').with(:hidden, 'foo')
72
+ end
73
+
74
+ it "should assert the hidden field 'foo' with value 'bar'" do
75
+ @correct_form.should have_form(:post => '/endpoint').with(:hidden, 'foo', 'bar')
76
+ end
77
+
78
+ it "should assert the presence of different radio buttons" do
79
+ @correct_form.should have_form(:post => '/endpoint').with(:radio, 'choice', '1', '2')
80
+ end
81
+
82
+ it "should not assert the presence of different radio buttons when outside the form tag" do
83
+ @wrong_form.should_not have_form(:post => '/endpoint').with(:radio, 'choice', '1', '2')
84
+ end
85
+
86
+ it "should assert the presence of different radio buttons with one too much values" do
87
+ @correct_form.should_not have_form(:post => '/endpoint').with(:radio, 'choice', '1', '2', '3')
88
+ end
89
+
90
+ it "should assert the presence of the checkbox" do
91
+ @correct_form.should have_form(:post => '/endpoint').with(:checkbox, 'select', '1')
92
+ end
93
+
94
+ it "should not assert the presence of the checkbox when outside the form tag" do
95
+ @correct_form.should have_form(:post => '/endpoint').with(:checkbox, 'select', '1')
96
+ end
97
+
98
+ it "should assert a form using a block syntax" do
99
+ @correct_form.should have_form(:post => '/endpoint') { |form|
100
+ form.hidden 'foo', 'bar'
101
+ form.checkbox 'select', '1'
102
+ form.radio 'choice', '1', '2'
103
+ form.text :username
104
+ form.password :password
105
+ }
106
+ end
107
+
108
+ end
@@ -0,0 +1,11 @@
1
+ require 'rubygems'
2
+ require 'spec'
3
+ require 'spec/autorun'
4
+
5
+ $:.unshift(File.dirname(__FILE__) + '/../lib')
6
+ require "rspec_form_matcher"
7
+
8
+ Spec::Runner.configure do |config|
9
+ # Include matchers for view specs
10
+ config.include Spec::Matchers::FormMatcher
11
+ end
metadata ADDED
@@ -0,0 +1,75 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: wvanbergen-rspec_form_matcher
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Willem van Bergen
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-08-28 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rspec
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 1.2.4
24
+ version:
25
+ description: The RSpec form matcher will check a string to see whether a specified form exists with the correct action and method. Moreover, it will check whether the specified fields actually occur within this form tag.
26
+ email: willem@vanbergen.org
27
+ executables: []
28
+
29
+ extensions: []
30
+
31
+ extra_rdoc_files:
32
+ - README.rdoc
33
+ files:
34
+ - .gitignore
35
+ - LICENSE
36
+ - README.rdoc
37
+ - Rakefile
38
+ - lib/rspec_form_matcher.rb
39
+ - rspec_form_matcher.gemspec
40
+ - spec/form_matcher_spec.rb
41
+ - spec/spec_helper.rb
42
+ has_rdoc: false
43
+ homepage: http://github.com/wvanbergen/rspec_form_matcher
44
+ licenses:
45
+ post_install_message:
46
+ rdoc_options:
47
+ - --title
48
+ - rspec_form_matcher
49
+ - --main
50
+ - README.rdoc
51
+ - --line-numbers
52
+ - --inline-source
53
+ require_paths:
54
+ - lib
55
+ required_ruby_version: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ version: "0"
60
+ version:
61
+ required_rubygems_version: !ruby/object:Gem::Requirement
62
+ requirements:
63
+ - - ">="
64
+ - !ruby/object:Gem::Version
65
+ version: "0"
66
+ version:
67
+ requirements: []
68
+
69
+ rubyforge_project:
70
+ rubygems_version: 1.3.5
71
+ signing_key:
72
+ specification_version: 2
73
+ summary: RSpec matcher to check forms including their fields.
74
+ test_files:
75
+ - spec/form_matcher_spec.rb