mediawiki_selenium 0.4.3 → 1.0.0.pre.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.
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