watir-rspec 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/.gitignore +17 -0
- data/Gemfile +3 -0
- data/LICENSE +22 -0
- data/README.md +80 -0
- data/Rakefile +1 -0
- data/lib/watir/rspec/active_record_shared_connection.rb +16 -0
- data/lib/watir/rspec/helper.rb +25 -0
- data/lib/watir/rspec/html_formatter.rb +91 -0
- data/lib/watir/rspec/version.rb +5 -0
- data/lib/watir/rspec.rb +158 -0
- data/watir-rspec.gemspec +19 -0
- metadata +73 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Jarmo Pertman
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
# Watir::RSpec
|
2
|
+
|
3
|
+
Use Watir with RSpec with ease.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add these lines to your application's Gemfile:
|
8
|
+
|
9
|
+
group :test do
|
10
|
+
gem 'watir-rspec'
|
11
|
+
end
|
12
|
+
|
13
|
+
And add these lines to your spec\_helper.rb file:
|
14
|
+
|
15
|
+
RSpec.configure do |config|
|
16
|
+
# Add Watir::RSpec::HtmlFormatter to get links to the screenshots, html and
|
17
|
+
# all other files created during the failing examples.
|
18
|
+
config.add_formatter('documentation')
|
19
|
+
config.add_formatter(Watir::RSpec::HtmlFormatter)
|
20
|
+
|
21
|
+
# Open up the browser for each example.
|
22
|
+
config.before :all do
|
23
|
+
@browser = Watir::Browser.new
|
24
|
+
end
|
25
|
+
|
26
|
+
# Close that browser after each example.
|
27
|
+
config.after :all do
|
28
|
+
@browser.close if @browser
|
29
|
+
end
|
30
|
+
|
31
|
+
# Include RSpec::Helper into each of your example group for making it possible to
|
32
|
+
# write in your examples instead of:
|
33
|
+
# @browser.goto "localhost"
|
34
|
+
# @browser.text_field(:name => "first_name").set "Bob"
|
35
|
+
#
|
36
|
+
# like this:
|
37
|
+
# goto "localhost"
|
38
|
+
# text_field(:name => "first_name").set "Bob"
|
39
|
+
#
|
40
|
+
# This needs that you've used @browser as an instance variable name in
|
41
|
+
# before :all block.
|
42
|
+
config.include Watir::RSpec::Helper
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
When using Rails and writing specs to requests directory, add an additional filter for RSpec:
|
47
|
+
|
48
|
+
config.before :all, :type => :request do
|
49
|
+
@browser = Watir::Browser.new :chrome
|
50
|
+
end
|
51
|
+
|
52
|
+
config.after :all, :type => :request do
|
53
|
+
@browser.close if @browser
|
54
|
+
end
|
55
|
+
|
56
|
+
config.include Watir::RSpec::Helper, :type => :request
|
57
|
+
|
58
|
+
## Usage
|
59
|
+
|
60
|
+
Just use the browser in your examples. If you haven't included
|
61
|
+
Watir::RSpec::Helper, then you need to use the @browser instance variable when
|
62
|
+
calling Watir::Browser methods, otherwise you may omit it.
|
63
|
+
|
64
|
+
When creating/downloading/uploading files in your examples and using
|
65
|
+
Watir::RSpec::HtmlFormatter then you can generate links automatically to these files when example
|
66
|
+
fails. To do that you need to use Watir::RSpec.file\_path method for generating
|
67
|
+
unique file name:
|
68
|
+
|
69
|
+
uploaded_file_path = Watir::RSpec.file_path("uploaded.txt")
|
70
|
+
File.open(uploaded_file_path, "w") {|file| file.write "Generated File Input"}
|
71
|
+
|
72
|
+
If you're using Rails, then you also need to install [watir-rails](https://github.com/watir/watir-rails) gem.
|
73
|
+
|
74
|
+
## Contributing
|
75
|
+
|
76
|
+
1. Fork it
|
77
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
78
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
79
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
80
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,16 @@
|
|
1
|
+
RSpec.configuration.before(:suite) do
|
2
|
+
# Allow RSpec specs to use transactional fixtures when using Watir.
|
3
|
+
#
|
4
|
+
# Tip from http://blog.plataformatec.com.br/2011/12/three-tips-to-improve-the-performance-of-your-test-suite/
|
5
|
+
class ::ActiveRecord::Base
|
6
|
+
mattr_accessor :shared_connection
|
7
|
+
@@shared_connection = nil
|
8
|
+
|
9
|
+
def self.connection
|
10
|
+
@@shared_connection || retrieve_connection
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
# Forces all threads to share the same connection.
|
15
|
+
::ActiveRecord::Base.shared_connection = ::ActiveRecord::Base.connection
|
16
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Watir
|
2
|
+
class RSpec
|
3
|
+
module Helper
|
4
|
+
extend Forwardable
|
5
|
+
|
6
|
+
def method_missing name, *args #:nodoc:
|
7
|
+
if @browser.respond_to?(name)
|
8
|
+
Helper.module_eval %Q[
|
9
|
+
def #{name}(*args)
|
10
|
+
@browser.send(:#{name}, *args) {yield}
|
11
|
+
end
|
12
|
+
]
|
13
|
+
self.send(name, *args) {yield}
|
14
|
+
else
|
15
|
+
super
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# make sure that using method 'p' will be invoked on browser
|
20
|
+
# and not Kernel
|
21
|
+
# use Kernel.p if you need to dump some variable
|
22
|
+
def_delegators :@browser, :p
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
require 'rspec/core/formatters/html_formatter'
|
2
|
+
require 'pathname'
|
3
|
+
require 'fileutils'
|
4
|
+
|
5
|
+
module Watir
|
6
|
+
class RSpec
|
7
|
+
# Custom RSpec formatter
|
8
|
+
# * saves screenshot of the browser upon test failure
|
9
|
+
# * saves html of the browser upon test failure
|
10
|
+
# * saves all files generated/downloaded during the test and shows them in the report
|
11
|
+
class HtmlFormatter < ::RSpec::Core::Formatters::HtmlFormatter
|
12
|
+
def initialize(output) # :nodoc:
|
13
|
+
@output_path = File.expand_path(ENV["WATIR_RESULTS_PATH"] || (output.respond_to?(:path) ? output.path : "tmp/spec-results/index.html"))
|
14
|
+
FileUtils.rm_rf File.dirname(@output_path), :verbose => true if File.exists?(@output_path)
|
15
|
+
|
16
|
+
@output_relative_path = Pathname.new(@output_path).relative_path_from(Pathname.new(Dir.pwd))
|
17
|
+
puts "Results will be saved to #{@output_relative_path}"
|
18
|
+
|
19
|
+
@files_dir = File.dirname(@output_path)
|
20
|
+
FileUtils.mkdir_p(@files_dir)
|
21
|
+
@files_saved_during_example = []
|
22
|
+
|
23
|
+
super(File.open(@output_path, "w"))
|
24
|
+
end
|
25
|
+
|
26
|
+
def example_group_started(example_group) # :nodoc:
|
27
|
+
@files_saved_during_example.clear
|
28
|
+
super
|
29
|
+
end
|
30
|
+
|
31
|
+
def example_started(example) # :nodoc:
|
32
|
+
@files_saved_during_example.clear
|
33
|
+
super
|
34
|
+
end
|
35
|
+
|
36
|
+
def extra_failure_content(exception) # :nodoc:
|
37
|
+
browser = example_group.before_all_ivars[:@browser]
|
38
|
+
return super unless browser && browser.exists?
|
39
|
+
|
40
|
+
save_screenshot browser
|
41
|
+
save_html browser
|
42
|
+
|
43
|
+
content = []
|
44
|
+
content << "<span>"
|
45
|
+
@files_saved_during_example.each {|f| content << link_for(f)}
|
46
|
+
content << "</span>"
|
47
|
+
super + content.join($/)
|
48
|
+
end
|
49
|
+
|
50
|
+
# Generates unique file name and path for each example.
|
51
|
+
#
|
52
|
+
# All file names generated with this method will be shown
|
53
|
+
# on the report.
|
54
|
+
def file_path(file_name, description=nil)
|
55
|
+
extension = File.extname(file_name)
|
56
|
+
basename = File.basename(file_name, extension)
|
57
|
+
file_path = File.join(@files_dir, "#{basename}_#{::Time.now.strftime("%H%M%S")}_#{example_group_number}_#{example_number}#{extension}")
|
58
|
+
@files_saved_during_example.unshift(:desc => description, :path => file_path)
|
59
|
+
file_path
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def link_for(file) # :nodoc:
|
65
|
+
return unless File.exists?(file[:path])
|
66
|
+
|
67
|
+
description = file[:desc] ? file[:desc] : File.extname(file[:path]).upcase[1..-1]
|
68
|
+
path = Pathname.new(file[:path])
|
69
|
+
"<a href='#{path.relative_path_from(Pathname.new(@output_path).dirname)}'>#{description}</a> "
|
70
|
+
end
|
71
|
+
|
72
|
+
def save_html(browser) # :nodoc:
|
73
|
+
file_name = file_path("browser.html")
|
74
|
+
begin
|
75
|
+
html = browser.html
|
76
|
+
File.open(file_name, 'w') {|f| f.puts html}
|
77
|
+
rescue => e
|
78
|
+
$stderr.puts "saving of html failed: #{e.message}"
|
79
|
+
end
|
80
|
+
file_name
|
81
|
+
end
|
82
|
+
|
83
|
+
def save_screenshot(browser, description="Screenshot") # :nodoc:
|
84
|
+
file_name = file_path("screenshot.png", description)
|
85
|
+
browser.screenshot.save(file_name)
|
86
|
+
file_name
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
data/lib/watir/rspec.rb
ADDED
@@ -0,0 +1,158 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
require File.expand_path("rspec/helper", File.dirname(__FILE__))
|
3
|
+
require File.expand_path("rspec/html_formatter", File.dirname(__FILE__))
|
4
|
+
|
5
|
+
if defined? ActiveRecord
|
6
|
+
require File.expand_path("rspec/active_record_shared_connection", File.dirname(__FILE__))
|
7
|
+
end
|
8
|
+
|
9
|
+
module Watir
|
10
|
+
# add #within(timeout) and #during(timeout) methods for every matcher for allowing to wait until some condition is met.
|
11
|
+
# div.click
|
12
|
+
# another_div.should be_present.within(5)
|
13
|
+
#
|
14
|
+
# expect {
|
15
|
+
# div.click
|
16
|
+
# }.to change {another_div.text}.from("before").to("after").within(5)
|
17
|
+
#
|
18
|
+
# expect {
|
19
|
+
# div.click
|
20
|
+
# }.to make {another_div.present?}.within(5)
|
21
|
+
#
|
22
|
+
# expect {
|
23
|
+
# div.click
|
24
|
+
# }.to change {another_div.text}.soon
|
25
|
+
#
|
26
|
+
class RSpec
|
27
|
+
class << self
|
28
|
+
def bootstrap const
|
29
|
+
const.class_eval do
|
30
|
+
|
31
|
+
inst_methods = instance_methods.map &:to_sym
|
32
|
+
|
33
|
+
if !(inst_methods.include?(:__matches?) || inst_methods.include?(:__does_not_match?)) &&
|
34
|
+
(inst_methods.include?(:matches?) || inst_methods.include?(:does_not_match?))
|
35
|
+
|
36
|
+
def within(timeout)
|
37
|
+
@within_timeout = timeout
|
38
|
+
self
|
39
|
+
end
|
40
|
+
|
41
|
+
def during(timeout)
|
42
|
+
@during_timeout = timeout
|
43
|
+
self
|
44
|
+
end
|
45
|
+
|
46
|
+
def soon
|
47
|
+
within(30)
|
48
|
+
end
|
49
|
+
|
50
|
+
def seconds
|
51
|
+
# for syntactic sugar
|
52
|
+
self
|
53
|
+
end
|
54
|
+
|
55
|
+
alias_method :second, :seconds
|
56
|
+
|
57
|
+
def minutes
|
58
|
+
@within_timeout *= 60 if @within_timeout
|
59
|
+
@during_timeout *= 60 if @during_timeout
|
60
|
+
self
|
61
|
+
end
|
62
|
+
|
63
|
+
alias_method :minute, :minutes
|
64
|
+
end
|
65
|
+
|
66
|
+
if inst_methods.include? :matches?
|
67
|
+
alias_method :__matches?, :matches?
|
68
|
+
|
69
|
+
def matches?(actual)
|
70
|
+
match_with_wait {__matches?(actual)}
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
if inst_methods.include? :does_not_match?
|
75
|
+
alias_method :__does_not_match?, :does_not_match?
|
76
|
+
|
77
|
+
def does_not_match?(actual)
|
78
|
+
match_with_wait {__does_not_match?(actual)}
|
79
|
+
end
|
80
|
+
elsif inst_methods.include? :matches?
|
81
|
+
def does_not_match?(actual)
|
82
|
+
match_with_wait {!__matches?(actual)}
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
private
|
87
|
+
|
88
|
+
def match_with_wait
|
89
|
+
if @within_timeout
|
90
|
+
timeout = @within_timeout; @within_timeout = nil
|
91
|
+
Watir::Wait.until(timeout) {yield} rescue false
|
92
|
+
elsif @during_timeout
|
93
|
+
timeout = @during_timeout; @during_timeout = nil
|
94
|
+
Watir::Wait.while(timeout) {yield} rescue true
|
95
|
+
else
|
96
|
+
yield
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def file_path(file_name, description=nil)
|
103
|
+
formatter.file_path(file_name, description=nil)
|
104
|
+
end
|
105
|
+
|
106
|
+
private
|
107
|
+
|
108
|
+
def formatter
|
109
|
+
@formatter ||= begin
|
110
|
+
formatter = ::RSpec.configuration.formatters.find {|f| f.kind_of? Watir::RSpec::HtmlFormatter}
|
111
|
+
unless formatter
|
112
|
+
raise <<-EOF
|
113
|
+
Watir::RSpec::HtmlFormatter is not set as a RSpec formatter.
|
114
|
+
|
115
|
+
You need to add it into your spec_helper.rb file like this:
|
116
|
+
RSpec.configure do |config|
|
117
|
+
config.add_formatter('documentation')
|
118
|
+
config.add_formatter(Watir::RSpec::HtmlFormatter)
|
119
|
+
end
|
120
|
+
EOF
|
121
|
+
end
|
122
|
+
formatter
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
|
127
|
+
end
|
128
|
+
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
# patch for #within(timeout) method
|
133
|
+
module ::RSpec::Matchers
|
134
|
+
class BuiltIn::Change
|
135
|
+
def matches?(event_proc)
|
136
|
+
raise_block_syntax_error if block_given?
|
137
|
+
|
138
|
+
# to make #change work with #in(timeout) method
|
139
|
+
unless defined? @actual_before
|
140
|
+
@actual_before = evaluate_value_proc
|
141
|
+
event_proc.call
|
142
|
+
end
|
143
|
+
@actual_after = evaluate_value_proc
|
144
|
+
|
145
|
+
(!change_expected? || changed?) && matches_before? && matches_after? && matches_expected_delta? && matches_min? && matches_max?
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
alias_method :make, :change
|
150
|
+
end
|
151
|
+
|
152
|
+
matchers = RSpec::Matchers::BuiltIn.constants.map(&:to_sym)
|
153
|
+
matchers.delete :BaseMatcher
|
154
|
+
matchers.each do |const|
|
155
|
+
Watir::RSpec.bootstrap RSpec::Matchers::BuiltIn.const_get const
|
156
|
+
end
|
157
|
+
|
158
|
+
Watir::RSpec.bootstrap RSpec::Matchers::DSL::Matcher
|
data/watir-rspec.gemspec
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/watir/rspec/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["Jarmo Pertman"]
|
6
|
+
gem.email = ["jarmo.p@gmail.com"]
|
7
|
+
gem.description = %q{Use Watir with RSpec with ease.}
|
8
|
+
gem.summary = %q{Use Watir with RSpec with ease.}
|
9
|
+
gem.homepage = "http://github.com/watir/watir-rspec"
|
10
|
+
|
11
|
+
gem.files = `git ls-files`.split($\)
|
12
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
13
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
14
|
+
gem.name = "watir-rspec"
|
15
|
+
gem.require_paths = ["lib"]
|
16
|
+
gem.version = Watir::RSpec::VERSION
|
17
|
+
|
18
|
+
gem.add_dependency "rspec", "~>2.0"
|
19
|
+
end
|
metadata
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: watir-rspec
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Jarmo Pertman
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-08-28 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rspec
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '2.0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '2.0'
|
30
|
+
description: Use Watir with RSpec with ease.
|
31
|
+
email:
|
32
|
+
- jarmo.p@gmail.com
|
33
|
+
executables: []
|
34
|
+
extensions: []
|
35
|
+
extra_rdoc_files: []
|
36
|
+
files:
|
37
|
+
- .gitignore
|
38
|
+
- Gemfile
|
39
|
+
- LICENSE
|
40
|
+
- README.md
|
41
|
+
- Rakefile
|
42
|
+
- lib/watir/rspec.rb
|
43
|
+
- lib/watir/rspec/active_record_shared_connection.rb
|
44
|
+
- lib/watir/rspec/helper.rb
|
45
|
+
- lib/watir/rspec/html_formatter.rb
|
46
|
+
- lib/watir/rspec/version.rb
|
47
|
+
- watir-rspec.gemspec
|
48
|
+
homepage: http://github.com/watir/watir-rspec
|
49
|
+
licenses: []
|
50
|
+
post_install_message:
|
51
|
+
rdoc_options: []
|
52
|
+
require_paths:
|
53
|
+
- lib
|
54
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
55
|
+
none: false
|
56
|
+
requirements:
|
57
|
+
- - ! '>='
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: '0'
|
60
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ! '>='
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
66
|
+
requirements: []
|
67
|
+
rubyforge_project:
|
68
|
+
rubygems_version: 1.8.24
|
69
|
+
signing_key:
|
70
|
+
specification_version: 3
|
71
|
+
summary: Use Watir with RSpec with ease.
|
72
|
+
test_files: []
|
73
|
+
has_rdoc:
|