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
@@ -1,3 +1,4 @@
1
+ require "page-object"
1
2
  require "mediawiki_api"
2
3
 
3
4
  class APIPage
@@ -1,19 +1,9 @@
1
- =begin
2
- This file is subject to the license terms in the LICENSE file found in the
3
- mediawiki_selenium top-level directory and at
4
- https://git.wikimedia.org/blob/mediawiki%2Fselenium/HEAD/LICENSE. No part of
5
- mediawiki_selenium, including this file, may be copied, modified, propagated, or
6
- distributed except according to the terms contained in the LICENSE file.
7
- Copyright 2013 by the Mediawiki developers. See the CREDITS file in the
8
- mediawiki_selenium top-level directory and at
9
- https://git.wikimedia.org/blob/mediawiki%2Fselenium/HEAD/CREDITS.
10
- =end
1
+ require "page-object"
11
2
 
12
3
  class LoginPage
13
4
  include PageObject
14
5
 
15
- include URL
16
- page_url URL.url("Special:UserLogin")
6
+ page_url "Special:UserLogin"
17
7
 
18
8
  div(:feedback, class: "errorbox")
19
9
  button(:login, id: "wpLoginAttempt")
@@ -30,6 +20,7 @@ class LoginPage
30
20
  def login_with(username, password, wait_for_logout_element = true)
31
21
  self.username_element.when_present.send_keys(username)
32
22
  self.password_element.when_present.send_keys(password)
23
+ login_element.fire_event("onfocus")
33
24
  login_element.when_present.click
34
25
  logout_element.when_present(10) if wait_for_logout_element
35
26
  end
@@ -1,17 +1,7 @@
1
- =begin
2
- This file is subject to the license terms in the LICENSE file found in the
3
- mediawiki_selenium top-level directory and at
4
- https://git.wikimedia.org/blob/mediawiki%2Fselenium/HEAD/LICENSE. No part of
5
- mediawiki_selenium, including this file, may be copied, modified, propagated, or
6
- distributed except according to the terms contained in the LICENSE file.
7
- Copyright 2013 by the Mediawiki developers. See the CREDITS file in the
8
- mediawiki_selenium top-level directory and at
9
- https://git.wikimedia.org/blob/mediawiki%2Fselenium/HEAD/CREDITS.
10
- =end
1
+ require "page-object"
11
2
 
12
3
  class RandomPage
13
4
  include PageObject
14
5
 
15
- include URL
16
- page_url URL.url("Special:Random")
6
+ page_url "Special:Random"
17
7
  end
@@ -1,18 +1,9 @@
1
- =begin
2
- This file is subject to the license terms in the LICENSE file found in the
3
- mediawiki_selenium top-level directory and at
4
- https://git.wikimedia.org/blob/mediawiki%2Fselenium/HEAD/LICENSE. No part of
5
- mediawiki_selenium, including this file, may be copied, modified, propagated, or
6
- distributed except according to the terms contained in the LICENSE file.
7
- Copyright 2013 by the Mediawiki developers. See the CREDITS file in the
8
- mediawiki_selenium top-level directory and at
9
- https://git.wikimedia.org/blob/mediawiki%2Fselenium/HEAD/CREDITS.
10
- =end
1
+ require "page-object"
11
2
 
12
3
  class ResetPreferencesPage
13
4
  include PageObject
14
- include URL
15
- page_url URL.url("Special:Preferences/reset")
5
+
6
+ page_url "Special:Preferences/reset"
16
7
 
17
8
  button(:submit, class: "mw-htmlform-submit")
18
9
  end
@@ -10,5 +10,5 @@ https://git.wikimedia.org/blob/mediawiki%2Fselenium/HEAD/CREDITS.
10
10
  =end
11
11
 
12
12
  module MediawikiSelenium
13
- VERSION = "0.4.3"
13
+ VERSION = "1.0.0.pre.1"
14
14
  end
