lapis_lazuli 0.6.3 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +2 -2
- data/lib/lapis_lazuli/browser.rb +200 -108
- data/lib/lapis_lazuli/browser/error.rb +5 -5
- data/lib/lapis_lazuli/browser/find.rb +5 -5
- data/lib/lapis_lazuli/browser/interaction.rb +1 -1
- data/lib/lapis_lazuli/browser/remote.rb +140 -0
- data/lib/lapis_lazuli/browser/screenshots.rb +15 -16
- data/lib/lapis_lazuli/browser/wait.rb +2 -2
- data/lib/lapis_lazuli/runtime.rb +15 -1
- data/lib/lapis_lazuli/version.rb +1 -1
- data/lib/lapis_lazuli/world/browser.rb +3 -2
- data/lib/lapis_lazuli/world/config.rb +92 -7
- data/lib/lapis_lazuli/world/hooks.rb +14 -5
- data/lib/lapis_lazuli/world/proxy.rb +3 -3
- data/test/Gemfile +1 -2
- data/test/features/config.feature +14 -0
- data/test/features/step_definitions/interaction_steps.rb +6 -3
- data/test/features/step_definitions/validation_steps.rb +19 -2
- data/test/features/support/env.rb +0 -3
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c231db7a9cb304150e2ca2eccf956be02c367482
|
4
|
+
data.tar.gz: 3eb2d929510b34cfd70f2e944eb2590b6059f6e6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cede96cad3beb40c9a3f331c47cc930906ccd707283b393aaddccd4d713120233b3e01c4b3d7f15dbf1f117fde4b1c9d3593f1ae43d8189b2d6316345d2e4b16
|
7
|
+
data.tar.gz: d941873ef4a11ef98524f994c931b0acea5348dc261b6392dddabdff7212b1d678b91a311b18fbe1d21cd58c986100e386e88de270299093e6b0c580b28a9915
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
lapis_lazuli (0.
|
4
|
+
lapis_lazuli (0.7.0)
|
5
5
|
facets (~> 2.9)
|
6
6
|
faraday (~> 0.9.0)
|
7
7
|
faraday_middleware (~> 0.9.1)
|
@@ -31,7 +31,7 @@ GEM
|
|
31
31
|
multi_json (~> 1.0)
|
32
32
|
simplecov-html (~> 0.9.0)
|
33
33
|
simplecov-html (0.9.0)
|
34
|
-
teelogger (0.4.
|
34
|
+
teelogger (0.4.1)
|
35
35
|
thor (0.19.1)
|
36
36
|
|
37
37
|
PLATFORMS
|
data/lib/lapis_lazuli/browser.rb
CHANGED
@@ -18,6 +18,7 @@ require 'lapis_lazuli/browser/find'
|
|
18
18
|
require "lapis_lazuli/browser/wait"
|
19
19
|
require "lapis_lazuli/browser/screenshots"
|
20
20
|
require "lapis_lazuli/browser/interaction"
|
21
|
+
require "lapis_lazuli/browser/remote"
|
21
22
|
require 'lapis_lazuli/generic/xpath'
|
22
23
|
require 'lapis_lazuli/generic/assertions'
|
23
24
|
|
@@ -26,7 +27,7 @@ module LapisLazuli
|
|
26
27
|
# Extension to the Watir browser
|
27
28
|
#
|
28
29
|
# This class handles initialization, for the most part. BrowserModules
|
29
|
-
# included here can rely on
|
30
|
+
# included here can rely on world being set to the current cucumber world
|
30
31
|
# object, and for some WorldModules to exist in it (see assertions in
|
31
32
|
# constructor).
|
32
33
|
class Browser
|
@@ -37,29 +38,54 @@ module LapisLazuli
|
|
37
38
|
include LapisLazuli::BrowserModule::Wait
|
38
39
|
include LapisLazuli::BrowserModule::Screenshots
|
39
40
|
include LapisLazuli::BrowserModule::Interaction
|
41
|
+
include LapisLazuli::BrowserModule::Remote
|
40
42
|
include LapisLazuli::GenericModule::XPath
|
41
|
-
include LapisLazuli::GenericModule::Assertions
|
42
43
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
44
|
+
@@world=nil
|
45
|
+
@@cached_browser_options={}
|
46
|
+
@@browsers=[]
|
47
|
+
class << self
|
48
|
+
include LapisLazuli::GenericModule::Assertions
|
49
|
+
|
50
|
+
def browsers
|
51
|
+
return @@browsers
|
52
|
+
end
|
53
|
+
|
54
|
+
def add_browser(b)
|
55
|
+
# Add destructor for all browsers
|
56
|
+
Runtime.instance.set_if(self, :browsers, LapisLazuli::Browser.method(:close_all))
|
57
|
+
@@browsers.push(b)
|
58
|
+
end
|
59
|
+
|
60
|
+
def remove_browser(b)
|
61
|
+
@@browsers.delete(b)
|
62
|
+
end
|
63
|
+
|
64
|
+
def set_world(w)
|
65
|
+
@@world = w
|
66
|
+
end
|
47
67
|
|
68
|
+
def check_world?
|
69
|
+
assert @@world.respond_to?(:config), "Need to include LapisLazuli::WorldModule::Config in your cucumber world."
|
70
|
+
assert @@world.respond_to?(:log), "Need to include LapisLazuli::WorldModule::Logging in your cucumber world."
|
71
|
+
assert @@world.respond_to?(:error), "Need to include LapisLazuli::WorldModule::Error in your cucumber world."
|
72
|
+
assert @@world.respond_to?(:has_proxy?), "Need to include LapisLazuli::WorldModule::Proxy in your cucumber world."
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
@browser
|
48
77
|
@browser_name
|
49
|
-
|
78
|
+
@browser_wanted
|
79
|
+
@optional_data
|
80
|
+
|
81
|
+
attr_reader :browser_name, :browser_wanted, :optional_data
|
50
82
|
|
51
|
-
def initialize(
|
83
|
+
def initialize(*args)
|
52
84
|
# The class only works with some modules loaded; they're loaded by the
|
53
85
|
# Browser module, but we can't be sure that's been used.
|
54
|
-
|
55
|
-
assert world.respond_to?(:log), "Need to include LapisLazuli::WorldModule::Logging in your cucumber world."
|
56
|
-
assert world.respond_to?(:error), "Need to include LapisLazuli::WorldModule::Error in your cucumber world."
|
57
|
-
assert world.respond_to?(:has_proxy?), "Need to include LapisLazuli::WorldModule::Proxy in your cucumber world."
|
86
|
+
LapisLazuli::Browser.check_world?
|
58
87
|
|
59
|
-
|
60
|
-
|
61
|
-
# Create a new browser with optional arguments
|
62
|
-
@browser = self.init(*args)
|
88
|
+
self.start(*args)
|
63
89
|
|
64
90
|
# Add registered world modules.
|
65
91
|
if not LapisLazuli::WorldModule::Browser.browser_modules.nil?
|
@@ -69,92 +95,23 @@ module LapisLazuli
|
|
69
95
|
end
|
70
96
|
end
|
71
97
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
elsif optional_data.nil?
|
80
|
-
optional_data = {}
|
81
|
-
else
|
82
|
-
# Duplicate the data as Webdriver modifies it
|
83
|
-
@cached_optional_data = optional_data.dup
|
84
|
-
end
|
85
|
-
|
86
|
-
# Do the same caching stuff for the browser
|
87
|
-
if no_browser_wanted and browser_wanted.nil? and @cached_browser_wanted
|
88
|
-
browser_wanted = @cached_browser_wanted
|
89
|
-
else
|
90
|
-
@cached_browser_wanted = browser_wanted
|
91
|
-
end
|
92
|
-
|
93
|
-
# Create the browser
|
94
|
-
self.create_internal(browser_wanted, optional_data)
|
98
|
+
# Support browser.dup to create a duplicate
|
99
|
+
def initialize_copy(source)
|
100
|
+
super
|
101
|
+
@optional_data = @optional_data.dup
|
102
|
+
@browser = create_driver(@browser_wanted, @optional_data)
|
103
|
+
# Add this browser to the list of all browsers
|
104
|
+
LapisLazuli::Browser.add_browser(self)
|
95
105
|
end
|
96
106
|
|
97
107
|
##
|
98
108
|
# Creates a new browser instance.
|
99
109
|
def create(*args)
|
100
|
-
return Browser.new(
|
110
|
+
return Browser.new(*args)
|
101
111
|
end
|
102
112
|
|
103
|
-
|
104
|
-
|
105
|
-
# Always cached the supplied arguments
|
106
|
-
def create_internal(browser_wanted=nil, optional_data=nil)
|
107
|
-
# No browser? Does the config have a browser? Default to firefox
|
108
|
-
if browser_wanted.nil?
|
109
|
-
browser_wanted = @world.env_or_config('browser', 'firefox')
|
110
|
-
end
|
111
|
-
|
112
|
-
# Select the correct browser
|
113
|
-
case browser_wanted.to_s.downcase
|
114
|
-
when 'chrome'
|
115
|
-
# Check Platform running script
|
116
|
-
browser = :chrome
|
117
|
-
when 'safari'
|
118
|
-
browser = :safari
|
119
|
-
when 'ie'
|
120
|
-
require 'rbconfig'
|
121
|
-
if (RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/)
|
122
|
-
browser = :ie
|
123
|
-
else
|
124
|
-
@world.error("You can't run IE tests on non-Windows machine")
|
125
|
-
end
|
126
|
-
when 'ios'
|
127
|
-
if RUBY_PLATFORM.downcase.include?("darwin")
|
128
|
-
browser = :iphone
|
129
|
-
else
|
130
|
-
@world.error("You can't run IOS tests on non-mac machine")
|
131
|
-
end
|
132
|
-
else
|
133
|
-
browser = :firefox
|
134
|
-
end
|
135
|
-
|
136
|
-
args = [browser]
|
137
|
-
@browser_name = browser.to_s
|
138
|
-
if not optional_data.nil? and not optional_data.empty?
|
139
|
-
@world.log.debug("Got optional data: #{optional_data}")
|
140
|
-
args.push(optional_data)
|
141
|
-
elsif @world.has_proxy?
|
142
|
-
# Create a session if needed
|
143
|
-
if !@world.proxy.has_session?
|
144
|
-
@world.proxy.create()
|
145
|
-
end
|
146
|
-
|
147
|
-
proxy_url = "#{@world.proxy.ip}:#{@world.proxy.port}"
|
148
|
-
if browser == :firefox
|
149
|
-
@world.log.debug("Configuring Firefox proxy: #{proxy_url}")
|
150
|
-
profile = Selenium::WebDriver::Firefox::Profile.new
|
151
|
-
profile.proxy = Selenium::WebDriver::Proxy.new :http => proxy_url, :ssl => proxy_url
|
152
|
-
args.push({:profile => profile})
|
153
|
-
end
|
154
|
-
end
|
155
|
-
|
156
|
-
browser_instance = Watir::Browser.new(*args)
|
157
|
-
return browser_instance
|
113
|
+
def world
|
114
|
+
@@world
|
158
115
|
end
|
159
116
|
|
160
117
|
##
|
@@ -165,23 +122,25 @@ module LapisLazuli
|
|
165
122
|
|
166
123
|
##
|
167
124
|
# Start the browser if it's not yet open.
|
168
|
-
def start
|
125
|
+
def start(*args)
|
169
126
|
if @browser.nil?
|
170
|
-
@browser =
|
127
|
+
@browser = init(*args)
|
128
|
+
# Add this browser to the list of all browsers
|
129
|
+
LapisLazuli::Browser.add_browser(self)
|
171
130
|
end
|
172
131
|
end
|
173
132
|
|
174
133
|
##
|
175
134
|
# Close and create a new browser
|
176
135
|
def restart
|
177
|
-
|
136
|
+
world.log.debug "Restarting browser"
|
178
137
|
@browser.close
|
179
138
|
self.start
|
180
139
|
end
|
181
140
|
|
182
141
|
##
|
183
142
|
# Closes the browser and updates LL so that it will open a new one if needed
|
184
|
-
def close(reason = nil)
|
143
|
+
def close(reason = nil, remove_from_list=true)
|
185
144
|
if not @browser.nil?
|
186
145
|
if not reason.nil?
|
187
146
|
reason = " after #{reason}"
|
@@ -189,8 +148,11 @@ module LapisLazuli
|
|
189
148
|
reason = ""
|
190
149
|
end
|
191
150
|
|
192
|
-
|
151
|
+
world.log.debug "Closing browser#{reason}: #{@browser}"
|
193
152
|
@browser.close
|
153
|
+
if remove_from_list
|
154
|
+
LapisLazuli::Browser.remove_browser(self)
|
155
|
+
end
|
194
156
|
@browser = nil
|
195
157
|
end
|
196
158
|
end
|
@@ -209,12 +171,12 @@ module LapisLazuli
|
|
209
171
|
# Default: feature
|
210
172
|
def close_after_scenario(scenario)
|
211
173
|
# Determine the config
|
212
|
-
close_browser_after =
|
174
|
+
close_browser_after = world.env_or_config("close_browser_after")
|
213
175
|
|
214
176
|
case close_browser_after
|
215
177
|
when "scenario"
|
216
178
|
# We always close it
|
217
|
-
|
179
|
+
LapisLazuli::Browser.close_all close_browser_after
|
218
180
|
when "never"
|
219
181
|
# Do nothing: party time, excellent!
|
220
182
|
when "end"
|
@@ -222,7 +184,7 @@ module LapisLazuli
|
|
222
184
|
else
|
223
185
|
if is_last_scenario?(scenario)
|
224
186
|
# Close it
|
225
|
-
|
187
|
+
LapisLazuli::Browser.close_all close_browser_after
|
226
188
|
end
|
227
189
|
end
|
228
190
|
end
|
@@ -246,13 +208,143 @@ module LapisLazuli
|
|
246
208
|
end
|
247
209
|
|
248
210
|
def destroy(world)
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
211
|
+
# Primary browser should also close other browsers
|
212
|
+
LapisLazuli::Browser.close_all("end")
|
213
|
+
end
|
214
|
+
|
215
|
+
def self.close_all(reason=nil)
|
216
|
+
# A running browser should exist and we are allowed to close it
|
217
|
+
if @@browsers.length != 0 and @@world.env_or_config("close_browser_after") != "never"
|
218
|
+
# Notify user
|
219
|
+
@@world.log.debug("Closing all browsers")
|
220
|
+
|
221
|
+
# Close each browser
|
222
|
+
@@browsers.each do |b|
|
223
|
+
begin
|
224
|
+
b.close reason, false
|
225
|
+
rescue Exception => err
|
226
|
+
# Provide some details
|
227
|
+
@@world.log.debug("Failed to close the browser, probably chrome: #{err.to_s}")
|
228
|
+
end
|
254
229
|
end
|
230
|
+
|
231
|
+
# Make sure the array is cleared
|
232
|
+
@@browsers = []
|
255
233
|
end
|
256
234
|
end
|
235
|
+
|
236
|
+
private
|
237
|
+
##
|
238
|
+
# The main browser window for testing
|
239
|
+
def init(browser_wanted=(no_browser_wanted=true;nil), optional_data=(no_optional_data=true;nil))
|
240
|
+
# Store the optional data so on restart of the browser it still has the
|
241
|
+
# correct configuration
|
242
|
+
if no_optional_data and optional_data.nil? and @@cached_browser_options.has_key?(:optional_data) and (browser_wanted.nil? or browser_wanted == @@cached_browser_options[:browser])
|
243
|
+
optional_data = @@cached_browser_options[:optional_data]
|
244
|
+
elsif optional_data.nil?
|
245
|
+
optional_data = {}
|
246
|
+
end
|
247
|
+
|
248
|
+
# Do the same caching stuff for the browser
|
249
|
+
if no_browser_wanted and browser_wanted.nil? and @@cached_browser_options.has_key?(:browser)
|
250
|
+
browser_wanted = @@cached_browser_options[:browser]
|
251
|
+
end
|
252
|
+
|
253
|
+
|
254
|
+
if !@@cached_browser_options.has_key? :browser
|
255
|
+
@@cached_browser_options[:browser] = browser_wanted
|
256
|
+
# Duplicate the data as Webdriver modifies it
|
257
|
+
@@cached_browser_options[:optional_data] = optional_data.dup
|
258
|
+
end
|
259
|
+
|
260
|
+
@browser_wanted = browser_wanted
|
261
|
+
@optional_data = optional_data
|
262
|
+
# Create the browser
|
263
|
+
create_driver(@browser_wanted, @optional_data)
|
264
|
+
end
|
265
|
+
|
266
|
+
##
|
267
|
+
# Create a new browser depending on settings
|
268
|
+
# Always cached the supplied arguments
|
269
|
+
def create_driver(browser_wanted=nil, optional_data=nil)
|
270
|
+
# No browser? Does the config have a browser? Default to firefox
|
271
|
+
if browser_wanted.nil?
|
272
|
+
browser_wanted = world.env_or_config('browser', 'firefox')
|
273
|
+
end
|
274
|
+
|
275
|
+
# Select the correct browser
|
276
|
+
case browser_wanted.to_s.downcase
|
277
|
+
when 'chrome'
|
278
|
+
# Check Platform running script
|
279
|
+
b = :chrome
|
280
|
+
when 'safari'
|
281
|
+
b = :safari
|
282
|
+
when 'ie'
|
283
|
+
require 'rbconfig'
|
284
|
+
if (RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/)
|
285
|
+
b = :ie
|
286
|
+
else
|
287
|
+
world.error("You can't run IE tests on non-Windows machine")
|
288
|
+
end
|
289
|
+
when 'ios'
|
290
|
+
if RUBY_PLATFORM.downcase.include?("darwin")
|
291
|
+
b = :iphone
|
292
|
+
else
|
293
|
+
world.error("You can't run IOS tests on non-mac machine")
|
294
|
+
end
|
295
|
+
when 'remote'
|
296
|
+
b = :remote
|
297
|
+
else
|
298
|
+
b = :firefox
|
299
|
+
end
|
300
|
+
|
301
|
+
args = [b]
|
302
|
+
@browser_name = b.to_s
|
303
|
+
if b == :remote
|
304
|
+
# Get the config
|
305
|
+
remote_config = world.env_or_config("remote", {})
|
306
|
+
|
307
|
+
# The settings we are going to use to create the browser
|
308
|
+
remote_settings = {}
|
309
|
+
|
310
|
+
# Add the config to the settings using downcase string keys
|
311
|
+
remote_config.each{|k,v| remote_settings[k.to_s.downcase] = v}
|
312
|
+
|
313
|
+
if optional_data.is_a? Hash
|
314
|
+
# Convert the optional data to downcase string keys
|
315
|
+
string_hash = Hash.new
|
316
|
+
optional_data.each{|k,v| string_hash[k.to_s.downcase] = v}
|
317
|
+
|
318
|
+
# Merge them with the settings
|
319
|
+
remote_settings.merge! string_hash
|
320
|
+
end
|
321
|
+
|
322
|
+
args.push(remote_browser_config(remote_settings))
|
323
|
+
elsif not optional_data.nil? and not optional_data.empty?
|
324
|
+
world.log.debug("Got optional data: #{optional_data}")
|
325
|
+
args.push(optional_data)
|
326
|
+
elsif world.has_proxy?
|
327
|
+
# Create a session if needed
|
328
|
+
if !world.proxy.has_session?
|
329
|
+
world.proxy.create()
|
330
|
+
end
|
331
|
+
|
332
|
+
proxy_url = "#{world.proxy.ip}:#{world.proxy.port}"
|
333
|
+
if b == :firefox
|
334
|
+
world.log.debug("Configuring Firefox proxy: #{proxy_url}")
|
335
|
+
profile = Selenium::WebDriver::Firefox::Profile.new
|
336
|
+
profile.proxy = Selenium::WebDriver::Proxy.new :http => proxy_url, :ssl => proxy_url
|
337
|
+
args.push({:profile => profile})
|
338
|
+
end
|
339
|
+
end
|
340
|
+
|
341
|
+
begin
|
342
|
+
browser_instance = Watir::Browser.new(*args)
|
343
|
+
rescue Selenium::WebDriver::Error::UnknownError => err
|
344
|
+
raise err
|
345
|
+
end
|
346
|
+
return browser_instance
|
347
|
+
end
|
257
348
|
end
|
349
|
+
|
258
350
|
end
|
@@ -25,9 +25,9 @@ module BrowserModule
|
|
25
25
|
if errors.length > 0 or self.get_http_status.to_i > 299
|
26
26
|
errors.each do |error|
|
27
27
|
if error.is_a? Hash
|
28
|
-
|
28
|
+
world.log.debug("#{error["message"]} #{error["url"]} #{error["line"]} #{error["column"]}\n#{error["stack"]}")
|
29
29
|
else
|
30
|
-
|
30
|
+
world.log.debug("#{error}")
|
31
31
|
end
|
32
32
|
end
|
33
33
|
return true
|
@@ -42,12 +42,12 @@ module BrowserModule
|
|
42
42
|
def get_html_errors
|
43
43
|
result = []
|
44
44
|
# Need some error strings
|
45
|
-
if
|
45
|
+
if world.has_env_or_config?("error_strings")
|
46
46
|
begin
|
47
47
|
# Get the HTML of the page
|
48
48
|
page_text = @browser.html
|
49
49
|
# Try to find all errors
|
50
|
-
|
50
|
+
world.env_or_config("error_strings").each {|error|
|
51
51
|
if page_text.include? error
|
52
52
|
# Add to the result list
|
53
53
|
result.push error
|
@@ -55,7 +55,7 @@ module BrowserModule
|
|
55
55
|
}
|
56
56
|
rescue RuntimeError => err
|
57
57
|
# An error?
|
58
|
-
|
58
|
+
world.log.debug "Cannot read the html for page #{@browser.url}: #{err}"
|
59
59
|
end
|
60
60
|
end
|
61
61
|
# By default we don't have errors
|
@@ -157,7 +157,7 @@ module BrowserModule
|
|
157
157
|
else
|
158
158
|
options[:message] = optional_message("Invalid :pick value #{pick}.", options)
|
159
159
|
options[:groups] = ['find', 'pick']
|
160
|
-
|
160
|
+
world.error(options)
|
161
161
|
end
|
162
162
|
end
|
163
163
|
end
|
@@ -243,7 +243,7 @@ module BrowserModule
|
|
243
243
|
if not like_opts.has_key? :element
|
244
244
|
selector[:message] = optional_message("Like selector are missing the :element key.", selector)
|
245
245
|
selector[:groups] = ['find', 'selector']
|
246
|
-
|
246
|
+
world.error(selector)
|
247
247
|
end
|
248
248
|
end
|
249
249
|
|
@@ -443,7 +443,7 @@ module BrowserModule
|
|
443
443
|
res = []
|
444
444
|
lambdas.each do |func|
|
445
445
|
res = func.call
|
446
|
-
#
|
446
|
+
# world.log.debug("Got: #{res}")
|
447
447
|
if res.length > 0
|
448
448
|
break
|
449
449
|
end
|
@@ -453,7 +453,7 @@ module BrowserModule
|
|
453
453
|
else
|
454
454
|
options[:message] = optional_message("Invalid mode '#{options[:mode]}' provided to multi_find_all.", options)
|
455
455
|
options[:groups] = ['find', 'multi', 'mode']
|
456
|
-
|
456
|
+
world.error(options)
|
457
457
|
end
|
458
458
|
end
|
459
459
|
|
@@ -492,7 +492,7 @@ module BrowserModule
|
|
492
492
|
rescue RuntimeError => err
|
493
493
|
opts[:message] = optional_message(message, selectors)
|
494
494
|
opts[:exception] = err
|
495
|
-
|
495
|
+
world.error(opts)
|
496
496
|
end
|
497
497
|
end
|
498
498
|
end # module Find
|
@@ -0,0 +1,140 @@
|
|
1
|
+
#
|
2
|
+
# LapisLazuli
|
3
|
+
# https://github.com/spriteCloud/lapis-lazuli
|
4
|
+
#
|
5
|
+
# Copyright (c) 2013-2014 spriteCloud B.V. and other LapisLazuli contributors.
|
6
|
+
# All rights reserved.
|
7
|
+
#
|
8
|
+
|
9
|
+
module LapisLazuli
|
10
|
+
module BrowserModule
|
11
|
+
module Remote
|
12
|
+
# Convert settings to a valid remote driver argument
|
13
|
+
#
|
14
|
+
# Features:
|
15
|
+
# - settings hash can be case insensitive "URL","Url", "url"
|
16
|
+
# - caps.firefox_profile will be converted to a Selenium::WebDriver::Firefox::Profile
|
17
|
+
# - caps.proxy / caps.firefox_profile.proxy will be converted to a Selenium::WebDriver::Proxy
|
18
|
+
# - Hashes can have a String or a Symbol as key
|
19
|
+
#
|
20
|
+
# Example:
|
21
|
+
# args = remote_browser_config(
|
22
|
+
# {
|
23
|
+
# "url"=>"http://test.com",
|
24
|
+
# "user"=>"user21",
|
25
|
+
# "password"=>"jehwiufhewuf",
|
26
|
+
# "caps"=> {
|
27
|
+
# "browser_name"=>"firefox",
|
28
|
+
# "version"=>"37",
|
29
|
+
# "firefox_profile"=>{
|
30
|
+
# "plugin.state.flash"=>0,
|
31
|
+
# "secure_ssl"=>true,
|
32
|
+
# "proxy"=>{"http"=>"test.com:9000"}
|
33
|
+
# },
|
34
|
+
# "proxy"=>{:http=>"test.com:7000"},
|
35
|
+
# :css_selectors_enabled => true
|
36
|
+
# }
|
37
|
+
# })
|
38
|
+
# Watir::Browser.new :remote, args
|
39
|
+
def remote_browser_config(settings)
|
40
|
+
require "uri"
|
41
|
+
require "selenium-webdriver"
|
42
|
+
|
43
|
+
if !settings.is_a? Hash
|
44
|
+
world.error("Missing Remote Browser Settings")
|
45
|
+
end
|
46
|
+
|
47
|
+
# Fetch the URl
|
48
|
+
url = hash_get_case_insensitive(settings,"url")
|
49
|
+
|
50
|
+
# Test if its a valid URL
|
51
|
+
if not (url.to_s =~ /\A#{URI::regexp(["http", "https"])}\z/)
|
52
|
+
raise "Incorrect Remote URL: '#{url.to_s}'"
|
53
|
+
end
|
54
|
+
|
55
|
+
# Create URI object
|
56
|
+
uri = URI.parse(url)
|
57
|
+
|
58
|
+
# Add user if needed
|
59
|
+
user = hash_get_case_insensitive(settings,"user")
|
60
|
+
if !user.nil?
|
61
|
+
uri.user = user
|
62
|
+
end
|
63
|
+
|
64
|
+
# Add password if needed
|
65
|
+
password = hash_get_case_insensitive(settings,"password")
|
66
|
+
if !password.nil?
|
67
|
+
uri.password = password
|
68
|
+
end
|
69
|
+
|
70
|
+
# Create capabil
|
71
|
+
# Check ities
|
72
|
+
caps = Selenium::WebDriver::Remote::Capabilities.new
|
73
|
+
# Fetch the settings
|
74
|
+
caps_settings = hash_get_case_insensitive(settings,"caps")
|
75
|
+
|
76
|
+
# If we have settings
|
77
|
+
if !caps_settings.nil? and caps_settings.is_a? Hash
|
78
|
+
caps_settings.each do |key, val|
|
79
|
+
# Convert to proxy
|
80
|
+
if key.to_s == "proxy"
|
81
|
+
set_proxy(caps, val)
|
82
|
+
# Convert to FF profile
|
83
|
+
elsif key.to_s == "firefox_profile"
|
84
|
+
profile = Selenium::WebDriver::Firefox::Profile.new
|
85
|
+
# Set all the options
|
86
|
+
val.each do |fkey, fval|
|
87
|
+
# Convert to proxy
|
88
|
+
if fkey.to_s == "proxy"
|
89
|
+
set_proxy(profile,fval)
|
90
|
+
else
|
91
|
+
set_key(profile, fkey, fval)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
# Set the profile
|
95
|
+
caps[:firefox_profile] = profile
|
96
|
+
else
|
97
|
+
# Use set_key to assign the key
|
98
|
+
set_key(caps, key, val)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
world.log.debug("Using remote browser: #{url} (#{uri.user}) #{caps.to_json}")
|
104
|
+
|
105
|
+
return {
|
106
|
+
:url => uri.to_s,
|
107
|
+
:desired_capabilities => caps
|
108
|
+
}
|
109
|
+
end
|
110
|
+
|
111
|
+
private
|
112
|
+
def hash_get_case_insensitive(hash, key)
|
113
|
+
new_key = hash.keys.find {|e| e.to_s.casecmp(key.to_s) == 0}
|
114
|
+
if new_key.nil?
|
115
|
+
return nil
|
116
|
+
end
|
117
|
+
return hash[new_key]
|
118
|
+
end
|
119
|
+
|
120
|
+
# Sets a selenium proxy to the object
|
121
|
+
def set_proxy(object, hash)
|
122
|
+
proxy = Selenium::WebDriver::Proxy.new
|
123
|
+
hash.each do |key, val|
|
124
|
+
set_key(proxy, key, val)
|
125
|
+
end
|
126
|
+
object.proxy = proxy
|
127
|
+
end
|
128
|
+
|
129
|
+
# Uses function based on key or key itself to store the value in the object
|
130
|
+
def set_key(object, key, val)
|
131
|
+
if object.respond_to? "#{key}="
|
132
|
+
object.send("#{key}=", val)
|
133
|
+
else
|
134
|
+
object[key] = val
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
end # module Remote
|
139
|
+
end # module BrowserModule
|
140
|
+
end # module LapisLazuli
|
@@ -15,24 +15,23 @@ module BrowserModule
|
|
15
15
|
##
|
16
16
|
# Returns the name of the screenshot, if take_screenshot is called now.
|
17
17
|
def screenshot_name(suffix="")
|
18
|
-
dir =
|
18
|
+
dir = world.env_or_config("screenshot_dir")
|
19
19
|
|
20
20
|
# Generate the file name according to the new or old scheme.
|
21
|
-
|
22
|
-
case @world.env_or_config("screenshot_scheme")
|
21
|
+
case world.env_or_config("screenshot_scheme")
|
23
22
|
when "new"
|
24
|
-
# For non-cucumber cases: we don't have
|
25
|
-
if not
|
26
|
-
name =
|
23
|
+
# For non-cucumber cases: we don't have world.scenario.data
|
24
|
+
if not world.scenario.data.nil?
|
25
|
+
name = world.scenario.id
|
27
26
|
end
|
28
27
|
# FIXME random makes this non-repeatable, sadly
|
29
|
-
name = "#{
|
28
|
+
name = "#{world.scenario.time[:iso_short]}-#{@browser.object_id}-#{name}-#{Random.rand(10000).to_s}.png"
|
30
29
|
else # 'old' and default
|
31
|
-
# For non-cucumber cases: we don't have
|
32
|
-
if not
|
33
|
-
name =
|
30
|
+
# For non-cucumber cases: we don't have world.scenario.data
|
31
|
+
if not world.scenario.data.nil?
|
32
|
+
name = world.scenario.data.name.gsub(/^.*(\\|\/)/, '').gsub(/[^\w\.\-]/, '_').squeeze('_')
|
34
33
|
end
|
35
|
-
name =
|
34
|
+
name = world.time[:timestamp] + "_" + name + '.png'
|
36
35
|
end
|
37
36
|
|
38
37
|
# Full file location
|
@@ -46,7 +45,7 @@ module BrowserModule
|
|
46
45
|
# Using the name as defined at the start of every scenario
|
47
46
|
def take_screenshot(suffix="")
|
48
47
|
# If the target directory does not exist, create it.
|
49
|
-
dir =
|
48
|
+
dir = world.env_or_config("screenshot_dir")
|
50
49
|
begin
|
51
50
|
Dir.mkdir dir
|
52
51
|
rescue SystemCallError => ex
|
@@ -61,14 +60,14 @@ module BrowserModule
|
|
61
60
|
begin
|
62
61
|
# Save the screenshot
|
63
62
|
@browser.screenshot.save fileloc
|
64
|
-
|
63
|
+
world.log.debug "Screenshot saved: #{fileloc}"
|
65
64
|
|
66
65
|
# Try to store the screenshot name
|
67
|
-
if
|
68
|
-
|
66
|
+
if world.respond_to? :annotate
|
67
|
+
world.annotate :screenshot => fileloc
|
69
68
|
end
|
70
69
|
rescue RuntimeError => e
|
71
|
-
|
70
|
+
world.log.debug "Failed to save screenshot to '#{fileloc}'. Error message #{e.message}"
|
72
71
|
end
|
73
72
|
return fileloc
|
74
73
|
end
|
@@ -103,7 +103,7 @@ module BrowserModule
|
|
103
103
|
begin
|
104
104
|
res = Watir::Wait.send(condition, timeout, &find_proc)
|
105
105
|
rescue Watir::Wait::TimeoutError => e
|
106
|
-
|
106
|
+
world.log.debug("Caught timeout: #{e}")
|
107
107
|
err = e
|
108
108
|
end
|
109
109
|
|
@@ -112,7 +112,7 @@ module BrowserModule
|
|
112
112
|
# Error handling
|
113
113
|
if not err.nil? and filter_results.empty?
|
114
114
|
options[:exception] = err
|
115
|
-
|
115
|
+
world.error(options)
|
116
116
|
end
|
117
117
|
|
118
118
|
# Set if the underlying find function returns single results
|
data/lib/lapis_lazuli/runtime.rb
CHANGED
@@ -39,7 +39,10 @@ module LapisLazuli
|
|
39
39
|
return @objects[name]
|
40
40
|
end
|
41
41
|
|
42
|
-
obj =
|
42
|
+
obj = nil
|
43
|
+
if !block.nil?
|
44
|
+
obj = block.call
|
45
|
+
end
|
43
46
|
|
44
47
|
set(world, name, obj, destructor)
|
45
48
|
|
@@ -73,6 +76,17 @@ module LapisLazuli
|
|
73
76
|
return world.send(name).destroy(world)
|
74
77
|
end
|
75
78
|
|
79
|
+
# Try to run destroy on the object itself
|
80
|
+
obj = Runtime.get(name)
|
81
|
+
if obj.respond_to? :destroy
|
82
|
+
return obj.send(:destroy)
|
83
|
+
end
|
84
|
+
|
85
|
+
# If the object has stream/socket functions close ends the connection
|
86
|
+
if obj.respond_to? :close
|
87
|
+
return obj.send(:close)
|
88
|
+
end
|
89
|
+
|
76
90
|
# If all else fails, we have to log an error. We can't rely
|
77
91
|
# on log existing in world, though...
|
78
92
|
message = "No destructor available for #{name}."
|
data/lib/lapis_lazuli/version.rb
CHANGED
@@ -50,9 +50,10 @@ module WorldModule
|
|
50
50
|
def browser(*args)
|
51
51
|
b = Runtime.instance.set_if(self, :browser) do
|
52
52
|
# Add LL to the arguments for the browser
|
53
|
-
|
53
|
+
LapisLazuli::Browser.set_world(self)
|
54
|
+
|
54
55
|
# Create & return a new browser object
|
55
|
-
LapisLazuli::Browser.new(*
|
56
|
+
LapisLazuli::Browser.new(*args)
|
56
57
|
end
|
57
58
|
|
58
59
|
if not b.is_open?
|
@@ -238,7 +238,7 @@ module WorldModule
|
|
238
238
|
# Returns current environment
|
239
239
|
def current_env
|
240
240
|
init
|
241
|
-
|
241
|
+
|
242
242
|
return @env
|
243
243
|
end
|
244
244
|
|
@@ -255,11 +255,9 @@ module WorldModule
|
|
255
255
|
|
256
256
|
# Environment variables for known options override environment specific
|
257
257
|
# options, too
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
return ENV[var]
|
262
|
-
end
|
258
|
+
env_var = var_from_env(variable, default)
|
259
|
+
if env_var != default
|
260
|
+
return env_var
|
263
261
|
end
|
264
262
|
|
265
263
|
return self.config("#{@env}.#{variable}",default)
|
@@ -281,17 +279,104 @@ module WorldModule
|
|
281
279
|
# Make sure the configured configuration is loaded, if possible
|
282
280
|
init
|
283
281
|
|
282
|
+
# Environment variables for known options override environment specific
|
283
|
+
# options, too
|
284
|
+
env_var = var_from_env(variable, default)
|
285
|
+
if env_var != default
|
286
|
+
return env_var
|
287
|
+
end
|
288
|
+
|
284
289
|
if self.has_env?(variable)
|
285
290
|
return self.env(variable, default)
|
286
291
|
elsif self.has_config?(variable)
|
287
292
|
return self.config(variable, default)
|
288
293
|
else
|
289
|
-
return
|
294
|
+
return default
|
290
295
|
end
|
291
296
|
end
|
292
297
|
|
298
|
+
def var_from_env(var, default=nil)
|
299
|
+
# Simple solution for single depth variables like "browser"
|
300
|
+
if ENV.has_key? var
|
301
|
+
return ENV[var]
|
302
|
+
end
|
293
303
|
|
304
|
+
value = default
|
294
305
|
|
306
|
+
# Variables like:
|
307
|
+
# var_from_env("remote.url","http://test.test")
|
308
|
+
if var.is_a? String and
|
309
|
+
var.include? "." and
|
310
|
+
not default.is_a? Hash
|
311
|
+
|
312
|
+
# Env variables cannot contain a . replace them by _
|
313
|
+
key_wanted = var.gsub(".","__")
|
314
|
+
|
315
|
+
# Do a case insensitive compare
|
316
|
+
ENV.keys.each do |key|
|
317
|
+
if key.casecmp(key_wanted) == 0
|
318
|
+
value = ENV[key]
|
319
|
+
break
|
320
|
+
end
|
321
|
+
end
|
322
|
+
|
323
|
+
# Environment:
|
324
|
+
# REMOTE__USER=test
|
325
|
+
# REMOTE__PASS=test
|
326
|
+
# REMOTE__PROXY__HTTP=http://test.com
|
327
|
+
#
|
328
|
+
# Call:
|
329
|
+
# var_from_env("remote",{})
|
330
|
+
#
|
331
|
+
# Result:
|
332
|
+
# {"USER" => "test",
|
333
|
+
# "PASS" => "test",
|
334
|
+
# "proxy" => {"HTTP" => "http://test.con"}}
|
335
|
+
elsif default.is_a? Hash
|
336
|
+
# Env variables cannot contain a . replace them by _
|
337
|
+
key_wanted = var.gsub(".","__")
|
338
|
+
# Use a regular expression starting with the wanted key
|
339
|
+
rgx = Regexp.new("^#{key_wanted}","i")
|
340
|
+
|
341
|
+
result = {}
|
342
|
+
# For each key check if it matched the regexp
|
343
|
+
ENV.keys.each do |key|
|
344
|
+
if (key =~ rgx) == 0
|
345
|
+
tmp = result
|
346
|
+
# Remove start and split into parts
|
347
|
+
parts = key.sub(rgx, "").split("__")
|
348
|
+
# Remove empty start if needed
|
349
|
+
if parts[0].to_s.empty?
|
350
|
+
parts.shift
|
351
|
+
end
|
352
|
+
|
353
|
+
# For each part
|
354
|
+
parts.each_with_index do |part, index|
|
355
|
+
# Final part should store the value in the hash
|
356
|
+
if index == parts.length - 1
|
357
|
+
tmp[part] = ENV[key]
|
358
|
+
else
|
359
|
+
# Otherwise, downcase the partname
|
360
|
+
part.downcase!
|
361
|
+
# Set it to an object if needed
|
362
|
+
if !tmp.has_key? part
|
363
|
+
tmp[part] = {}
|
364
|
+
end
|
365
|
+
# Assign tmp to the new hash
|
366
|
+
tmp = tmp[part]
|
367
|
+
end
|
368
|
+
end
|
369
|
+
end
|
370
|
+
end
|
371
|
+
|
372
|
+
# If we have set keys in the result return it
|
373
|
+
if result.keys.length > 0
|
374
|
+
return result
|
375
|
+
end
|
376
|
+
end
|
377
|
+
|
378
|
+
return value
|
379
|
+
end
|
295
380
|
|
296
381
|
end # module Config
|
297
382
|
end # module WorldModule
|
@@ -77,18 +77,27 @@ module WorldModule
|
|
77
77
|
end
|
78
78
|
|
79
79
|
# Did we fail?
|
80
|
-
if respond_to? :scenario and respond_to? :browser and respond_to? :config
|
81
|
-
if (cuke_scenario.failed? or (scenario.check_browser_errors and browser.has_error?))
|
80
|
+
if respond_to? :scenario and respond_to? :has_browser? and respond_to? :browser and respond_to? :config
|
81
|
+
if has_browser? and (cuke_scenario.failed? or (scenario.check_browser_errors and browser.has_error?))
|
82
82
|
# Take a screenshot if needed
|
83
83
|
if has_env_or_config?('screenshot_on_failure')
|
84
|
-
|
84
|
+
if env_or_config("screenshot_scheme") == "new"
|
85
|
+
# Take screenshots on all active browsers
|
86
|
+
LapisLazuli::Browser.browsers.each do |b|
|
87
|
+
fileloc = b.take_screenshot()
|
88
|
+
end
|
89
|
+
else
|
90
|
+
browser.take_screenshot()
|
91
|
+
end
|
85
92
|
end
|
86
93
|
end
|
87
94
|
end
|
88
95
|
|
89
96
|
# Close browser if needed
|
90
|
-
if respond_to? :browser
|
91
|
-
|
97
|
+
if respond_to? :has_browser? and respond_to? :browser
|
98
|
+
if has_browser?
|
99
|
+
browser.close_after_scenario(cuke_scenario)
|
100
|
+
end
|
92
101
|
end
|
93
102
|
end
|
94
103
|
|
@@ -23,8 +23,8 @@ module WorldModule
|
|
23
23
|
##
|
24
24
|
# Checks if there is a proxy started
|
25
25
|
def has_proxy?
|
26
|
-
|
27
|
-
return !
|
26
|
+
proxy = Runtime.instance.get :proxy
|
27
|
+
return !proxy.nil?
|
28
28
|
end
|
29
29
|
|
30
30
|
##
|
@@ -46,7 +46,7 @@ module WorldModule
|
|
46
46
|
end
|
47
47
|
|
48
48
|
# Try to start the proxy
|
49
|
-
|
49
|
+
proxy = LapisLazuli::Proxy.new(proxy_ip, proxy_port, proxy_master)
|
50
50
|
|
51
51
|
log.debug("Found proxy: #{proxy_ip}:#{proxy_port}, spritecloud: #{proxy_master}")
|
52
52
|
rescue StandardError => err
|
data/test/Gemfile
CHANGED
@@ -36,8 +36,7 @@ gem 'cucumber', '>1.3.19'
|
|
36
36
|
# gem 'cucumber', '=1.3.19'
|
37
37
|
|
38
38
|
# Testing related
|
39
|
-
gem 'simplecov'
|
40
|
-
gem "codeclimate-test-reporter", group: :test, require: nil
|
39
|
+
gem 'simplecov'
|
41
40
|
|
42
41
|
# LapisLazul itself
|
43
42
|
gem 'lapis_lazuli', :github => 'spriteCloud/lapis-lazuli', :branch => 'master'
|
@@ -0,0 +1,14 @@
|
|
1
|
+
@config @p
|
2
|
+
Feature: config
|
3
|
+
When I want to test the Lapis Lazuli library
|
4
|
+
I want to run a webserver with some test files
|
5
|
+
And execute the each library function that handles configurations.
|
6
|
+
|
7
|
+
@config_01
|
8
|
+
Scenario: config_01 - Environment Hash
|
9
|
+
Given I set environment variable "configtest__user" to "username"
|
10
|
+
And I set environment variable "configtest__pass" to "password"
|
11
|
+
Then the environment variable "configtest" has "user" set to "username"
|
12
|
+
And the environment variable "configtest.user" is set to "username"
|
13
|
+
And the environment variable "configtest" has "pass" set to "password"
|
14
|
+
And the environment variable "close_browser_after" is set to "feature"
|
@@ -49,13 +49,13 @@ Given(/^I create a firefox browser named "(.*?)"( with proxy to "(.*?)")$/) do |
|
|
49
49
|
else
|
50
50
|
b = browser.create :firefox
|
51
51
|
end
|
52
|
-
scenario.storage.set(name,
|
52
|
+
scenario.storage.set(name, b)
|
53
53
|
end
|
54
54
|
|
55
55
|
Given(/^I close the browser named "(.*?)"$/) do |name|
|
56
56
|
if scenario.storage.has? name
|
57
|
-
|
58
|
-
|
57
|
+
b = scenario.storage.get name
|
58
|
+
b.close
|
59
59
|
else
|
60
60
|
error("No item in the storage named #{name}")
|
61
61
|
end
|
@@ -139,6 +139,9 @@ Then(/^I should be able to click the first button by force click$/) do
|
|
139
139
|
)
|
140
140
|
end
|
141
141
|
|
142
|
+
Given(/^I set environment variable "(.*?)" to "(.*?)"$/) do |var, val|
|
143
|
+
ENV[var]=val
|
144
|
+
end
|
142
145
|
|
143
146
|
Given(/^I annotate a step with (.*?)$/) do |data|
|
144
147
|
annotate data
|
@@ -230,8 +230,14 @@ end
|
|
230
230
|
Then(/^the firefox browser named "(.*?)" has a profile$/) do |name|
|
231
231
|
if scenario.storage.has? name
|
232
232
|
browser = scenario.storage.get name
|
233
|
-
if browser.
|
234
|
-
|
233
|
+
if browser.browser_name == "remote"
|
234
|
+
if browser.driver.capabilities.firefox_profile.nil?
|
235
|
+
raise "Remote Firefox Profile is not set"
|
236
|
+
end
|
237
|
+
else
|
238
|
+
if browser.optional_data.has_key? "profile" or browser.optional_data.has_key? :profile
|
239
|
+
raise "No profile found in the optional data"
|
240
|
+
end
|
235
241
|
end
|
236
242
|
else
|
237
243
|
error("No item in the storage named #{name}")
|
@@ -348,3 +354,14 @@ Then(/^I expect to use tagname to hash options to (.*?) find element (.*?)$/) do
|
|
348
354
|
end
|
349
355
|
end
|
350
356
|
|
357
|
+
Then(/^the environment variable "(.*?)" is set to "(.*?)"$/) do |var,val|
|
358
|
+
value = env(var)
|
359
|
+
assert_equal val, value, "Incorrect value"
|
360
|
+
end
|
361
|
+
|
362
|
+
Then(/^the environment variable "(.*?)" has "(.*?)" set to "(.*?)"$/) do |var, key, val|
|
363
|
+
hash = env(var,{})
|
364
|
+
assert hash.is_a?(Hash), "Config element is not a Hash: #{hash}"
|
365
|
+
assert hash.has_key?(key), "Config is missing #{key}"
|
366
|
+
assert_equal hash[key], val, "Config has incorrect value"
|
367
|
+
end
|
@@ -2,9 +2,6 @@
|
|
2
2
|
# Copyright 2014 spriteCloud B.V. All rights reserved.
|
3
3
|
# Generated by LapisLazuli, version 0.0.1
|
4
4
|
# Author: "Onno Steenbergen" <onno@steenbe.nl>
|
5
|
-
require "codeclimate-test-reporter"
|
6
|
-
CodeClimate::TestReporter.start
|
7
|
-
|
8
5
|
require 'lapis_lazuli'
|
9
6
|
require 'lapis_lazuli/cucumber'
|
10
7
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lapis_lazuli
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Onno Steenbergen
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date: 2015-
|
14
|
+
date: 2015-05-06 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: bundler
|
@@ -196,6 +196,7 @@ files:
|
|
196
196
|
- lib/lapis_lazuli/browser/error.rb
|
197
197
|
- lib/lapis_lazuli/browser/find.rb
|
198
198
|
- lib/lapis_lazuli/browser/interaction.rb
|
199
|
+
- lib/lapis_lazuli/browser/remote.rb
|
199
200
|
- lib/lapis_lazuli/browser/screenshots.rb
|
200
201
|
- lib/lapis_lazuli/browser/wait.rb
|
201
202
|
- lib/lapis_lazuli/cli.rb
|
@@ -239,6 +240,7 @@ files:
|
|
239
240
|
- test/features/browser.feature
|
240
241
|
- test/features/button.feature
|
241
242
|
- test/features/click.feature
|
243
|
+
- test/features/config.feature
|
242
244
|
- test/features/error.feature
|
243
245
|
- test/features/find.feature
|
244
246
|
- test/features/har.feature
|
@@ -293,6 +295,7 @@ test_files:
|
|
293
295
|
- test/features/browser.feature
|
294
296
|
- test/features/button.feature
|
295
297
|
- test/features/click.feature
|
298
|
+
- test/features/config.feature
|
296
299
|
- test/features/error.feature
|
297
300
|
- test/features/find.feature
|
298
301
|
- test/features/har.feature
|