test_right 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2011 Sauce Labs Inc
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,73 @@
1
+ Test::Right - Opinionated full-stack browser testing
2
+ =================================================
3
+
4
+ Test::Right is a testing framework designed to help users get maximum value out
5
+ of browser testing. It provides a flexible Page Object model for building
6
+ robust, reliable tests quickly and easily. No more slogging through XPaths in
7
+ Selenium IDE: Test::Right is the right way to build browser tests.
8
+
9
+ Setup
10
+ -----
11
+
12
+ gem install test_right
13
+ cd MY_APP
14
+ test_right install
15
+
16
+ The test_right executable will create a default directory structure in
17
+ test/right for you to put your tests in.
18
+
19
+ Begin by setting the base_url setting in test/right/config.yml to the base URL
20
+ of your application staging environment. Then add the necessary code to reset
21
+ your application state and launch your server to setup.rb.
22
+
23
+ Tests are defined in terms of _actions_ and _properties_ on _widgets_. A
24
+ widget is a piece of functionality present on one more more pages of your
25
+ application. A single page can have many widgets, and multiple copies of a
26
+ widget may appear on the same page.
27
+
28
+ To get started, add widget definitions to the widgets/ directory. A widget
29
+ defines its elements in terms of standard Selenium 2 selectors and actions in
30
+ terms of those elements. For example, something like this in
31
+ test/right/widgets/login.rb:
32
+
33
+ class LoginWidget < Test::Right::Widget
34
+ field :username, :id => 'username'
35
+ button :login, :css => "input[type=submit]"
36
+
37
+ action :login |username, password|
38
+ fill_in :username, username
39
+ click :login
40
+ end
41
+ end
42
+
43
+ class CartWidget < Test::Right::Widget
44
+ element :count, :id => 'item_count'
45
+
46
+ property :number_of_items do
47
+ get_element(:count).text
48
+ end
49
+ end
50
+
51
+ Once your widgets are setup, write tests for features of your application in
52
+ test/right/features. For example, something like this would go in
53
+ test/right/features/shopping_cart.rb:
54
+
55
+ class ShoppingCartFeature < Test::Right::Feature
56
+ def setup
57
+ with LoginWidget do |w|
58
+ w.login
59
+ end
60
+ end
61
+
62
+ def test_adding_item
63
+ with ItemWidget do |w|
64
+ w.add_an_item
65
+ end
66
+
67
+ with CartWidget do |w|
68
+ assert_equal, 1, w.number_of_items
69
+ end
70
+ end
71
+ end
72
+
73
+ Learn more on the Test::Right wiki at https://github.com/saucelabs/test_right/wiki
data/Rakefile ADDED
@@ -0,0 +1,53 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ require 'rake/testtask'
5
+ Rake::TestTask.new(:test) do |test|
6
+ test.libs << 'lib' << 'test'
7
+ test.pattern = 'test/**/test_*.rb'
8
+ test.verbose = true
9
+ end
10
+
11
+ require 'rcov/rcovtask'
12
+ Rcov::RcovTask.new do |t|
13
+ #t.test_files = FileList['test/test_*.rb']
14
+ t.ruby_opts << "-Ilib" # in order to use this rcov
15
+ t.ruby_opts << "-Itest"
16
+ t.rcov_opts << "--xrefs" # comment to disable cross-references
17
+ t.rcov_opts << "--exclude-only" << "test/test*,^\/,^features\/,^widgets\/,test/helper.rb,test/mock_driver.rb"
18
+ t.verbose = true
19
+ end
20
+
21
+ task :build do
22
+ unless system "gem build test_right.gemspec"
23
+ raise "Failed to build"
24
+ end
25
+ end
26
+
27
+ desc 'Release gem to rubygems.org'
28
+ task :release => :build do
29
+ system "gem push `ls *.gem | sort | tail -n 1`"
30
+ end
31
+
32
+ desc 'tag current version'
33
+ task :tag do
34
+ version = nil
35
+ File.open("test_right.gemspec").each do |line|
36
+ if line =~ /s.version = "(.*)"/
37
+ version = $1
38
+ end
39
+ end
40
+
41
+ if version.nil?
42
+ raise "Couldn't find version"
43
+ end
44
+
45
+ system "git tag v#{version}"
46
+ end
47
+
48
+ desc 'push to github'
49
+ task :push do
50
+ system "git push origin master --tags"
51
+ end
52
+
53
+ task :default => [:test, :tag, :push]
@@ -0,0 +1,36 @@
1
+ module Test
2
+ module Right
3
+ module Assertions
4
+ DEFAULT_ASSERTION_TIMEOUT = 15 # seconds
5
+
6
+ def assert(timeout=DEFAULT_ASSERTION_TIMEOUT)
7
+ if !block_given?
8
+ raise ArgumentError, "assert requires a block"
9
+ end
10
+
11
+ start = Time.now
12
+ while Time.now-start < timeout
13
+ begin
14
+ if yield
15
+ return
16
+ end
17
+ rescue WidgetNotPresentError
18
+ end
19
+ sleep(0.5)
20
+ end
21
+
22
+ raise AssertionFailedError, "Assertion failed after #{timeout} seconds"
23
+ end
24
+
25
+ def assert_equal(expected, actual, timeout=DEFAULT_ASSERTION_TIMEOUT)
26
+ if actual.is_a? Value
27
+ assert do
28
+ expected == actual.value
29
+ end
30
+ else
31
+ raise AssertionFailedError, "Expected #{expected.inspect} but got #{actual.inspect}" unless expected == actual
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,34 @@
1
+ require 'selenium-webdriver'
2
+
3
+ module Test
4
+ module Right
5
+ class BrowserDriver
6
+ def initialize(config)
7
+ @base_url = config[:base_url]
8
+ if @base_url =~ /\/$/
9
+ @base_url = @base_url[0..-2]
10
+ end
11
+ @driver = Selenium::WebDriver.for :firefox
12
+ end
13
+
14
+ def get(url, options = {})
15
+ if options[:relative]
16
+ @driver.get(relative_url(url))
17
+ else
18
+ @driver.get(url)
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ def relative_url(url)
25
+ raise ConfigurationError, "No base_url in config.yml" if @base_url.nil?
26
+ @base_url + url
27
+ end
28
+
29
+ def method_missing(name, *args)
30
+ @driver.send(name, *args)
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,117 @@
1
+ require 'yaml'
2
+
3
+ module Test
4
+ module Right
5
+ class CLI
6
+ RUBY_FILE = /^[^.].+.rb$/
7
+
8
+
9
+ def start(argument_list)
10
+ if argument_list.first == "install"
11
+ Generator.new(argument_list[1..-1]).generate
12
+ return
13
+ else
14
+ load_and_run_tests
15
+ end
16
+ end
17
+
18
+ def load_and_run_tests
19
+ run_setup
20
+
21
+ subdir = false
22
+ if File.directory? "test/right"
23
+ Dir.chdir("test/right")
24
+ subdir = true
25
+ end
26
+
27
+ load_config
28
+ load_widgets
29
+ load_features
30
+
31
+ Dir.chdir("../..") if subdir
32
+
33
+ puts "Running #{features.size} features"
34
+ runner = Runner.new(config, widgets, features)
35
+ if runner.run
36
+ puts "Passed!"
37
+ else
38
+ at_exit {
39
+ exit(1)
40
+ }
41
+ puts "Failed:"
42
+ runner.results.each do |feature, feature_result|
43
+ puts " #{feature}"
44
+ feature_result.each do |method, result|
45
+ if result.is_a? Exception
46
+ if result.is_a? WidgetActionNotImplemented
47
+ puts " #{method} => #{result}"
48
+ else
49
+ puts " #{method} => #{result.class} - #{result}"
50
+ result.backtrace.each do |trace|
51
+ puts " #{trace}"
52
+ end
53
+ end
54
+ else
55
+ puts " #{method} => #{result}"
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
61
+
62
+ def run_setup
63
+ if File.exists? "setup.rb"
64
+ unless system("./setup.rb")
65
+ raise ConfigurationError, "Setup failed"
66
+ end
67
+ elsif File.exists? "test/right/setup.rb"
68
+ unless system("test/right/setup.rb")
69
+ raise ConfigurationError, "Setup failed"
70
+ end
71
+ end
72
+ end
73
+
74
+ def load_config
75
+ options = {}
76
+ if File.exists? "config.yml"
77
+ options = YAML.load(open("config.yml"))
78
+ end
79
+ @config = Config.new(options)
80
+ end
81
+
82
+ def config
83
+ @config
84
+ end
85
+
86
+ def load_widgets
87
+ raise ConfigurationError, "no widgets/ directory" unless File.directory? "widgets"
88
+ load_ruby_in_dir("widgets")
89
+ end
90
+
91
+ def widgets
92
+ Widget.subclasses || []
93
+ end
94
+
95
+ def load_features
96
+ raise ConfigurationError, "no features/ directory" unless File.directory? "features"
97
+ load_ruby_in_dir("features")
98
+ end
99
+
100
+ def features
101
+ Feature.subclasses || []
102
+ end
103
+
104
+ private
105
+
106
+ def load_ruby_in_dir(dirname)
107
+ Dir.foreach dirname do |filename|
108
+ unless [".", ".."].include? filename
109
+ if filename =~ RUBY_FILE
110
+ load "#{dirname}/#{filename}"
111
+ end
112
+ end
113
+ end
114
+ end
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,13 @@
1
+ module Test
2
+ module Right
3
+ class Config
4
+ def initialize(options={})
5
+ @options = options
6
+ end
7
+
8
+ def [](name)
9
+ @options[name] || @options[name.to_s]
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,22 @@
1
+ require 'set'
2
+
3
+ module Test
4
+ module Right
5
+ class DataFactory
6
+ def initialize(template)
7
+ @template = template
8
+ @used_ids = Set.new([nil])
9
+ end
10
+
11
+ def [](name)
12
+ base = @template[name] || @template[name.to_s] || name.to_s
13
+ id = nil
14
+ while @used_ids.include? id
15
+ id = rand(100000)
16
+ end
17
+ base += id.to_s
18
+ return base
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,15 @@
1
+ module Test
2
+ module Right
3
+ class Error < StandardError; end
4
+ class ConfigurationError < Error; end
5
+ class WidgetActionNotImplemented < Error; end
6
+ class WidgetNotFoundError < Error; end
7
+ class SelectorNotFoundError < Error; end
8
+ class SelectorsNotFoundError < Error; end
9
+ class ElementNotFoundError < Error; end
10
+ class AssertionFailedError < Error; end
11
+ class WidgetConfigurationError < Error; end
12
+ class WidgetNotPresentError < Error; end
13
+ class IAmConfusedError < Error; end
14
+ end
15
+ end
@@ -0,0 +1,38 @@
1
+ module Test
2
+ module Right
3
+ class Feature
4
+ extend Utils::SubclassTracking
5
+ include Assertions
6
+
7
+ attr_reader :data
8
+
9
+ WIDGET_TIMEOUT = 10 # seconds
10
+
11
+ def initialize(driver, data)
12
+ @driver = driver
13
+ @data = data
14
+ end
15
+
16
+ private
17
+
18
+
19
+ def with(widget_class)
20
+ wait_for(widget_class)
21
+ yield widget_class.new(@driver)
22
+ end
23
+
24
+ def wait_for(widget_class)
25
+ widget = widget_class.new(@driver)
26
+
27
+ timeout = Time.now + WIDGET_TIMEOUT
28
+ while Time.now < timeout
29
+ break if widget.exists?
30
+ sleep(0.25)
31
+ end
32
+ if !widget.exists?
33
+ raise WidgetNotPresentError
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,28 @@
1
+ require 'fileutils'
2
+
3
+ module Test
4
+ module Right
5
+ class Generator
6
+ include FileUtils
7
+
8
+ def initialize(args)
9
+ @args = args
10
+ end
11
+
12
+ def generate
13
+ mkdir_p("test/right/features")
14
+ mkdir_p("test/right/widgets")
15
+
16
+ open("test/right/config.yml", 'wb') do |file|
17
+ file.write <<-EOF
18
+ # The base URL of your staging server
19
+ base_url: http://example.com/
20
+
21
+ # Which browser you want to run your tests in
22
+ browser: firefox
23
+ EOF
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,83 @@
1
+ # trigger autoload before the threads get ahold of it
2
+ Selenium::WebDriver::Firefox
3
+
4
+ module Test
5
+ module Right
6
+ class Runner
7
+ attr_reader :results, :widget_classes
8
+
9
+ def initialize(config, widgets, features)
10
+ @config = config
11
+ @widget_classes = widgets
12
+ @features = features
13
+ @results = {}
14
+ @pool = Threadz::ThreadPool.new(:initial_size => 2, :maximum_size => 2)
15
+ @result_queue = Queue.new
16
+ @data_template = config[:data] || {}
17
+ end
18
+
19
+ def run
20
+ @batch = @pool.new_batch
21
+
22
+ @features.sort_by{|x| rand(10000)}.all? do |feature|
23
+ run_feature(feature)
24
+ end
25
+
26
+ @batch.wait_until_done
27
+
28
+ process_results
29
+ end
30
+
31
+ def process_results
32
+ failed = false
33
+ until @result_queue.empty?
34
+ feature, method, result = @result_queue.pop
35
+ if result.is_a? Exception
36
+ failed = true
37
+ end
38
+ @results[feature] ||= {}
39
+ @results[feature][method] = result
40
+ end
41
+ return !failed
42
+ end
43
+
44
+ def run_feature(feature)
45
+ methods = feature.instance_methods
46
+ methods.sort_by{|x| rand(10000)}.each do |method_name|
47
+ if method_name =~ /^test_/
48
+ @batch << Proc.new do
49
+ begin
50
+ method = method_name.to_sym
51
+ run_test(feature, method_name.to_sym)
52
+
53
+ @result_queue << [feature, method, true]
54
+ rescue => e
55
+ @result_queue << [feature, method, e]
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
61
+
62
+ def run_test(feature, method)
63
+ if $MOCK_DRIVER
64
+ driver = MockDriver.new(@config)
65
+ else
66
+ driver = BrowserDriver.new(@config)
67
+ end
68
+
69
+ data = DataFactory.new(@data_template)
70
+
71
+ begin
72
+ target = feature.new(driver, data)
73
+ if target.respond_to? :setup
74
+ target.setup
75
+ end
76
+ target.send(method)
77
+ ensure
78
+ driver.quit
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,20 @@
1
+ module Test
2
+ module Right
3
+ module Utils
4
+ module SubclassTracking
5
+ def inherited(subclass)
6
+ @subclasses ||= []
7
+ @subclasses << subclass
8
+ end
9
+
10
+ def subclasses
11
+ @subclasses
12
+ end
13
+
14
+ def wipe!
15
+ @subclasses = []
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,13 @@
1
+ module Test
2
+ module Right
3
+ class Value
4
+ def initialize(&body)
5
+ @body = body
6
+ end
7
+
8
+ def value
9
+ @body.call
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,240 @@
1
+ module Test
2
+ module Right
3
+ class Widget
4
+ extend Utils::SubclassTracking
5
+
6
+ module ClassMethods
7
+ attr_reader :root, :name_elements, :validator, :location
8
+
9
+ def selector(name)
10
+ @selectors[name]
11
+ end
12
+
13
+ def element(name, locator)
14
+ @selectors[name] = locator
15
+ end
16
+
17
+ def lives_at(url)
18
+ @location = url
19
+ end
20
+
21
+ def rooted_at(root)
22
+ @root = [root.keys.first, root.values.first]
23
+ @selectors[:root] = root
24
+ end
25
+
26
+ def named_by(*args)
27
+ @name_elements ||= []
28
+ if args.length == 2
29
+ property, name_element = args
30
+ @name_elements << [property, name_element.keys.first, name_element.values.first]
31
+ else
32
+ name_element = args.first
33
+ @name_elements << [:text, name_element.keys.first, name_element.values.first]
34
+ end
35
+ end
36
+
37
+ def validated_by_presence_of(selector)
38
+ @validator = selector
39
+ end
40
+
41
+ def action(name, &body)
42
+ define_method name do |*args|
43
+ self.validate!
44
+ self.instance_exec *args, &body
45
+ end
46
+ end
47
+
48
+ def property(name, &body)
49
+ define_method name do
50
+ self.validate!
51
+ Value.new do
52
+ self.instance_eval &body
53
+ end
54
+ end
55
+ end
56
+
57
+ def [](name)
58
+ WidgetProxy.new(self, name)
59
+ end
60
+
61
+ alias_method :button, :element
62
+ alias_method :field, :element
63
+ end
64
+
65
+ def self.inherited(subclass)
66
+ @subclasses ||= []
67
+ @subclasses << subclass
68
+ subclass.instance_eval do
69
+ @selectors = {}
70
+ @location = nil
71
+ end
72
+
73
+ subclass.extend(ClassMethods)
74
+ end
75
+
76
+ attr_reader :name
77
+
78
+ def initialize(driver, name=nil)
79
+ @driver = driver
80
+ @name = name
81
+ end
82
+
83
+ def visit
84
+ @driver.get(self.class.location, :relative => true)
85
+ end
86
+
87
+ def exists?
88
+ begin
89
+ root
90
+ return true
91
+ rescue WidgetNotPresentError
92
+ return false
93
+ end
94
+ end
95
+
96
+ def validate!(timeout=15)
97
+ timeout = Time.now + timeout
98
+ while Time.now < timeout
99
+ if self.exists?
100
+ return
101
+ end
102
+ end
103
+ raise WidgetNotPresentError
104
+ end
105
+
106
+ def method_missing(name, *args)
107
+ raise WidgetActionNotImplemented, "#{self.class.to_s}##{name.to_s} not implemented"
108
+ end
109
+
110
+ private
111
+
112
+ def fill_in(selector_name, value)
113
+ get_element(selector_name).send_keys(value)
114
+ end
115
+
116
+ def clear(selector_name)
117
+ get_element(selector_name).clear
118
+ end
119
+
120
+ def click(selector_name)
121
+ get_element(selector_name).click
122
+ end
123
+
124
+ def select(selector_name)
125
+ get_element(selector_name).select
126
+ end
127
+
128
+ def navigate_to(url)
129
+ @driver.get(url)
130
+ end
131
+
132
+ def wait_for_element_present(selector_name, timeout=10)
133
+ endtime = Time.now + timeout
134
+ while Time.now < endtime
135
+ begin
136
+ get_element(selector_name)
137
+ return
138
+ rescue ElementNotFoundError
139
+ rescue WidgetNotPresentError
140
+ end
141
+ end
142
+ raise ElementNotFoundError
143
+ end
144
+
145
+ def wait_for_element_not_present(selector_name, timeout=10)
146
+ endtime = Time.now + timeout
147
+ while Time.now < endtime
148
+ begin
149
+ get_element(selector_name)
150
+ rescue ElementNotFoundError
151
+ return true
152
+ rescue WidgetNotPresentError
153
+ return true
154
+ end
155
+ end
156
+ raise Error, "Element didn't disappear"
157
+ end
158
+
159
+ def get_element(selector_name)
160
+ selector = find_selector(selector_name)
161
+ if selector_name == :root
162
+ begin
163
+ return @driver.find_element(*self.class.root)
164
+ rescue Selenium::WebDriver::Error::NoSuchElementError => e
165
+ raise ElementNotFoundError, e.message
166
+ end
167
+ end
168
+
169
+ target = nil
170
+ while target.nil?
171
+ begin
172
+ target = root.find_element(*selector)
173
+ rescue Selenium::WebDriver::Error::NoSuchElementError => e
174
+ raise ElementNotFoundError, "Element #{selector_name} not found on #{self.class.name} using #{selector.inspect}"
175
+ rescue Selenium::WebDriver::Error::ObsoleteElementError
176
+ # ignore
177
+ end
178
+ end
179
+ return target
180
+ end
181
+
182
+ def get_elements(selector_name)
183
+ selector = find_selector(selector_name)
184
+ begin
185
+ element = root.find_elements(*selector)
186
+ rescue Selenium::WebDriver::Error::NoSuchElementError => e
187
+ raise ElementNotFoundError, e.message
188
+ end
189
+ end
190
+
191
+ def find_selector(selector_name)
192
+ if !self.class.selector(selector_name)
193
+ raise SelectorNotFoundError, "Selector \"#{selector_name}\" for Widget \"#{self.class}\" not found"
194
+ end
195
+
196
+ selector = self.class.selector(selector_name)
197
+ return [selector.keys.first, selector.values.first]
198
+ end
199
+
200
+ def root
201
+ if self.class.root.nil? && self.class.name_elements.nil?
202
+ return @driver
203
+ elsif self.class.root && self.class.name_elements.nil?
204
+ begin
205
+ return @driver.find_element(*self.class.root)
206
+ rescue Selenium::WebDriver::Error::NoSuchElementError => e
207
+ raise WidgetNotPresentError, "#{self.class.name} not found on page"
208
+ end
209
+ elsif self.class.root && self.class.name_elements
210
+ all_instances = @driver.find_elements(*self.class.root)
211
+ target = all_instances.find do |root_element|
212
+ self.class.name_elements.any? do |property, how, what|
213
+ begin
214
+ element = root_element.find_element(how, what)
215
+ element_name = nil
216
+ if :value == property
217
+ element_name = element.attribute('value')
218
+ else
219
+ element_name = element.send(property)
220
+ end
221
+ @name == element_name
222
+ rescue Selenium::WebDriver::Error::ObsoleteElementError
223
+ false
224
+ rescue Selenium::WebDriver::Error::NoSuchElementError
225
+ false
226
+ end
227
+ end
228
+ end
229
+ if target.nil?
230
+ raise WidgetNotPresentError, "#{self.class.name} with name \"#{name}\" not found"
231
+ end
232
+
233
+ return target
234
+ else
235
+ raise IAmConfusedError
236
+ end
237
+ end
238
+ end
239
+ end
240
+ end
@@ -0,0 +1,14 @@
1
+ module Test
2
+ module Right
3
+ class WidgetProxy
4
+ def initialize(klass, name)
5
+ @klass = klass
6
+ @name = name
7
+ end
8
+
9
+ def new(driver)
10
+ @klass.new(driver, @name)
11
+ end
12
+ end
13
+ end
14
+ end
data/lib/test/right.rb ADDED
@@ -0,0 +1,21 @@
1
+ require 'test/unit/assertions'
2
+ require 'threadz'
3
+
4
+ module Test
5
+ module Right
6
+ end
7
+ end
8
+
9
+ require 'test/right/errors'
10
+ require 'test/right/utils'
11
+ require 'test/right/config'
12
+ require 'test/right/value'
13
+ require 'test/right/widget_proxy'
14
+ require 'test/right/widget'
15
+ require 'test/right/assertions'
16
+ require 'test/right/feature'
17
+ require 'test/right/browser_driver'
18
+ require 'test/right/data_factory'
19
+ require 'test/right/runner'
20
+ require 'test/right/generator'
21
+ require 'test/right/cli'
metadata ADDED
@@ -0,0 +1,131 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: test_right
3
+ version: !ruby/object:Gem::Version
4
+ hash: 23
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 2
9
+ - 0
10
+ version: 0.2.0
11
+ platform: ruby
12
+ authors:
13
+ - Eric Allen
14
+ - Sean Grove
15
+ autorequire:
16
+ bindir: bin
17
+ cert_chain: []
18
+
19
+ date: 2011-05-03 00:00:00 -07:00
20
+ default_executable:
21
+ dependencies:
22
+ - !ruby/object:Gem::Dependency
23
+ name: selenium-webdriver
24
+ prerelease: false
25
+ requirement: &id001 !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ">="
29
+ - !ruby/object:Gem::Version
30
+ hash: 23
31
+ segments:
32
+ - 0
33
+ - 2
34
+ - 0
35
+ version: 0.2.0
36
+ type: :runtime
37
+ version_requirements: *id001
38
+ - !ruby/object:Gem::Dependency
39
+ name: threadz
40
+ prerelease: false
41
+ requirement: &id002 !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ~>
45
+ - !ruby/object:Gem::Version
46
+ hash: 29
47
+ segments:
48
+ - 0
49
+ - 1
50
+ - 3
51
+ version: 0.1.3
52
+ type: :runtime
53
+ version_requirements: *id002
54
+ - !ruby/object:Gem::Dependency
55
+ name: mocha
56
+ prerelease: false
57
+ requirement: &id003 !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ hash: 35
63
+ segments:
64
+ - 0
65
+ - 9
66
+ - 12
67
+ version: 0.9.12
68
+ type: :development
69
+ version_requirements: *id003
70
+ description: An opinionated browser testing framework
71
+ email: help@saucelabs.com
72
+ executables: []
73
+
74
+ extensions: []
75
+
76
+ extra_rdoc_files: []
77
+
78
+ files:
79
+ - LICENSE
80
+ - README.md
81
+ - Rakefile
82
+ - lib/test/right/assertions.rb
83
+ - lib/test/right/browser_driver.rb
84
+ - lib/test/right/cli.rb
85
+ - lib/test/right/config.rb
86
+ - lib/test/right/data_factory.rb
87
+ - lib/test/right/errors.rb
88
+ - lib/test/right/feature.rb
89
+ - lib/test/right/generator.rb
90
+ - lib/test/right/runner.rb
91
+ - lib/test/right/utils.rb
92
+ - lib/test/right/value.rb
93
+ - lib/test/right/widget.rb
94
+ - lib/test/right/widget_proxy.rb
95
+ - lib/test/right.rb
96
+ has_rdoc: true
97
+ homepage:
98
+ licenses: []
99
+
100
+ post_install_message:
101
+ rdoc_options: []
102
+
103
+ require_paths:
104
+ - lib
105
+ required_ruby_version: !ruby/object:Gem::Requirement
106
+ none: false
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ hash: 3
111
+ segments:
112
+ - 0
113
+ version: "0"
114
+ required_rubygems_version: !ruby/object:Gem::Requirement
115
+ none: false
116
+ requirements:
117
+ - - ">="
118
+ - !ruby/object:Gem::Version
119
+ hash: 3
120
+ segments:
121
+ - 0
122
+ version: "0"
123
+ requirements: []
124
+
125
+ rubyforge_project:
126
+ rubygems_version: 1.4.2
127
+ signing_key:
128
+ specification_version: 3
129
+ summary: An opinionated browser testing framework
130
+ test_files: []
131
+