mediawiki_selenium 0.4.3 → 1.0.0.pre.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/.gitreview +1 -1
  3. data/.rspec +1 -0
  4. data/.yardopts +1 -0
  5. data/Gemfile +1 -1
  6. data/README.md +108 -55
  7. data/bin/mediawiki-selenium-init +5 -0
  8. data/lib/mediawiki_selenium.rb +10 -19
  9. data/lib/mediawiki_selenium/browser_factory.rb +24 -0
  10. data/lib/mediawiki_selenium/browser_factory/base.rb +212 -0
  11. data/lib/mediawiki_selenium/browser_factory/chrome.rb +27 -0
  12. data/lib/mediawiki_selenium/browser_factory/firefox.rb +34 -0
  13. data/lib/mediawiki_selenium/browser_factory/phantomjs.rb +21 -0
  14. data/lib/mediawiki_selenium/configuration_error.rb +4 -0
  15. data/lib/mediawiki_selenium/environment.rb +494 -0
  16. data/lib/mediawiki_selenium/initializer.rb +19 -0
  17. data/lib/mediawiki_selenium/page_factory.rb +38 -0
  18. data/lib/mediawiki_selenium/remote_browser_factory.rb +87 -0
  19. data/lib/mediawiki_selenium/step_definitions.rb +5 -0
  20. data/lib/mediawiki_selenium/support.rb +3 -0
  21. data/lib/mediawiki_selenium/support/env.rb +3 -127
  22. data/lib/mediawiki_selenium/support/hooks.rb +23 -34
  23. data/lib/mediawiki_selenium/support/modules/api_helper.rb +44 -5
  24. data/lib/mediawiki_selenium/support/pages.rb +4 -0
  25. data/lib/mediawiki_selenium/support/pages/api_page.rb +1 -0
  26. data/lib/mediawiki_selenium/support/pages/login_page.rb +3 -12
  27. data/lib/mediawiki_selenium/support/pages/random_page.rb +2 -12
  28. data/lib/mediawiki_selenium/support/pages/reset_preferences_page.rb +3 -12
  29. data/lib/mediawiki_selenium/version.rb +1 -1
  30. data/mediawiki_selenium.gemspec +9 -3
  31. data/spec/api_helper_spec.rb +84 -0
  32. data/spec/browser_factory/base_spec.rb +211 -0
  33. data/spec/browser_factory/chrome_spec.rb +36 -0
  34. data/spec/browser_factory/firefox_spec.rb +60 -0
  35. data/spec/browser_factory/phantomjs_spec.rb +38 -0
  36. data/spec/environment_spec.rb +474 -0
  37. data/spec/page_factory_spec.rb +61 -0
  38. data/spec/remote_browser_factory_spec.rb +50 -0
  39. data/spec/spec_helper.rb +4 -0
  40. data/templates/tests/browser/environments.yml +35 -0
  41. data/templates/tests/browser/features/support/env.rb +6 -0
  42. metadata +122 -20
  43. data/lib/mediawiki_selenium/support/modules/sauce_helper.rb +0 -13
  44. data/lib/mediawiki_selenium/support/modules/url_module.rb +0 -21
  45. data/spec/README +0 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1370bd256c005fa2d4d225fd94da2124219c7120
4
- data.tar.gz: 802b87cd07fdc7c9661f072433a17ad378a7a09c
3
+ metadata.gz: 6cfb45e7cecfe3d24690b4bc3b0577b523a32f0c
4
+ data.tar.gz: da0ddd70c32a9e191f88eb28091295b115a36621
5
5
  SHA512:
