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
@@ -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