suhyo 0.0.1

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/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,21 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## PROJECT::GENERAL
17
+ coverage
18
+ rdoc
19
+ pkg
20
+
21
+ ## PROJECT::SPECIFIC
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 jarrett
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.markdown ADDED
@@ -0,0 +1,4 @@
1
+ Suhyo
2
+ =====
3
+
4
+ Suhyo is an extension to RSpec and Webrat. It provides commonly-needed matchers for web applications. The matchers are documented with RDoc in their respective files in the `lib` directory.
data/Rakefile ADDED
@@ -0,0 +1,46 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "suhyo"
8
+ gem.summary = 'Matchers for web app specs'
9
+ gem.description = 'Matchers built on Webrat to address some common needs in web app testing'
10
+ gem.email = 'jarrett@uchicago.edu'
11
+ gem.homepage = 'http://github.com/jarrett/suhyo'
12
+ gem.authors = ['jarrett']
13
+ gem.add_dependency 'rspec', '>= 1.2.9'
14
+ gem.add_dependency 'webrat', '>= 0.7.0'
15
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
16
+ end
17
+ Jeweler::GemcutterTasks.new
18
+ rescue LoadError
19
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
20
+ end
21
+
22
+ require 'spec/rake/spectask'
23
+ Spec::Rake::SpecTask.new(:spec) do |spec|
24
+ spec.libs << 'lib' << 'spec'
25
+ spec.spec_files = FileList['spec/**/*_spec.rb']
26
+ end
27
+
28
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
29
+ spec.libs << 'lib' << 'spec'
30
+ spec.pattern = 'spec/**/*_spec.rb'
31
+ spec.rcov = true
32
+ end
33
+
34
+ task :spec => :check_dependencies
35
+
36
+ task :default => :spec
37
+
38
+ require 'rake/rdoctask'
39
+ Rake::RDocTask.new do |rdoc|
40
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
41
+
42
+ rdoc.rdoc_dir = 'rdoc'
43
+ rdoc.title = "suhyo #{version}"
44
+ rdoc.rdoc_files.include('README*')
45
+ rdoc.rdoc_files.include('lib/**/*.rb')
46
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
@@ -0,0 +1,22 @@
1
+ require 'ostruct'
2
+
3
+ module Suhyo
4
+ # Get/set Suhyo's config values. This method can be used in several ways:
5
+ #
6
+ # 1. To get config values:
7
+ # puts Suhyo.config.access_denied_url
8
+ # 2. To set config values:
9
+ # Suhyo.config.access_denied_url = 'http://test.host/login'
10
+ # 3. To set config values in block form:
11
+ # Suhyo.config do |config|
12
+ # config.access_denied_url = 'http://test.host/login'
13
+ # end
14
+ def self.config
15
+ @config ||= OpenStruct.new
16
+ # Set defaults here
17
+ @config.access_denied_url ||= 'http://test.host/login'
18
+ # End of defaults
19
+ yield @config if block_given?
20
+ @config
21
+ end
22
+ end
@@ -0,0 +1,38 @@
1
+ module Suhyo
2
+ module ControllerMatchers
3
+ class DenyAccess
4
+ def matches?(response)
5
+ @response = response
6
+ @response.status.split(' ').first == '403' or (@response.redirect? and response.redirect_url == Suhyo.config.access_denied_url)
7
+ end
8
+
9
+ def failure_message
10
+ if @response.redirect?
11
+ "expected response to deny access (403 or 302 to #{Suhyo.config.access_denied_url}). Status was #{@response.status} with redirect to #{@response.redirect_url}."
12
+ else
13
+ "expected response to deny access (403 or 302 to #{Suhyo.config.access_denied_url}). Status was #{@response.status}."
14
+ end
15
+ end
16
+
17
+ def negative_failure_message
18
+ 'expected response not to deny access'
19
+ end
20
+ end
21
+
22
+ # Looks for either of two things:
23
+ #
24
+ # 1. HTTP status code 403 Forbidden
25
+ # 2. Redirect to a certain access denied URL.
26
+ #
27
+ # The access denied URL is determined by +Suhyo.config.access_denied_url+,
28
+ # which defaults to +http://test.host/login+.
29
+ #
30
+ # Usage:
31
+ #
32
+ # get :some_restricted_action
33
+ # response.should deny_access
34
+ def deny_access
35
+ DenyAccess.new
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,155 @@
1
+ module Suhyo
2
+ module ViewMatchers
3
+ include Webrat::Matchers
4
+
5
+ class HaveOrderedContent < ::Webrat::Matchers::HasContent
6
+ def initialize(content, options = {})
7
+ @content = content
8
+ @options = options
9
+ end
10
+
11
+ def matches?(stringlike)
12
+ @document = Webrat::XML.document(stringlike)
13
+ @element = @document.inner_text
14
+ compacted = @element.gsub(/\s+/, ' ')
15
+ if index = compacted.index(@content)
16
+ if @options.has_key?(:before)
17
+ @other_content_index = compacted.index(options[:before])
18
+ index < @other_content_index
19
+ elsif @options.has_key?(:after)
20
+ @other_content_index = compacted.index(options[:after])
21
+ index > @other_content_index
22
+ else
23
+ true
24
+ end
25
+ else
26
+ nil
27
+ end
28
+ end
29
+
30
+ def failure_message
31
+ "expected the following element's content to #{content_message}:\n#{squeeze_space(@element)} #{order_message}"
32
+ end
33
+
34
+ def negative_failure_message
35
+ "expected the following element's content to not #{content_message}:\n#{squeeze_space(@element)} #{order_message}"
36
+ end
37
+
38
+ def order_message
39
+ if @options.has_key?(:before)
40
+ str = "before #{options[:before]}"
41
+ if @other_content_index.nil?
42
+ str << " but #{options[:before]} was not foudn"
43
+ end
44
+ elsif @options.has_key?(:after)
45
+ str = "after #{options[:after]}"
46
+ if @other_content_index.nil?
47
+ str << " but #{options[:after]} was not foudn"
48
+ end
49
+ else
50
+ nil
51
+ end
52
+ end
53
+ end
54
+
55
+ # Like Webrat's +contain+ matcher, except it checks that one bit of text comes before or after another.
56
+ # Useful for testing sort order, for example.
57
+ def contain_in_order(content, options = {})
58
+ HaveOrderedContent.new(content, options)
59
+ end
60
+
61
+ # A simple wrapper around +have_selector+. Usage:
62
+ #
63
+ # response.should have_link(:url => people_url, :text => 'People', :ancestors => 'div#main')
64
+ #
65
+ # The above example would match the following:
66
+ #
67
+ # <div id="main">
68
+ # <a href="http://test.host/people">People</a>
69
+ # </div>
70
+ #
71
+ # Options other than +:url+, +:text+, and +ancestors+ will be passed through
72
+ # to +have_selector+.
73
+ def have_link(options = {})
74
+ options[:href] = options.delete(:url) if options.has_key?(:url)
75
+ options[:content] = options.delete(:text) if options.has_key?(:text)
76
+ if ancestors = options.delete(:ancestors)
77
+ selector = ancestors + ' a'
78
+ else
79
+ selector = 'a'
80
+ end
81
+ have_selector(selector, options)
82
+ end
83
+
84
+ class HaveRestfulForm < ::Webrat::Matchers::HaveSelector
85
+ def initialize(method, options = {}, &block)
86
+ @options = options
87
+ @method = method.to_s.downcase
88
+ # browser_method is the method the browser actually uses, either GET or POST
89
+ @browser_method = (method == 'get') ? 'get' : 'post'
90
+ if ancestors = options.delete(:ancestors)
91
+ @expected = ancestors + ' form'
92
+ else
93
+ @expected = 'form'
94
+ end
95
+ @options.merge!(:method => @browser_method)
96
+ @block = block
97
+ end
98
+
99
+ def matches(stringlike)
100
+ # Cache it, because we're going to use it again in matches_hidden_field?
101
+ @matches ||= super(stringlike)
102
+ end
103
+
104
+ def matches?(stringlike, &block)
105
+ super(stringlike, &block) and matches_hidden_field?(stringlike)
106
+ end
107
+
108
+ def matches_hidden_field?(stringlike)
109
+ form = matches(stringlike)
110
+ case @method
111
+ when 'get', 'post'
112
+ !::Webrat::Matchers::HaveSelector.new('input', :name => '_method').matches?(form)
113
+ when 'put'
114
+ ::Webrat::Matchers::HaveSelector.new('input', :name => '_method', :value => 'put').matches?(form)
115
+ when 'delete'
116
+ ::Webrat::Matchers::HaveSelector.new('input', :name => '_method', :value => 'delete').matches?(form)
117
+ end
118
+ end
119
+
120
+ # Messages
121
+
122
+ def failure_message
123
+ "expected following output to contain a #{@method.upcase} form#{attributes_message}:\n\n#{@document}"
124
+ end
125
+
126
+ def negative_failure_message
127
+ "expected following output to omit a #{@method.upcase} form#{attributes_message}:\n\n#{@document}"
128
+ end
129
+
130
+ def attributes_message
131
+ attrs = @options.dup
132
+ attrs.delete(:method)
133
+ attrs.empty? ? nil : ' with attributes ' + attrs.inspect
134
+ end
135
+ end
136
+
137
+ # Wrapper around +have_selector+. Checks for a Rails-style form with the given HTTP method.
138
+ # You can also specify the +action+ and any other other attributes in the +options+ hash. Usage:
139
+ #
140
+ # response.should have_restful_form('put', :action => person_path(42), :class => 'edit_person', :ancestors => 'div#main')
141
+ #
142
+ # The above example would match the following:
143
+ #
144
+ # <div id="main">
145
+ # <form method="post" action="/people/42">
146
+ # <input type="hidden" name="_method" value="put"/>
147
+ # </form>
148
+ # </div>
149
+ #
150
+ # Options other than +ancestors+ will be passed through to +have_selector+.
151
+ def have_restful_form(method, options = {})
152
+ HaveRestfulForm.new(method, options)
153
+ end
154
+ end
155
+ end
data/lib/suhyo.rb ADDED
@@ -0,0 +1,8 @@
1
+ require 'webrat'
2
+ require 'cucumber'
3
+
4
+ $: << File.expand_path(File.dirname(__FILE__))
5
+
6
+ require 'suhyo/view_matchers'
7
+ require 'suhyo/controller_matchers'
8
+ require 'suhyo/config'
@@ -0,0 +1,42 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe Suhyo::ViewMatchers do
4
+ include Suhyo::ControllerMatchers
5
+
6
+ describe '#deny_access' do
7
+ before :all do
8
+ Suhyo.config.access_denied_url = 'http://test.host/access_denied'
9
+ end
10
+
11
+ before :each do
12
+ @response = mock(:status => '200 OK', :redirect? => false, :redirect_url => nil)
13
+ end
14
+
15
+ it 'matches 403' do
16
+ @response.stub(:status => '403 Forbidden')
17
+ @response.should deny_access
18
+ end
19
+
20
+ it 'matches a 302 redirect to the access denied URL' do
21
+ @response.stub(:redirect? => true, :status_code => '302 Found', :redirect_url => 'http://test.host/access_denied')
22
+ @response.should deny_access
23
+ end
24
+
25
+ ((
26
+ (100..102).to_a +
27
+ (200..207).to_a +
28
+ (400..450).to_a +
29
+ (500..530).to_a
30
+ ) - [403]).each do |code|
31
+ it "does not match #{code}" do
32
+ @response.stub(:status => code.to_s + ' Code Description')
33
+ @response.should_not deny_access
34
+ end
35
+ end
36
+
37
+ it 'does not match a 302 redirect to anything other than the access denied URL' do
38
+ @response.stub(:redirect? => true, :status => '302 Found', :redirect_url => 'http://test.host/private')
39
+ @response.should_not deny_access
40
+ end
41
+ end
42
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1 @@
1
+ --color
@@ -0,0 +1,9 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+ require 'suhyo'
4
+ require 'spec'
5
+ require 'spec/autorun'
6
+
7
+ Spec::Runner.configure do |config|
8
+
9
+ end
@@ -0,0 +1,84 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe Suhyo::ViewMatchers do
4
+ include Suhyo::ViewMatchers
5
+
6
+ describe '#have_link' do
7
+ it 'matches with no options' do
8
+ '<a href="http://example.com">Foo</a>'.should have_link
9
+ end
10
+
11
+ it 'matches the text' do
12
+ '<a href="http://example.com">Foo</a>'.should have_link(:text => 'Foo')
13
+ end
14
+
15
+ it 'matches the URL' do
16
+ '<a href="http://example.com">Foo</a>'.should have_link(:url => 'http://example.com')
17
+ end
18
+
19
+ it 'matches the ancestors' do
20
+ '<div id="main"><a href="http://example.com">Foo</a></div>'.should have_link(:ancestors => 'div#main')
21
+ end
22
+
23
+ it 'does not match when there is no link' do
24
+ '<div><p>Foo</p></div>'.should_not have_link
25
+ end
26
+
27
+ it 'does not match when the text is wrong' do
28
+ '<a href="http://example.com">Foo</a>'.should_not have_link(:text => 'Bar')
29
+ end
30
+
31
+ it 'does not match when the URL is wrong' do
32
+ '<a href="http://example.com">Foo</a>'.should_not have_link(:url => 'http://google.com')
33
+ end
34
+
35
+ it 'does not match when the ancestors are wrong' do
36
+ '<a href="http://example.com">Foo</a>'.should_not have_link(:ancestors => 'div#main')
37
+ end
38
+ end
39
+
40
+ describe '#have_restful_form' do
41
+ def restful_form(method)
42
+ case method
43
+ when 'get'
44
+ browser_method = 'get'
45
+ hidden_field = nil
46
+ when 'post'
47
+ browser_method = 'post'
48
+ hidden_field = nil
49
+ when 'put'
50
+ browser_method = 'post'
51
+ hidden_field = '<input type="hidden" name="_method" value="put"/>'
52
+ when 'delete'
53
+ browser_method = 'post'
54
+ hidden_field = '<input type="hidden" name="_method" value="delete"/>'
55
+ end
56
+ %Q{<form method="#{browser_method}">#{hidden_field}</form>}
57
+ end
58
+
59
+ %w(get post put delete).each do |expected_method|
60
+ it "matches a #{expected_method.upcase} form" do
61
+ restful_form(expected_method).should have_restful_form(expected_method)
62
+ end
63
+
64
+ (%w(get post put delete) - [expected_method]).each do |actual_method|
65
+ it "does not match #{expected_method.upcase} when the method is #{actual_method.upcase}" do
66
+ restful_form(actual_method).should_not have_restful_form(expected_method)
67
+ end
68
+ end
69
+ end
70
+
71
+ it 'matches the ancestors' do
72
+ ('<div id="main">' + restful_form('get') + '</div>').should have_restful_form('get', :ancestors => 'div#main')
73
+ end
74
+
75
+ it 'does not match if the ancestors are wrong' do
76
+ restful_form('get').should_not have_restful_form('get', :ancestors => 'div#main')
77
+ end
78
+
79
+ it 'matches arbitrary attributes' do
80
+ '<form action="http://example.com" method="get"></form>'.should have_restful_form('get', :action => 'http://example.com')
81
+ '<form action="http://example.com" method="get"></form>'.should_not have_restful_form('get', :action => 'http://google.com')
82
+ end
83
+ end
84
+ end
data/suhyo.gemspec ADDED
@@ -0,0 +1,63 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{suhyo}
8
+ s.version = "0.0.1"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["jarrett"]
12
+ s.date = %q{2010-03-11}
13
+ s.description = %q{Matchers built on Webrat to address some common needs in web app testing}
14
+ s.email = %q{jarrett@uchicago.edu}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.markdown"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ ".gitignore",
22
+ "LICENSE",
23
+ "README.markdown",
24
+ "Rakefile",
25
+ "VERSION",
26
+ "lib/suhyo.rb",
27
+ "lib/suhyo/config.rb",
28
+ "lib/suhyo/controller_matchers.rb",
29
+ "lib/suhyo/view_matchers.rb",
30
+ "spec/controller_matchers_spec.rb",
31
+ "spec/spec.opts",
32
+ "spec/spec_helper.rb",
33
+ "spec/view_matchers_spec.rb",
34
+ "suhyo.gemspec"
35
+ ]
36
+ s.homepage = %q{http://github.com/jarrett/suhyo}
37
+ s.rdoc_options = ["--charset=UTF-8"]
38
+ s.require_paths = ["lib"]
39
+ s.rubygems_version = %q{1.3.5}
40
+ s.summary = %q{Matchers for web app specs}
41
+ s.test_files = [
42
+ "spec/controller_matchers_spec.rb",
43
+ "spec/spec_helper.rb",
44
+ "spec/view_matchers_spec.rb"
45
+ ]
46
+
47
+ if s.respond_to? :specification_version then
48
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
49
+ s.specification_version = 3
50
+
51
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
52
+ s.add_runtime_dependency(%q<rspec>, [">= 1.2.9"])
53
+ s.add_runtime_dependency(%q<webrat>, [">= 0.7.0"])
54
+ else
55
+ s.add_dependency(%q<rspec>, [">= 1.2.9"])
56
+ s.add_dependency(%q<webrat>, [">= 0.7.0"])
57
+ end
58
+ else
59
+ s.add_dependency(%q<rspec>, [">= 1.2.9"])
60
+ s.add_dependency(%q<webrat>, [">= 0.7.0"])
61
+ end
62
+ end
63
+
metadata ADDED
@@ -0,0 +1,91 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: suhyo
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - jarrett
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2010-03-11 00:00:00 -06: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.9
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: webrat
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 0.7.0
34
+ version:
35
+ description: Matchers built on Webrat to address some common needs in web app testing
36
+ email: jarrett@uchicago.edu
37
+ executables: []
38
+
39
+ extensions: []
40
+
41
+ extra_rdoc_files:
42
+ - LICENSE
43
+ - README.markdown
44
+ files:
45
+ - .document
46
+ - .gitignore
47
+ - LICENSE
48
+ - README.markdown
49
+ - Rakefile
50
+ - VERSION
51
+ - lib/suhyo.rb
52
+ - lib/suhyo/config.rb
53
+ - lib/suhyo/controller_matchers.rb
54
+ - lib/suhyo/view_matchers.rb
55
+ - spec/controller_matchers_spec.rb
56
+ - spec/spec.opts
57
+ - spec/spec_helper.rb
58
+ - spec/view_matchers_spec.rb
59
+ - suhyo.gemspec
60
+ has_rdoc: true
61
+ homepage: http://github.com/jarrett/suhyo
62
+ licenses: []
63
+
64
+ post_install_message:
65
+ rdoc_options:
66
+ - --charset=UTF-8
67
+ require_paths:
68
+ - lib
69
+ required_ruby_version: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: "0"
74
+ version:
75
+ required_rubygems_version: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - ">="
78
+ - !ruby/object:Gem::Version
79
+ version: "0"
80
+ version:
81
+ requirements: []
82
+
83
+ rubyforge_project:
84
+ rubygems_version: 1.3.5
85
+ signing_key:
86
+ specification_version: 3
87
+ summary: Matchers for web app specs
88
+ test_files:
89
+ - spec/controller_matchers_spec.rb
90
+ - spec/spec_helper.rb
91
+ - spec/view_matchers_spec.rb