6
- metadata.gz: 7ca28e9b1124c314f402d4abec4e4f544c052abfaeeeff006539c960f988c0ea38c7c80d567d64662ecb767ef82f9f423a2c3f1c111fe8ac303171be90c23b03
7
- data.tar.gz: 272eba01eb16179269395248009a517b5a79b8c08fe57a0124f71fa78ecacb60d960bdcb3d2104d01195b973d722299c75b518d324300cbea8b72382c61de4ca
6
+ metadata.gz: ba624b67027eeec05822cd82927f4849859f07d43302d416965ef8be9f3541b010d332ef19668ec07b87d9d57288cbfa6e4ea61309c04ea5c683abddc999d24e
7
+ data.tar.gz: 231504b0c5ae4b35f307b0544c67e56b6c07fb9e4cdc2050a3b089e54db445c80c047ed0f55ad850ce9584e54f3f4ed86720b25ed49d3c9175b44c8d1f533a17
data/.gitreview CHANGED
@@ -2,5 +2,5 @@
2
2
  host=gerrit.wikimedia.org
3
3
  port=29418
4
4
  project=mediawiki/selenium.git
5
- defaultbranch=0.4
5
+ defaultbranch=master
6
6
  defaultrebase=0
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/.yardopts CHANGED
@@ -1 +1,2 @@
1
1
  --title "MediaWiki Selenium"
2
+ --markup markdown
data/Gemfile CHANGED
@@ -1,4 +1,4 @@
1
- #ruby=ruby-2.1.1
1
+ #ruby=ruby-2.1.3
2
2
  #ruby-gemset=mediawiki_selenium
3
3
 
4
4
  source "https://rubygems.org"
data/README.md CHANGED
@@ -1,82 +1,123 @@
1
- # Mediawiki::Selenium
1
+ # MediaWiki-Selenium
2
2
 
