lapis_lazuli 3.0.1 → 3.0.2

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9ea6c404b7d1a7a47007360bda7725812af256234c6b33b68626ced98c77b3fd
4
- data.tar.gz: e9dc94d78218d53dd6e8bcc0938d8a08481b9e2bc53da9744619183b1f08e099
3
+ metadata.gz: 6371db0c7cade2ee1594513f572a7c36540be30947f35ec275ca88d8cf29f6f6
4
+ data.tar.gz: 58f488b7d84511ec095b04b585a8cbfc0c39853d232ce0285e963191a1ad3e9a
5
5
  SHA512:
6
- metadata.gz: c637008b61477116811bb63e4436f4a00276073da2ad28a6257df7d4812376701e33565000d8abfca02085e6cd6c6877778cff9563609d8f355fa48853006c71
7
- data.tar.gz: 858ce3df0863b0fcc949959bbc0cfa11f9e2b78d238d02f68bed2a6c4912d881e4e191eb4e193b9a051c5b8452dc0129d0eaa7ce8d445354c648e0e5c1f902fd
6
+ metadata.gz: 867d75be07317b7dff52efc926183e48ecc31322a645714fe4aceab9fa2c611f6e2deac7ce00f5c23fee4484407eed495466342dbc91abf80972d6a9caf30ba6
7
+ data.tar.gz: f7ddb7958fc2a0d87d7f0c8f92132f29851955823faf7df7d2afa0bc0aa02dbf5182359f88b57d8dd5ec796cac25a91fff9d5a132b363d5acbaf8ff1663dc7a9
data/CHANGELOG.md ADDED
@@ -0,0 +1,13 @@
1
+ # 3.0.0
2
+
3
+ ## Breaking changes
4
+
5
+ * Dropped support for annotation
6
+ * Dropped support for Cucumber `2` and `3`
7
+
8
+ ## Changes
9
+
10
+ * Updated Cucumber support version to `>= 4`
11
+ * Updated Watir support version to `>= 6`
12
+ * Unlocked all other dependencies.
13
+ * Don't act as an _in between_ party starting up a Watir browser anymore by passing all browser starts arguments directly to Watir.
data/README.md CHANGED
@@ -7,6 +7,9 @@ test automation suite development.
7
7
  [![Code Climate](https://codeclimate.com/github/spriteCloud/lapis-lazuli/badges/gpa.svg)](https://codeclimate.com/github/spriteCloud/lapis-lazuli)
8
8
  [![Test Coverage](https://codeclimate.com/github/spriteCloud/lapis-lazuli/badges/coverage.svg)](https://codeclimate.com/github/spriteCloud/lapis-lazuli)
9
9
 
10
+ Tested with Cucumber 4, 5 & 6
11
+ For cucumber 2 and 3, have a look at the version 2 release of Lapis Lazuli.
12
+
10
13
  A lot of functionality is aimed at dealing better with [Watir](http://watir.com/),
11
14
  such as:
12
15
 
data/lapis_lazuli.gemspec CHANGED
@@ -23,7 +23,7 @@ Gem::Specification.new do |spec|
23
23
  spec.summary = %q{Cucumber helper functions and scaffolding for easier test automation suite development.}
24
24
  spec.homepage = "https://github.com/spriteCloud/lapis-lazuli"
25
25
  spec.license = "MITNFA"
26
- spec.required_ruby_version = '~> 2'
26
+ spec.required_ruby_version = '>= 2'
27
27
  spec.platform = Gem::Platform::RUBY
28
28
 
29
29
  spec.files = `git ls-files -z`.split("\x0")
@@ -31,23 +31,23 @@ Gem::Specification.new do |spec|
31
31
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
32
32
  spec.require_paths = ["lib"]
33
33
 
34
- spec.add_development_dependency "bundler", "~> 2.0"
35
- spec.add_development_dependency "rake", "~> 12.3"
36
- spec.add_development_dependency "simplecov", "~> 0.17"
34
+ spec.add_development_dependency "bundler", ">= 2.0"
35
+ spec.add_development_dependency "rake", ">= 12.3"
36
+ spec.add_development_dependency "simplecov", ">= 0.17"
37
37
 
38
- spec.add_dependency "faraday_middleware", "~> 0.13"
39
- spec.add_dependency "faraday_json", "~> 0.1"
40
- spec.add_dependency "multi_xml", "~> 0.6"
41
- spec.add_dependency "teelogger", "~> 0.5"
42
- spec.add_dependency "minitest", "~> 5.11"
43
- spec.add_dependency "thor", "~> 0.20" # Used in the cucumber project generator
44
- spec.add_dependency "facets", "~> 3.1" # Used in the cucumber project generator
45
- spec.add_dependency "deep_merge", "~> 1.2"
38
+ spec.add_dependency "faraday_middleware", ">= 0.13"
39
+ spec.add_dependency "faraday_json", ">= 0.1"
40
+ spec.add_dependency "multi_xml", ">= 0.6"
41
+ spec.add_dependency "teelogger", ">= 0.5"
42
+ spec.add_dependency "minitest", ">= 5.11"
43
+ spec.add_dependency "thor", ">= 0.20" # Used in the cucumber project generator
44
+ spec.add_dependency "facets", ">= 3.1" # Used in the cucumber project generator
45
+ spec.add_dependency "deep_merge", ">= 1.2"
46
46
 
47
47
  # webdriver specifics
48
- spec.add_dependency "selenium-webdriver", ">= 2.0", '< 4'
49
- spec.add_dependency "watir", "~> 6"
50
- spec.add_dependency "ffi", "~> 1.11"
51
- spec.add_dependency "cucumber", ">= 2.0", '< 4.0'
48
+ spec.add_dependency "selenium-webdriver", ">= 2.0"
49
+ spec.add_dependency "watir", ">= 6"
50
+ spec.add_dependency "ffi", ">= 1.11"
51
+ spec.add_dependency "cucumber", ">= 4.0"
52
52
 
53
53
  end
data/lib/lapis_lazuli.rb CHANGED
@@ -34,7 +34,6 @@ require "lapis_lazuli/world/config"
34
34
  require "lapis_lazuli/world/hooks"
35
35
  require "lapis_lazuli/world/variable"
36
36
  require "lapis_lazuli/world/error"
37
- require "lapis_lazuli/world/annotate"
38
37
  require "lapis_lazuli/world/logging"
39
38
  require "lapis_lazuli/world/browser"
40
39
  require "lapis_lazuli/world/api"
@@ -49,7 +48,6 @@ module LapisLazuli
49
48
  include LapisLazuli::WorldModule::Hooks
50
49
  include LapisLazuli::WorldModule::Variable
51
50
  include LapisLazuli::WorldModule::Error
52
- include LapisLazuli::WorldModule::Annotate
53
51
  include LapisLazuli::WorldModule::Logging
54
52
  include LapisLazuli::WorldModule::Browser
55
53
  include LapisLazuli::WorldModule::API
@@ -5,23 +5,7 @@
5
5
  # Copyright (c) 2015 spriteCloud B.V. and other LapisLazuli contributors.
6
6
  # All rights reserved.
7
7
  #
8
-
9
- # Hack for cucumber 2.0.x
10
- begin
11
- module Cucumber
12
- module Core
13
- module Ast
14
- class ExamplesTable
15
- public :example_rows
16
- end # ExamplesTable
17
- end # Ast
18
- end # Core
19
- end # Cucumber
20
- rescue NameError
21
- # Not cucumber 2.0.x
22
- end
23
-
24
-
8
+ #
25
9
  module LapisLazuli
26
10
  ##
27
11
  # Convenience module for dealing with aspects of the cucumber AST. From
@@ -30,131 +14,8 @@ module LapisLazuli
30
14
  ##
31
15
  # Return a unique and human parsable ID for scenarios
32
16
  def scenario_id(scenario)
33
- # For 2.0.x, the best scenario ID is one prefixed by the file name + line
34
- # number, followed by the feature name, scenario name, and table data (if
35
- # applicable).
36
- if is_cucumber_2?(scenario)
37
- id = [scenario.location.to_s]
38
- for i in 0 .. scenario.source.length - 1 do
39
- part = scenario.source[i]
40
- if part.respond_to?(:name)
41
- id << part.name
42
- elsif part.is_a?(Cucumber::Core::Ast::ExamplesTable::Row)
43
- id << part.values.join("|")
44
- end
45
- end
46
- return id
47
- end
48
-
49
- case scenario
50
- when Cucumber::Ast::Scenario
51
- return [
52
- scenario.feature.file,
53
- scenario.name
54
- ]
55
- when Cucumber::Ast::OutlineTable::ExampleRow
56
- return [
57
- scenario.scenario_outline.feature.file,
58
- scenario.scenario_outline.name,
59
- scenario.name
60
- ]
61
- end
62
- end
63
-
64
-
65
- ##
66
- # Tests whether the given scenario object indicates we're using cucumber 2.x
67
- def is_cucumber_2?(scenario)
68
- begin
69
- # The assumption - FIXME perhaps wrong - is that cucumber 1.3.x does not
70
- # have this source array.
71
- return (scenario.respond_to?(:source) and scenario.source.is_a?(Array))
72
- rescue
73
- return false
74
- end
75
- end
76
-
77
-
78
- ##
79
- # Tests whether the scenario object is a single scenario
80
- def is_scenario?(scenario)
81
- begin
82
- # 1.3.x
83
- return scenario.class == Cucumber::Ast::Scenario
84
- rescue
85
- # 2.0.x - everything is a Cucumber::Core::Test::Case
86
- return (not scenario.outline?)
87
- end
17
+ [scenario.id]
88
18
  end
89
19
 
90
-
91
- ##
92
- # Tests whether the scenario object is a table row
93
- def is_table_row?(scenario)
94
- begin
95
- # 1.3.x
96
- return scenario.class == Cucumber::Ast::OutlineTable::ExampleRow
97
- rescue
98
- # 2.0.x - everything is a Cucumber::Core::Test::Case
99
- return scenario.outline?
100
- end
101
- end
102
-
103
-
104
- ##
105
- # Tests whether this scenario is the last scenario of a feature
106
- def is_last_scenario?(scenario)
107
- if is_scenario?(scenario)
108
- begin
109
- # 2.0.x
110
- return (scenario.feature.feature_elements.last.location == scenario.location)
111
- rescue
112
- # 1.3.x
113
- return (scenario.feature.feature_elements.last == scenario)
114
- end
115
-
116
- elsif is_table_row?(scenario)
117
- begin
118
- # 2.0.x
119
-
120
- # We can bail early if this scenario's line is < the last feature
121
- # element's line
122
- outline = scenario.feature.feature_elements.last
123
- if scenario.source.last.location.line < outline.location.line
124
- return false
125
- end
126
-
127
- # Now the last feature element needs to be an outline - this is a
128
- # sanity check that makes later stuff easier
129
- if not outline.respond_to? :examples_tables
130
- return false
131
- end
132
-
133
- # The last row of the last examples tables is what we care about
134
- last_row = outline.examples_tables.last.example_rows.last
135
-
136
- # If the current scenario has the same location as the last example,
137
- # then we're the last scenario.
138
- return scenario.source.last.location.line == last_row.location.line
139
-
140
- rescue
141
- # 1.3.x
142
- if scenario.scenario_outline.feature.feature_elements.last == scenario.scenario_outline
143
- # And is this the last example in the table?
144
- is_last_example = false
145
- scenario.scenario_outline.each_example_row do |row|
146
- if row == scenario
147
- is_last_example = true
148
- else
149
- # Overwrite this again with 'false'
150
- is_last_example = false
151
- end
152
- end
153
- return is_last_example
154
- end
155
- end
156
- end
157
- raise "If you see this error it might indicate you're running an unsupported version of cucumber"
158
- end
159
20
  end # module Ast
160
21
  end # module LapisLazuli
@@ -5,16 +5,13 @@
5
5
  # Copyright (c) 2013-2019 spriteCloud B.V. and other LapisLazuli contributors.
6
6
  # All rights reserved.
7
7
  #
8
-
9
8
  require "lapis_lazuli/ast"
10
-
11
9
  # Modules
12
10
  require "lapis_lazuli/browser/error"
13
11
  require 'lapis_lazuli/browser/find'
14
12
  require "lapis_lazuli/browser/wait"
15
13
  require "lapis_lazuli/browser/screenshots"
16
14
  require "lapis_lazuli/browser/interaction"
17
- require "lapis_lazuli/browser/remote"
18
15
  require 'lapis_lazuli/generic/xpath'
19
16
  require 'lapis_lazuli/generic/assertions'
20
17
 
@@ -27,19 +24,18 @@ module LapisLazuli
27
24
  # object, and for some WorldModules to exist in it (see assertions in
28
25
  # constructor).
29
26
  class Browser
30
- include LapisLazuli::Ast
31
27
 
32
28
  include LapisLazuli::BrowserModule::Error
33
29
  include LapisLazuli::BrowserModule::Find
34
30
  include LapisLazuli::BrowserModule::Wait
35
31
  include LapisLazuli::BrowserModule::Screenshots
36
32
  include LapisLazuli::BrowserModule::Interaction
37
- include LapisLazuli::BrowserModule::Remote
38
33
  include LapisLazuli::GenericModule::XPath
39
34
 
40
- @@world=nil
41
- @@cached_browser_options={}
42
- @@browsers=[]
35
+ @@world = nil
36
+ @@cached_browser_options = {}
37
+ @@browsers = []
38
+
43
39
  class << self
44
40
  include LapisLazuli::GenericModule::Assertions
45
41
 
@@ -70,11 +66,9 @@ module LapisLazuli
70
66
  end
71
67
 
72
68
  @browser
73
- @browser_name
74
- @browser_wanted
75
- @optional_data
69
+ @browser_args
76
70
 
77
- attr_reader :browser_name, :browser_wanted, :optional_data
71
+ attr_reader :browser_args
78
72
 
79
73
  def initialize(*args)
80
74
  # The class only works with some modules loaded; they're loaded by the
@@ -94,8 +88,7 @@ module LapisLazuli
94
88
  # Support browser.dup to create a duplicate
95
89
  def initialize_copy(source)
96
90
  super
97
- @optional_data = @optional_data.dup
98
- @browser = create_driver(@browser_wanted, @optional_data)
91
+ @browser = create_driver(*@browser_args)
99
92
  # Add this browser to the list of all browsers
100
93
  LapisLazuli::Browser.add_browser(self)
101
94
  end
@@ -124,7 +117,7 @@ module LapisLazuli
124
117
  # Add this browser to the list of all browsers
125
118
  LapisLazuli::Browser.add_browser(self)
126
119
  # Making sure all browsers are gracefully closed when the exit event is triggered.
127
- at_exit {LapisLazuli::Browser::close_all 'exit event trigger'}
120
+ at_exit { LapisLazuli::Browser::close_all 'exit event trigger' }
128
121
  end
129
122
  end
130
123
 
@@ -138,7 +131,7 @@ module LapisLazuli
138
131
 
139
132
  ##
140
133
  # Closes the browser and updates LL so that it will open a new one if needed
141
- def close(reason = nil, remove_from_list=true)
134
+ def close(reason = nil, remove_from_list = true)
142
135
  if not @browser.nil?
143
136
  if not reason.nil?
144
137
  reason = " after #{reason}"
@@ -171,18 +164,39 @@ module LapisLazuli
171
164
  # Determine the config
172
165
  close_browser_after = world.env_or_config("close_browser_after")
173
166
  case close_browser_after
174
- when "scenario"
175
- # We always close it
167
+ when "scenario"
168
+ # We always close it
169
+ LapisLazuli::Browser.close_all close_browser_after
170
+ when "never"
171
+ # Do nothing: party time, excellent!
172
+ when "feature"
173
+ if is_last_scenario?(scenario)
174
+ # Close it
176
175
  LapisLazuli::Browser.close_all close_browser_after
177
- when "never"
178
- # Do nothing: party time, excellent!
179
- when "feature"
180
- if is_last_scenario?(scenario)
181
- # Close it
182
- LapisLazuli::Browser.close_all close_browser_after
183
- end
184
- else # close after 'end' is now default
185
- # Also ignored here - this is handled in World.browser_destroy
176
+ end
177
+ else
178
+ # close after 'end' is now default
179
+ # Also ignored here - this is handled in World.browser_destroy
180
+ end
181
+ end
182
+
183
+ def is_last_scenario?(scenario)
184
+ begin
185
+ feature_file = File.read(scenario.location.file)
186
+ gherkin_object = Gherkin::Parser.new.parse(feature_file)
187
+ last_line = gherkin_object[:feature][:children].last[:scenario][:examples].last[:table_body].last[:location][:line] rescue nil
188
+ unless last_line
189
+ last_line = gherkin_object[:feature][:children].last[:scenario][:location][:line] rescue nil
190
+ end
191
+ if last_line
192
+ return last_line == scenario.location.line
193
+ else
194
+ warn 'Failed to find the last line of the feature trying to determine if this is the last scenario running.'
195
+ return false
196
+ end
197
+ rescue Exception => e
198
+ warn 'Something went wrong trying to determine if this is the last sceanrio of the feature.'
199
+ warn e
186
200
  end
187
201
  end
188
202
 
@@ -209,7 +223,7 @@ module LapisLazuli
209
223
  LapisLazuli::Browser.close_all("end")
210
224
  end
211
225
 
212
- def self.close_all(reason=nil)
226
+ def self.close_all(reason = nil)
213
227
  # A running browser should exist and we are allowed to close it
214
228
  if @@browsers.length != 0 and @@world.env_or_config("close_browser_after") != "never"
215
229
  # Notify user
@@ -225,68 +239,22 @@ module LapisLazuli
225
239
  end
226
240
 
227
241
  private
242
+
228
243
  ##
229
244
  # The main browser window for testing
230
- def init(browser_wanted=nil, optional_data=nil)
245
+ def init(*args)
231
246
  # Store the optional data so on restart of the browser it still has the correct configuration
232
- if optional_data.nil? and @@cached_browser_options.has_key?(:optional_data) and (browser_wanted.nil? or browser_wanted == @@cached_browser_options[:browser])
233
- optional_data = @@cached_browser_options[:optional_data].dup
234
- if !@@cached_browser_options[:optional_data][:profile].nil?
235
- # A selenium profile needs to be duplicated separately, else it doesn't get a new ID.
236
- optional_data[:profile] = @@cached_browser_options[:optional_data][:profile].dup
237
- end
238
- elsif optional_data.nil?
239
- optional_data = {}
240
- end
241
-
242
- # Do the same caching stuff for the browser
243
- if browser_wanted.nil? and @@cached_browser_options.has_key?(:browser)
244
- browser_wanted = @@cached_browser_options[:browser]
245
- end
246
-
247
- # Set the default device if the optional data does not contain a specific device
248
- if optional_data[:device].nil?
249
- # Check if there is a cached value of a previously used
250
- if @@cached_browser_options.has_key?(:device)
251
- optional_data[:device] = @@cached_browser_options[:device]
252
- # Check if the ENV['DEVICE'] variable is set
253
- elsif world.env_or_config('DEVICE', false)
254
- optional_data[:device] = world.env_or_config('DEVICE')
255
- # Else grab the default set device
256
- elsif world.env_or_config('default_device', false)
257
- optional_data[:device] = world.env_or_config('default_device')
258
- else
259
- warn 'No default device, nor a selected device was set. Browser default settings will be loaded. More info: http://testautomation.info/Lapis_Lazuli:Device_Simulation'
260
- end
261
- end
262
-
263
- # cache all the settings if this is the first time opening the browser.
264
- if !@@cached_browser_options.has_key? :browser and !@@cached_browser_options.has_key? :optional_data
265
- @@cached_browser_options[:browser] = browser_wanted
266
- # Duplicate the data as Webdriver modifies it
267
- @@cached_browser_options[:optional_data] = optional_data.dup
268
- if !@@cached_browser_options[:optional_data][:profile].nil?
269
- # A selenium profile needs to be duplicated separately, else it doesn't get a new ID.
270
- @@cached_browser_options[:optional_data][:profile] = optional_data[:profile].dup
271
- end
272
- end
273
-
274
- @browser_wanted = browser_wanted
275
- @optional_data = optional_data
276
- # Create the browser
277
- create_driver(@browser_wanted, @optional_data)
247
+ create_driver(*args)
278
248
  end
279
249
 
280
250
  ##
281
251
  # Create a new browser depending on settings
282
252
  # Always cached the supplied arguments
283
- def create_driver(browser_wanted=nil, optional_data=nil)
253
+ def create_driver(*args)
284
254
  # Remove device information from optional_data and create a separate variable for it
285
- device = optional_data[:device]
286
- optional_data.delete :device
287
-
255
+ device = args[1] ? args[1].delete(:device) : nil
288
256
  # If device is set, load it from the devices.yml config
289
- if !device.nil?
257
+ unless device.nil?
290
258
  begin
291
259
  world.add_config_from_file('./config/devices.yml')
292
260
  rescue
@@ -307,84 +275,6 @@ module LapisLazuli
307
275
  raise LoadError, "#{err}: you need to add 'watir' to your Gemfile before using the browser."
308
276
  end
309
277
 
310
- # No browser? Does the config have a browser?
311
- if browser_wanted.nil?
312
- browser_wanted = world.env_or_config('browser', nil)
313
- end
314
-
315
- b = browser_wanted
316
- b = b.to_sym unless b.nil?
317
-
318
- # Overwrite user-agent if a device simulation is set and it contains a user-agent
319
- if !device_configuration.nil? and !device_configuration['user-agent'].nil?
320
- # Firefox user-agent settings
321
- # Create a firefox profile if it does not exist yet
322
- if optional_data[:profile].nil?
323
- optional_data[:profile] = Selenium::WebDriver::Firefox::Profile.new
324
- else
325
- # If the profile already exists, we need to create a duplicate, so we don't overwrite any settings.
326
- optional_data[:profile] = optional_data[:profile].dup
327
- end
328
- # Add the user agent to it if it has not been set yet
329
- if optional_data[:profile].instance_variable_get(:@additional_prefs)['general.useragent.override'].nil?
330
- optional_data[:profile]['general.useragent.override'] = device_configuration['user-agent']
331
- else
332
- world.log.debug "User-agent was already set in the :profile."
333
- end
334
- # Chrome user-agent settings
335
- ua_string = "--user-agent=#{device_configuration['user-agent']}"
336
- if optional_data[:switches].nil?
337
- optional_data[:switches] = [ua_string]
338
- elsif !optional_data[:switches].join(',').include? '--user-agent='
339
- optional_data[:switches].push ua_string
340
- else
341
- world.log.debug "User-agent was already set in the :switches."
342
- end
343
- if b != :firefox and b != :chrome
344
- warn "#{device} user agent cannot be set for #{b.to_s}. Only Chrome & Firefox are supported."
345
- end
346
- end
347
-
348
- args = []
349
- args = [b] unless b.nil?
350
- @browser_name = b.to_s
351
- if b == :remote
352
- # Get the config
353
- remote_config = world.env_or_config("remote", {})
354
-
355
- # The settings we are going to use to create the browser
356
- remote_settings = {}
357
-
358
- # Add the config to the settings using downcase string keys
359
- remote_config.each {|k, v| remote_settings[k.to_s.downcase] = v}
360
-
361
- if optional_data.is_a? Hash
362
- # Convert the optional data to downcase string keys
363
- string_hash = Hash.new
364
- optional_data.each {|k, v| string_hash[k.to_s.downcase] = v}
365
-
366
- # Merge them with the settings
367
- remote_settings.merge! string_hash
368
- end
369
-
370
- args.push(remote_browser_config(remote_settings))
371
- elsif not optional_data.nil? and not optional_data.empty?
372
- world.log.debug("Got optional data: #{optional_data}")
373
- args.push(optional_data)
374
- elsif world.has_proxy?
375
- # Create a session if needed
376
- if !world.proxy.has_session?
377
- world.proxy.create()
378
- end
379
-
380
- proxy_url = "#{world.proxy.ip}:#{world.proxy.port}"
381
- if b == :firefox
382
- world.log.debug("Configuring Firefox proxy: #{proxy_url}")
383
- profile = Selenium::WebDriver::Firefox::Profile.new
384
- profile.proxy = Selenium::WebDriver::Proxy.new :http => proxy_url, :ssl => proxy_url
385
- args.push({:profile => profile})
386
- end
387
- end
388
278
  begin
389
279
  browser_instance = Watir::Browser.new(*args)
390
280
  # Resize the browser if the device simulation requires it
@@ -394,7 +284,7 @@ module LapisLazuli
394
284
  rescue Selenium::WebDriver::Error::UnknownError => err
395
285
  raise err
396
286
  end
397
- return browser_instance
287
+ browser_instance
398
288
  end
399
289
  end
400
290