@@ -14,6 +14,9 @@ makes it easy to update the shared code.}
14
14
  spec.homepage = "https://gerrit.wikimedia.org/r/#/admin/projects/mediawiki/selenium"
15
15
  spec.license = "GPL-2"
16
16
 
17
+ spec.bindir = "bin"
18
+ spec.executables << 'mediawiki-selenium-init'
19
+
17
20
  spec.files = `git ls-files`.split($/)
18
21
  spec.require_paths = ["lib"]
19
22
 
@@ -25,9 +28,12 @@ makes it easy to update the shared code.}
25
28
  spec.add_runtime_dependency "rest-client", "~> 1.6", ">= 1.6.7"
26
29
  spec.add_runtime_dependency "rspec-expectations", "~> 2.14", ">= 2.14.4"
27
30
  spec.add_runtime_dependency "syntax", "~> 1.2", ">= 1.2.0"
31
+ spec.add_runtime_dependency "thor", "~> 0.19", ">= 0.19.1"
28
32
 
29
- spec.add_development_dependency "redcarpet"
33
+ spec.add_development_dependency "bundler", "~> 1.6", ">= 1.6.3"
34
+ spec.add_development_dependency "yard", "~> 0.8", ">= 0.8.7.4"
35
+ spec.add_development_dependency "redcarpet", "~> 3.2", ">= 3.2.0"
36
+ spec.add_development_dependency "rubocop", "~> 0.26", ">= 0.26.1"
30
37
  spec.add_development_dependency "rspec-core", "~> 2.14", ">= 2.14.4"
31
- spec.add_development_dependency "rubocop", "~> 0.26.1"
32
- spec.add_development_dependency "yard"
38
+ spec.add_development_dependency "rspec-mocks", "~> 2.14", ">= 2.14.4"
33
39
  end