3
- Several MediaWiki extensions share code that makes it easy to run Selenium
4
- tests. This gem makes it easy to update the shared code.
3
+ MediaWiki-Selenium is a Ruby framework for the implementation and execution of
4
+ acceptance tests against [MediaWiki](https://www.mediawiki.org/wiki/MediaWiki)
5
+ installations. It is comprised of a number of core dependencies and native
6
+ APIs that help you describe the expected behavior of your MediaWiki-related
7
+ features, and drive cross-browser simulations to ensure the correctness of
8
+ your implementation.
9
+
10
+ ## Core Dependencies
11
+
12
+ * [Cucumber](https://github.com/cucumber/cucumber) provides the natural
13
+ [Gherkin](https://github.com/cucumber/cucumber/wiki/Gherkin) language used
14
+ to describe application features, a basic API for binding that natural
15
+ language to step definitions written in Ruby, and a test runner for
16
+ executing the suite.
17
+
18
+ * [PageObject](https://github.com/cheezy/page-object) helps you to implement
19
+ [PageObject patterns](https://code.google.com/p/selenium/wiki/PageObjects)
20
+ within your test suite that better encapsulate the expected structure and
21
+ mechanics of your application's UI.
22
+
23
+ * [Watir](https://github.com/watir/watir/) and
24
+ [Selenium](http://docs.seleniumhq.org/) for driving browser sessions.
25
+
26
+ * [RSpec](https://github.com/rspec/rspec-expectations) for asserting
27
+ expectations of scenario outcomes.
5
28
 
6
29
  ## Installation
7
30
 
8
- To run the Selenium tests you will have to install Ruby. Look at the `Gemfile`
9
- file for the exact required version. You also have to install the latest
10
- versions of RubyGems and Firefox (the default browser in which the tests run).
11
- The easiest way to install Ruby on Linux/Unix/Mac is [RVM](https://rvm.io/) and
12
- on Windows [RubyInstaller](http://rubyinstaller.org/).
31
+ Ruby 1.9 or above is required, 2.1 is recommended. The easiest way to install
32
+ it is with [RVM](https://rvm.io/) or [rbenv](http://rbenv.org/) on
33
+ Linux/Unix/OS X, and with [RubyInstaller](http://rubyinstaller.org/) on
34
+ Windows.
13
35
 
14
- cd tests/browser
15
- gem update --system
16
- gem install bundler
17
- bundle install
36
+ Create a `Gemfile` in the root of your MediaWiki-related project that
37
+ specifies the version of `mediawiki_selenium` you wish to use (typically the
38
+ latest version).
18
39
 
19
- If you're not using RVM to manage your Ruby versions, you will need to run the
20
- commands as root (using `sudo`).
40
+ gem 'mediawiki_selenium', '~> 1.0.0'
21
41
 
22
- Environment variables `MEDIAWIKI_USER` and `MEDIAWIKI_PASSWORD` are required for
23
- tests tagged `@login`. For local testing, create a test user on your local wiki
24
- and export the user and password as the values for those variables.
25
- For example:
42
+ Install the gem and its dependencies by running `bundle install`. (If
43
+ [Bundler](http://bundler.io/) is not yet installed, install it with
44
+ `gem install bundler`, or `sudo gem install bundler` if you're using a
45
+ system wide Ruby.)
26
46
 
27
- export MEDIAWIKI_USER=<username here> # Linux/Unix/Mac
28
- set MEDIAWIKI_USER=<username here> # Windows Command Prompt
29
- $env:MEDIAWIKI_USER="<username here>" # Windows PowerShell
47
+ ## Getting Started
30
48
 
31
- export MEDIAWIKI_PASSWORD=<password here> # Linux/Unix/Mac
32
- set MEDIAWIKI_PASSWORD=<password here> # Windows Command Prompt
33
- $env:MEDIAWIKI_PASSWORD="<password here>" # Windows PowerShell
49
+ Once the gem is installed, run `mediawiki-selenium-init` in your project's
50
+ root directory to create a boilerplate configuration under `tests/browser`.
34
51
 
35
- ## Usage
52
+ $ bundle exec mediawiki-selenium-init
53
+ create tests/browser
54
+ create tests/browser/environments.yml
55
+ create tests/browser/features/support/env.rb
36
56
 
37
- Run the tests with `bundle exec cucumber`, this should start Firefox.
57
+ Default configuration for various resources (wiki URLs, users, etc.) is
58
+ typically loaded from an `environments.yml` YAML file in the current working
59
+ directory. It should contain defaults for each environment in which the tests
60
+ are expected to run, indexed by environment name. Double check that the
61
+ generated file is suitable for how you expect your tests to be run, for
62
+ example against [Mediawiki-Vagrant](http://www.mediawiki.org/wiki/MediaWiki-Vagrant)
63
+ for local development, or against at least the [Beta Cluster](http://www.mediawiki.org/wiki/Beta_cluster)
64
+ for continuous integration.
38
65
 
39
- By default the tests run at en.wikipedia.beta.wmflabs.org. If you want to run
40
- the tests on another web server, set the `MEDIAWIKI_URL` environment variable. For example:
66
+ For details on how environment configuration is loaded and used by step
67
+ definitions, see the documentation for `MediawikiSelenium::Environment`.
41
68
 
42
- export MEDIAWIKI_URL=http://commons.wikimedia.beta.wmflabs.org/wiki/ # Linux/Unix/Mac
43
- set MEDIAWIKI_URL=http://commons.wikimedia.beta.wmflabs.org/wiki/ # Windows Command Prompt
44
- $env:MEDIAWIKI_URL="http://commons.wikimedia.beta.wmflabs.org/wiki/" # Windows PowerShell
69
+ ## Writing Tests
45
70
 
46
- Some tests use the [MediaWiki web API](https://www.mediawiki.org/wiki/API:Main_page)
47
- to interact with the web server in addition to driving a browser.
48
- If you want these tests to run on another web server,
49
- you must also set the `MEDIAWIKI_API_URL` environment variable. For example:
71
+ The ability to write effective and cruft-free tests will come with practice
72
+ and greater familiarity with the underlying libraries. On mediawiki.org,
73
+ you'll find some helpful [high-level documentation](http://www.mediawiki.org/wiki/Quality_Assurance/Browser_testing/Writing_tests)
74
+ to get you started.
50
75
 
51
- export MEDIAWIKI_API_URL=http://commons.wikimedia.beta.wmflabs.org/w/api.php # Linux/Unix/Mac
52
- set MEDIAWIKI_API_URL=http://commons.wikimedia.beta.wmflabs.org/w/api.php # Windows Command Prompt
53
- $env:MEDIAWIKI_API_URL="http://commons.wikimedia.beta.wmflabs.org/w/api.php" # Windows PowerShell
76
+ To see exactly which methods are available from within step definitions, see
77
+ the documentation for `MediawikiSelenium::Environment`,
78
+ `MediawikiSelenium::ApiHelper`, and `MediawikiSelenium::PageFactory`.
54
79
 
55
- To run a single test file:
80
+ ## Running Tests
56
81
 
57
- bundle exec cucumber features/FEATURE_NAME.feature
82
+ Execute your tests by running `bundle exec cucumber` from within the
83
+ `tests/browser` directory.
58
84
 
59
- To run a single test scenario, put a colon and the line number (NN) on which
60
- the scenario begins after the file name:
85
+ By default, the entire suite is run which may take some time. If you wish to
86
+ execute scenarios for just a single feature, you can provide the feature file
87
+ as an argument.
61
88
 
62
- bundle exec cucumber features/FEATURE_NAME.feature:NN
89
+ bundle exec cucumber feature/some.feature
63
90
 
64
- You can use a different browser with the `BROWSER` env variable, the fastest is
65
- probably PhantomJS, a headless browser:
91
+ To run a single scenario, give the line number as well.
92
+
93
+ bundle exec cucumber feature/some.feature:11
94
+
95
+ The set of default configuration to use (see "Getting started") is specified
96
+ by the `MEDIAWIKI_ENVIRONMENT` environment variable, which should be defined
97
+ somewhere in your shell profile. For example, if you're using
98
+ [Mediawiki-Vagrant](http://www.mediawiki.org/wiki/MediaWiki-Vagrant) for your
99
+ development and executing tests on the host OS, the environment name would be
100
+ `mw-vagrant-host`.
101
+
102
+ export MEDIAWIKI_ENVIRONMENT=mw-vagrant-host # Linux/Unix/Mac
103
+ set MEDIAWIKI_URL=mw-vagrant-host # Windows Command Prompt
104
+ $env:MEDIAWIKI_URL="mw-vagrant-host" # Windows PowerShell
105
+
106
+ Firefox is the default browser, but you can specify a different one by setting
107
+ `BROWSER`.
66
108
 
67
109
  export BROWSER=phantomjs # Linux/Unix/Mac
68
110
  set BROWSER=phantomjs # Windows Command Prompt
69
111
  $env:BROWSER="internet_explorer" # Windows PowerShell
70
112
 
71
113
  By default, the browser will close itself at the end of every scenario. If you
72
- want the browser to stay open, set the environment variable `KEEP_BROWSER_OPEN`
73
- to `true`:
114
+ want the browser to stay open, set `KEEP_BROWSER_OPEN` to `true`.
74
115
 
75
116
  export KEEP_BROWSER_OPEN=true # Linux/Unix/Mac
76
117
  set KEEP_BROWSER_OPEN=true # Windows Command Prompt
77
118
  $env:KEEP_BROWSER_OPEN="true" # Windows PowerShell
78
119
 
79
- ## Headless Mode
120
+ ### Headless Mode
80
121
 
81
122
  Headless operation can be useful when running tests in an environment where
82
123
  there's no GUI available, environments such as a continuous integration
@@ -109,7 +150,7 @@ behavior.
109
150
  # Keep xvfb running after execution (the default is to kill it)
110
151
  HEADLESS_DESTROY_AT_EXIT=false bundle exec cucumber ...
111
152
 
112
- ## Screenshots
153
+ ### Screenshots
113
154
 
114
155
  You can get screenshots on failures by setting the environment
115
156
  variable `SCREENSHOT_FAILURES` to `true`. Screenshots will be written under the
@@ -138,7 +179,7 @@ commit back both files.
138
179
 
139
180
  ### Repositories
140
181
 
141
- If not stated differently, Selenium tests are in `/tests/browser` folder and Jenkins jobs are at [integration.wikimedia.org/ci/view/BrowserTests](https://integration.wikimedia.org/ci/view/BrowserTests/).
182
+ If not stated differently, Selenium tests are in `tests/browser` folder and Jenkins jobs are at [integration.wikimedia.org/ci/view/BrowserTests](https://integration.wikimedia.org/ci/view/BrowserTests/).
142
183
 
143
184
  Repositories that use the gem:
144
185
 
@@ -177,11 +218,23 @@ See https://www.mediawiki.org/wiki/Gerrit
177
218
 
178
219
  ## Release notes
179
220
 
180
- ### 0.4.3 2015-06-03
181
- * Fixed bug in SauceLabs reporting for when a scenario is skipped
182
-
183
- ### 0.4.2 2015-02-04
184
- * Removed use of `onfocus` from `LoginPage#login_with`
221
+ ### 1.0.0 2015-01-16
222
+ * Substantial refactoring and backwards incompatible changes
223
+ * Implemented an "environment abstraction layer" with the aim to:
224
+ * Improve test determinism by sourcing environment-specific default
225
+ configurations and enforcing an immutable runtime configuration
226
+ * Simplify test patterns by providing DSL constructs around commonly tested
227
+ MediaWiki resources
228
+ * Manage multiple isolated browser sessions within a single test scenario
229
+ * Serve more advanced use cases by supporting ad hoc browser customization
230
+ * Cleaned up the global object space by moving methods into the new
231
+ `Environment` and `BrowserFactory` classes
232
+ * Further decoupled core framework from Cucumber, allowing for the possibility
233
+ of its use under other Ruby test frameworks like RSpec
234
+ * Established test suite with coverage for all newly implemented EAL modules
235
+ and classes
236
+ * Improved high level and inline documentation with examples and links to
237
+ upstream resources
185
238
 
186
239
  ### 0.4.1 2014-11-11
187
240
  * Additional headless environment variables: HEADLESS_DISPLAY, HEADLESS_REUSE, HEADLESS_DESTROY_AT_EXIT.
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "mediawiki_selenium"
4
+
5
+ MediawikiSelenium::Initializer.new.install
@@ -9,22 +9,13 @@ mediawiki_selenium top-level directory and at
9
9
  https://git.wikimedia.org/blob/mediawiki%2Fselenium/HEAD/CREDITS.
10
10
  =end
11
11
 
12
- require "mediawiki_selenium/version"
13
-
14
- require "mediawiki_selenium/support/env"
15
- require "mediawiki_selenium/support/hooks"
16
- require "mediawiki_selenium/support/sauce"
17
-
18
- require "mediawiki_selenium/step_definitions/login_steps"
19
- require "mediawiki_selenium/step_definitions/navigation_steps"
20
- require "mediawiki_selenium/step_definitions/preferences_steps"
21
- require "mediawiki_selenium/step_definitions/resource_loader_steps"
22
- require "mediawiki_selenium/step_definitions/upload_file_steps"
23
-
24
- require "mediawiki_selenium/support/modules/api_helper"
25
- require "mediawiki_selenium/support/modules/url_module"
26
-
27
- require "mediawiki_selenium/support/pages/api_page"
28
- require "mediawiki_selenium/support/pages/login_page"
29
- require "mediawiki_selenium/support/pages/random_page"
30
- require "mediawiki_selenium/support/pages/reset_preferences_page"
12
+ module MediawikiSelenium
13
+ autoload :VERSION, "mediawiki_selenium/version"
14
+ autoload :ApiHelper, "mediawiki_selenium/support/modules/api_helper"
15
+ autoload :BrowserFactory, "mediawiki_selenium/browser_factory"
16
+ autoload :ConfigurationError, "mediawiki_selenium/configuration_error"
17
+ autoload :Environment, "mediawiki_selenium/environment"
18
+ autoload :Initializer, "mediawiki_selenium/initializer"
19
+ autoload :PageFactory, "mediawiki_selenium/page_factory"
20
+ autoload :RemoteBrowserFactory, "mediawiki_selenium/remote_browser_factory"
21
+ end
@@ -0,0 +1,24 @@
1
+ module MediawikiSelenium
2
+ module BrowserFactory
3
+ autoload :Base, "mediawiki_selenium/browser_factory/base"
4
+ autoload :Firefox, "mediawiki_selenium/browser_factory/firefox"
5
+ autoload :Chrome, "mediawiki_selenium/browser_factory/chrome"
6
+ autoload :Phantomjs, "mediawiki_selenium/browser_factory/phantomjs"
7
+
8
+ # Resolves and instantiates a new factory for the given browser name.
9
+ #
10
+ # @example Create a new firefox factory
11
+ # factory = BrowserFactory.new(:firefox)
12
+ # # => #<MediawikiSelenium::BrowserFactory::Firefox>
13
+ # factory.browser_for(env) # => #<Watir::Browser>
14
+ #
15
+ # @param browser_name [Symbol] Browser name.
16
+ #
17
+ # @return [BrowserFactory::Base]
18
+ #
19
+ def self.new(browser_name)
20
+ factory_class = const_get(browser_name.to_s.split("_").map(&:capitalize).join(""))
21
+ factory_class.new(browser_name)
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,212 @@
1
+ require "watir-webdriver"
2
+
3
+ module MediawikiSelenium
4
+ module BrowserFactory
5
+ # Browser factories instantiate browsers of a certain type, configure
6
+ # them according to bound environmental variables, and cache them
7
+ # according to the uniqueness of that configuration.
8
+ #
9
+ class Base
10
+ class << self
11
+ # Binds environmental configuration to any browser created by
12
+ # factories of this type. Use of this method should generally be
13
+ # reserved for macro-style invocation in derived classes.
14
+ #
15
+ # @example Always configure Firefox's language according to `:browser_language`
16
+ # module MediawikiSelenium::BrowserFactory
17
+ # class Firefox < Base
18
+ # bind(:browser_language) do |language, options|
19
+ # options[:desired_capabilities][:firefox_profile]["intl.accept_languages"] = language
20
+ # end
21
+ # end
22
+ # end
23
+ #
24
+ # @param names [Symbol] One or more option names.
25
+ #
26
+ # @yield [values, browser_options] A block that binds the configuration to
27
+ # the browser options.
28
+ #
29
+ def bind(*names, &blk)
30
+ raise ArgumentError, "no block given" unless block_given?
31
+
32
+ key = names.length == 1 ? names.first : names
33
+ default_bindings[key] ||= []
34
+ default_bindings[key] << blk
35
+ end
36
+
37
+ # All bindings for this factory class combined with those of super
38
+ # classes.
39
+ #
40
+ # @return [Hash]
41
+ #
42
+ def bindings
43
+ if superclass <= Base
44
+ default_bindings.merge(superclass.bindings) { |key, old, new| old + new }
45
+ else
46
+ default_bindings
47
+ end
48
+ end
49
+
50
+ # Bindings for this factory class.
51
+ #
52
+ # @return [Hash]
53
+ #
54
+ def default_bindings
55
+ @default_bindings ||= {}
56
+ end
57
+ end
58
+
59
+ attr_reader :browser_name
60
+
61
+ bind(:browser_timeout) { |value, options| options[:http_client].timeout = value.to_i }
62
+
63
+ # Initializes new factory instances.
64
+ #
65
+ # @param browser_name [Symbol]
66
+ #
67
+ def initialize(browser_name)
68
+ @browser_name = browser_name
69
+ @bindings = {}
70
+ @browser_cache = {}
71
+ end
72
+
73
+ # Returns a unique set of all the binding keys.
74
+ #
75
+ # @return [Array]
76
+ #
77
+ def all_binding_keys
78
+ bindings.keys.flatten.uniq
79
+ end
80
+
81
+ # Binds environmental configuration to any browser created by this
82
+ # factory instance.
83
+ #
84
+ # @example Override the user agent according :browser_user_agent
85
+ # factory = BrowserFactory.new(:firefox)
86
+ # factory.bind(:browser_user_agent) do |agent, options|
87
+ # options[:desired_capabilities][:firefox_profile]["general.useragent.override"] = agent
88
+ # end
89
+ #
90
+ # @example Annotate the session with our build information
91
+ # factory.bind(:job_name, :build_number) do |job, build, options|
92
+ # options[:desired_capabilities][:name] = "#{job} (#{build})"
93
+ # end
94
+ #
95
+ # @example Bindings aren't invoked unless all given options are configured
96
+ # factory.bind(:foo, :bar) do |foo, bar, options|
97
+ # # this never happens!
98
+ # options[:desired_capabilities][:name] = "#{foo} #{bar}"
99
+ # end
100
+ # factory.browser_for(Environment.new(foo: "x"))
101
+ #
102
+ # @param names [Symbol] One or more option names.
103
+ #
104
+ # @yield [values, browser_options] A block that binds the configuration to
105
+ # the browser options.
106
+ #
107
+ def bind(*names, &blk)
108
+ key = names.length == 1 ? names.first : names
109
+ @bindings[key] ||= []
110
+ @bindings[key] << (blk || proc {})
111
+ end
112
+
113
+ # Effective bindings for this factory, those defined at the class level
114
+ # and those defined for this instance.
115
+ #
116
+ # @return [Hash]
117
+ #
118
+ def bindings
119
+ self.class.bindings.merge(@bindings) { |key, old, new| old + new }
120
+ end
121
+
122
+ # Instantiate a browser using the given environmental configuration.
123
+ # Browsers are cached and reused as long as the configuration is the
124
+ # same.
125
+ #
126
+ # @param config [Hash] Browser configuration.
127
+ #
128
+ # @return [Watir::Browser]
129
+ #
130
+ # @see #new_browser_for
131
+ #
132
+ def browser_for(config)
133
+ @browser_cache[config] ||= new_browser_for(config)
134
+ end
135
+
136
+ # Browser options for the given configuration.
137
+ #
138
+ # @param config [Hash]
139
+ #
140
+ # @return [Hash]
141
+ #
142
+ def browser_options(config)
143
+ options = default_browser_options.tap do |default_options|
144
+ bindings.each do |(names, bindings_for_option)|
145
+ bindings_for_option.each do |binding|
146
+ values = config.values_at(*Array(names))
147
+
148
+ unless values.any? { |value| value.nil? || value.to_s.empty? }
149
+ binding.call(*values, default_options)
150
+ end
151
+ end
152
+ end
153
+ end
154
+
155
+ finalize_options!(options)
156
+
157
+ options
158
+ end
159
+
160
+ # Iterate over each browser created by this factory.
161
+ #
162
+ # @yield [browser]
163
+ #
164
+ def each(&blk)
165
+ @browser_cache.values.each(&blk)
166
+ end
167
+
168
+ # A new browser for the given environmental configuration.
169
+ #
170
+ # @param config [Hash] Browser configuration.
171
+ #
172
+ # @return [Watir::Browser]
173
+ #
174
+ # @see #browser_for
175
+ #
176
+ def new_browser_for(config)
177
+ new_browser(browser_options(config))
178
+ end
179
+
180
+ # Executes additional teardown tasks.
181
+ #
182
+ # @param env [Environment] Environment.
183
+ # @param status [Symbol] Status of the executed scenario.
184
+ #
185
+ def teardown(env, status)
186
+ # abstract
187
+ end
188
+
189
+ protected
190
+
191
+ def default_browser_options
192
+ { http_client: http_client, desired_capabilities: desired_capabilities }
193
+ end
194
+
195
+ def desired_capabilities
196
+ Selenium::WebDriver::Remote::Capabilities.send(browser_name)
197
+ end
198
+
199
+ def finalize_options!(options)
200
+ # abstract
201
+ end
202
+
203
+ def http_client
204
+ Selenium::WebDriver::Remote::Http::Default.new
205
+ end
206
+
207
+ def new_browser(options)
208
+ Watir::Browser.new(options[:desired_capabilities].browser_name, options)
209
+ end
210
+ end
211
+ end
212
+ end