test_right 0.2.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/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
+