@@ -0,0 +1,84 @@
1
+ require "spec_helper"
2
+
3
+ module MediawikiSelenium
4
+ describe ApiHelper do
5
+ let(:env) { Environment.new(config).extend(ApiHelper) }
6
+
7
+ let(:config) do
8
+ {
9
+ mediawiki_url: wiki_url,
10
+ mediawiki_url_b: alternative_wiki_url,
11
+ mediawiki_api_url: api_url,
12
+ mediawiki_api_url_b: alternative_api_url,
13
+ mediawiki_user: "mw user",
14
+ mediawiki_password: "mw password"
15
+ }
16
+ end
17
+
18
+ describe "#api" do
19
+ subject { env.api }
20
+
21
+ let(:wiki_url) { "http://an.example/wiki/" }
22
+ let(:api_url) { "http://an.example/api" }
23
+ let(:alternative_wiki_url) { "http://another.example/wiki/" }
24
+ let(:alternative_api_url) { "" }
25
+
26
+ let(:client) { double(MediawikiApi::Client) }
27
+
28
+ before do
29
+ expect(MediawikiApi::Client).to receive(:new).with(api_url).and_return(client)
30
+ expect(client).to receive(:log_in).with("mw user", "mw password")
31
+ end
32
+
33
+ context "called for the first time" do
34
+ it "returns a new client" do
35
+ expect(subject).to be(client)
36
+ end
37
+ end
38
+
39
+ context "called subsequently" do
40
+ before do
41
+ env.api
42
+ end
43
+
44
+ it "returns a cached client" do
45
+ expect(subject).to be(client)
46
+ end
47
+ end
48
+ end
49
+
50
+ describe "#on_wiki" do
51
+ let(:wiki_url) { "http://an.example/wiki/" }
52
+ let(:api_url) { "http://an.example/api" }
53
+ let(:alternative_wiki_url) { "http://another.example/wiki/" }
54
+
55
+ context "and the given alternative API URL is configured" do
56
+ let(:alternative_api_url) { "http://another.example/api" }
57
+
58
+ it "executes in the new environment using the alternative wiki and API URL" do
59
+ expect { |block| env.on_wiki(:b, &block) }.
60
+ to yield_with_args(alternative_wiki_url, alternative_api_url)
61
+
62
+ env.on_wiki(:b) do
63
+ expect(env[:mediawiki_url]).to eq(alternative_wiki_url)
64
+ expect(env[:mediawiki_api_url]).to eq(alternative_api_url)
65
+ end
66
+ end
67
+ end
68
+
69
+ context "and no explicit API URL is configured for the wiki" do
70
+ let(:alternative_api_url) { "" }
71
+
72
+ it "constructs one at /w/api.php relative to the wiki URL" do
73
+ expect { |block| env.on_wiki(:b, &block) }.
74
+ to yield_with_args(alternative_wiki_url, "http://another.example/w/api.php")
75
+
76
+ env.on_wiki(:b) do
77
+ expect(env[:mediawiki_url]).to eq(alternative_wiki_url)
78
+ expect(env[:mediawiki_api_url]).to eq("http://another.example/w/api.php")
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,211 @@
1
+ require "spec_helper"
2
+
3
+ module MediawikiSelenium::BrowserFactory
4
+ describe Base do
5
+ let(:factory_class) { Class.new(Base) }
6
+ let(:factory) { factory_class.new(browser_name) }
7
+ let(:browser_name) { :lynx }
8
+
9
+ describe ".bind" do
10
+ subject { factory_class.bind(option_name, &block) }
11
+
12
+ let(:option_name) { :foo }
13
+ let(:block) { proc { } }
14
+
15
+ it "adds a new default binding for the given option" do
16
+ subject
17
+ expect(factory_class.default_bindings).to include(option_name)
18
+ expect(factory_class.default_bindings[option_name]).to include(block)
19
+ end
20
+
21
+ context "given no block" do
22
+ subject { factory_class.bind(option_name) }
23
+
24
+ it "raises an ArgumentError" do
25
+ expect { subject }.to raise_error(ArgumentError)
26
+ end
27
+ end
28
+ end
29
+
30
+ describe ".bindings" do
31
+ subject { factory_class.bindings }
32
+
33
+ before do
34
+ factory_class.bind(:foo) {}
35
+ end
36
+
37
+ it "includes the base class's default bindings" do
38
+ expect(subject).to include(Base.default_bindings)
39
+ end
40
+
41
+ it "includes its own bindings" do
42
+ expect(subject).to include(factory_class.default_bindings)
43
+ end
44
+ end
45
+
46
+ describe ".default_bindings" do
47
+ subject { factory_class.default_bindings }
48
+
49
+ it { is_expected.to be_a(Hash) }
50
+
51
+ context "before any bindings are defined" do
52
+ it { is_expected.to be_empty }
53
+ end
54
+
55
+ context "when bindings are defined" do
56
+ before do
57
+ factory_class.bind(:foo) {}
58
+ factory_class.bind(:bar) {}
59
+ factory_class.bind(:bar) {}
60
+ end
61
+
62
+ it "includes all defined bindings" do
63
+ expect(subject).to include(:foo, :bar)
64
+ end
65
+
66
+ it "includes all bindings for the same option name" do
67
+ expect(subject[:bar].length).to be(2)
68
+ end
69
+ end
70
+ end
71
+
72
+ describe "#bind" do
73
+ subject { factory.bind(option_name, &block) }
74
+ before { subject }
75
+
76
+ let(:option_name) { :foo }
77
+ let(:block) { proc { } }
78
+
79
+ it "adds a new binding for the given option" do
80
+ expect(factory.bindings).to include(option_name)
81
+ expect(factory.bindings[option_name]).to include(block)
82
+ end
83
+
84
+ context "given no block" do
85
+ subject { factory.bind(option_name) }
86
+
87
+ it "will default to an empty block" do
88
+ expect(factory.bindings[option_name]).not_to include(nil)
89
+ end
90
+ end
91
+ end
92
+
93
+ describe "#bindings" do
94
+ subject { factory.bindings }
95
+
96
+ before do
97
+ factory_class.bind(:foo) {}
98
+ factory.bind(:bar)
99
+ end
100
+
101
+ it "includes the class-level bindings" do
102
+ expect(subject).to include(factory_class.bindings)
103
+ end
104
+
105
+ it "includes its own bindings" do
106
+ expect(subject).to include(:bar)
107
+ end
108
+ end
109
+
110
+ describe "#browser_for" do
111
+ subject { factory.browser_for(config) }
112
+
113
+ let(:config) { { foo: "x" } }
114
+
115
+ let(:watir_browser) { double(Watir::Browser) }
116
+ let(:capabilities) { double(Selenium::WebDriver::Remote::Capabilities) }
117
+
118
+ before do
119
+ expect(Selenium::WebDriver::Remote::Capabilities).to receive(browser_name).
120
+ at_least(:once).and_return(capabilities)
121
+ expect(capabilities).to receive(:browser_name).
122
+ at_least(:once).and_return(browser_name)
123
+ end
124
+
125
+ it "creates a new Watir::Browser" do
126
+ expect(Watir::Browser).to receive(:new).once.and_return(watir_browser)
127
+ expect(subject).to be(watir_browser)
128
+ end
129
+
130
+ context "called more than once" do
131
+ let(:config1) { config }
132
+
133
+ context "with the same configuration" do
134
+ let(:config2) { config }
135
+
136
+ it "returns a cached browser" do
137
+ expect(Watir::Browser).to receive(:new).once.and_return(watir_browser)
138
+ expect(factory.browser_for(config1)).to be(factory.browser_for(config2))
139
+ end
140
+ end
141
+
142
+ context "with different configuration" do
143
+ let(:config2) { { foo: "y" } }
144
+
145
+ it "returns two distinct browsers" do
146
+ expect(Watir::Browser).to receive(:new).twice
147
+
148
+ factory.browser_for(config1)
149
+ factory.browser_for(config2)
150
+ end
151
+ end
152
+ end
153
+ end
154
+
155
+ describe "#browser_options" do
156
+ subject { factory.browser_options(config) }
157
+
158
+ let(:config) { {} }
159
+
160
+ let(:capabilities) { double(Selenium::WebDriver::Remote::Capabilities) }
161
+ let(:client) { double(Selenium::WebDriver::Remote::Http::Default) }
162
+ let(:options) { { desired_capabilities: capabilities, http_client: client } }
163
+
164
+ before do
165
+ expect(Selenium::WebDriver::Remote::Capabilities).to receive(browser_name).
166
+ at_least(:once).and_return(capabilities)
167
+ expect(Selenium::WebDriver::Remote::Http::Default).to receive(:new).
168
+ and_return(client)
169
+ end
170
+
171
+ it { is_expected.to be_a(Hash) }
172
+ it { is_expected.to include(desired_capabilities: capabilities, http_client: client) }
173
+
174
+ context "with a binding" do
175
+ context "and corresponding configuration" do
176
+ let(:config) { { foo: "x" } }
177
+
178
+ it "invokes the binding with the configured value" do
179
+ expect { |block| factory.bind(:foo, &block) && subject }.to yield_with_args("x", options)
180
+ end
181
+ end
182
+
183
+ context "but no configuration" do
184
+ let(:config) { {} }
185
+
186
+ it "never invokes the binding" do
187
+ expect { |block| factory.bind(:foo, &block) && subject }.to_not yield_control
188
+ end
189
+ end
190
+ end
191
+
192
+ context "with a multi-option binding" do
193
+ context "and complete configuration for all options" do
194
+ let(:config) { { foo: "x", bar: "y" } }
195
+
196
+ it "invokes the binding with the configured values" do
197
+ expect { |block| factory.bind(:foo, :bar, &block) && subject }.to yield_with_args("x", "y", options)
198
+ end
199
+ end
200
+
201
+ context "but incomplete configuration for all options" do
202
+ let(:config) { { foo: "x" } }
203
+
204
+ it "never invokes the binding" do
205
+ expect { |block| factory.bind(:foo, :bar, &block) && subject }.to_not yield_control
206
+ end
207
+ end
208
+ end
209
+ end
210
+ end
211
+ end
@@ -0,0 +1,36 @@
1
+ require "spec_helper"
2
+
3
+ module MediawikiSelenium::BrowserFactory
4
+ describe Chrome do
5
+ let(:factory_class) { Chrome }
6
+ let(:factory) { factory_class.new(:chrome) }
7
+
8
+ describe ".default_bindings" do
9
+ subject { factory_class.default_bindings }
10
+
11
+ it { is_expected.to include(:browser_language) }
12
+ it { is_expected.not_to include(:browser_timeout) }
13
+ it { is_expected.to include(:browser_user_agent) }
14
+ end
15
+
16
+ describe "#browser_options" do
17
+ subject { factory.browser_options(config) }
18
+
19
+ context "given a custom browser_language" do
20
+ let(:config) { { browser_language: "eo" } }
21
+
22
+ it "sets the intl.accept_languages preference to the given language" do
23
+ expect(subject[:prefs]).to include("intl.accept_languages" => "eo")
24
+ end
25
+ end
26
+
27
+ context "given a custom browser_user_agent" do
28
+ let(:config) { { browser_user_agent: "FooBot" } }
29
+
30
+ it "includes it as --user-agent in the chrome arguments" do
31
+ expect(subject[:args]).to include("--user-agent=FooBot")
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,60 @@
1
+ require "spec_helper"
2
+
3
+ module MediawikiSelenium::BrowserFactory
4
+ describe Firefox do
5
+ let(:factory_class) { Firefox }
6
+ let(:factory) { factory_class.new(:firefox) }
7
+
8
+ describe ".default_bindings" do
9
+ subject { factory_class.default_bindings }
10
+
11
+ it { is_expected.to include(:browser_language) }
12
+ it { is_expected.to include(:browser_timeout) }
13
+ it { is_expected.to include(:browser_user_agent) }
14
+ end
15
+
16
+ describe "#browser_options" do
17
+ subject { factory.browser_options(config) }
18
+
19
+ let(:profile) { double(Selenium::WebDriver::Firefox::Profile) }
20
+
21
+ before do
22
+ expect(Selenium::WebDriver::Firefox::Profile).to receive(:new).and_return(profile)
23
+ end
24
+
25
+ context "given a custom browser_timeout" do
26
+ let(:config) { { browser_timeout: "30" } }
27
+
28
+ it "sets dom.max_script_run_time to the given number" do
29
+ expect(profile).to receive(:[]=).with("dom.max_script_run_time", 30)
30
+ allow(profile).to receive(:[]=)
31
+ subject
32
+ end
33
+
34
+ it "sets dom.max_chrome_script_run_time to the given number" do
35
+ expect(profile).to receive(:[]=).with("dom.max_chrome_script_run_time", 30)
36
+ allow(profile).to receive(:[]=)
37
+ subject
38
+ end
39
+ end
40
+
41
+ context "given a custom browser_language" do
42
+ let(:config) { { browser_language: "eo" } }
43
+
44
+ it "sets intl.accept_languages to the given language" do
45
+ expect(profile).to receive(:[]=).with("intl.accept_languages", "eo")
46
+ subject
47
+ end
48
+ end
49
+
50
+ context "given a custom browser_user_agent" do
51
+ let(:config) { { browser_user_agent: "FooBot" } }
52
+
53
+ it "sets general.useragent.override to the given string" do
54
+ expect(profile).to receive(:[]=).with("general.useragent.override", "FooBot")
55
+ subject
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end