appium_lib_core 5.7.0 → 5.8.0

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: fdc105db151bc415072c5c693ec951a14ea681762f686be52941b89d48eb879c
4
- data.tar.gz: 74ae58624c62216572e321b22386b530f3271ffeeba15b9e25764b9ffda5328d
3
+ metadata.gz: 06c7b0bb078ece1a833874436e4611cb407cc762d73dd2fbcb27e69ace076e14
4
+ data.tar.gz: ab4e2733c06ed9866368e983c4e2a28510a4125eff5614e404c3e83f1eaceae9
5
5
  SHA512:
6
- metadata.gz: 0a52ad3c06dc494049be9c72cf7e74fea74ad005b4c45bc87ae308e3b27e180f0488c0a9e967e16992031d5282f637bba35b5aa80235ece79d1307e9e05ca120
7
- data.tar.gz: 160ec09d1c7f1205ade5e17fab276a3e68f10250b7c3ff84a5984b9fd875a7d74238fc5cc7bb2c6c960ccf581993b642718fba6b7f8731df2e74e1d676c0f2ae
6
+ metadata.gz: fd894aaad52613559c842c0a42ff6d6bbfc9b871ea5f3bf02a302f7ae53e9b7cb6397bea363f9108ac9bbe601f1f1cacb5fa38ee4371eebaf875d2e64b756cf4
7
+ data.tar.gz: '097f706be4f0403e6397bdb941f1f63ced8c6cfae8a7f68af401ffcd0fa2e75d81051b37d1f421c9d60051c85f125c6662edb8461f8fcbc7afcaa6a89ba69142'
data/CHANGELOG.md CHANGED
@@ -10,6 +10,12 @@ Read `release_notes.md` for commit level details.
10
10
 
11
11
  ### Deprecations
12
12
 
13
+ ## [5.8.0] - 2022-12-11
14
+
15
+ ### Enhancements
16
+ - Add `::Appium::Core::Driver#attach_to` to generate a driver instance which has the given session id.
17
+ - The primary usage is for debugging to attach to an existing session.
18
+
13
19
  ## [5.7.0] - 2022-12-02
14
20
 
15
21
  ### Enhancements
data/README.md CHANGED
@@ -104,7 +104,7 @@ $ IGNORE_VERSION_SKIP=true CI=true bundle exec rake test:func:android
104
104
 
105
105
  opts = {
106
106
  capabilities: { # Append capabilities
107
- platformName: :ios,
107
+ platformName: 'ios',
108
108
  platformVersion: '11.0',
109
109
  deviceName: 'iPhone Simulator',
110
110
  automationName: 'XCUITest',
@@ -133,6 +133,15 @@ $ IGNORE_VERSION_SKIP=true CI=true bundle exec rake test:func:android
133
133
 
134
134
  More examples are in [test/functional](test/functional)
135
135
 
136
+ As of version 5.8.0, the client can attach to an existing session. The main purpose is for debugging.
137
+
138
+ ```ruby
139
+ # @driver is the driver instance of an existing session
140
+ attached_driver = ::Appium::Core::Driver.attach_to @driver.session_id, url: 'http://127.0.0.1:4723/wd/hub', automation_name: 'XCUITest', platform_name: 'ios'
141
+ assert attached_driver.session_id == @driver.session_id
142
+ attached_driver.page_source
143
+ ```
144
+
136
145
  ### Capabilities
137
146
 
138
147
  Read [Appium/Core/Driver](https://www.rubydoc.info/github/appium/ruby_lib_core/Appium/Core/Driver) to catch up with available capabilities.
@@ -43,13 +43,39 @@ module Appium
43
43
 
44
44
  def browser
45
45
  @browser ||= begin
46
- name = @capabilities.browser_name
46
+ name = @capabilities&.browser_name
47
47
  name ? name.tr(' ', '_').downcase.to_sym : 'unknown'
48
48
  rescue KeyError
49
49
  APPIUM_NATIVE_BROWSER_NAME
50
50
  end
51
51
  end
52
52
 
53
+ # Appium only.
54
+ # Attach to an existing session.
55
+ #
56
+ # @param [String] The session id to attach to.
57
+ # @param [String] platform_name The platform name to keep in the dummy capabilities
58
+ # @param [String] platform_name The automation name to keep in the dummy capabilities
59
+ # @return [::Appium::Core::Base::Capabilities]
60
+ #
61
+ # @example
62
+ #
63
+ # new_driver = ::Appium::Core::Driver.attach_to(
64
+ # driver.session_id,
65
+ # url: 'http://127.0.0.1:4723/wd/hub', automation_name: 'UiAutomator2', platform_name: 'Android'
66
+ # )
67
+ #
68
+ def attach_to(session_id, platform_name, automation_name)
69
+ @available_commands = ::Appium::Core::Commands::COMMANDS.dup
70
+ @session_id = session_id
71
+
72
+ # generate a dummy capabilities instance which only has the given platformName and automationName
73
+ @capabilities = ::Appium::Core::Base::Capabilities.new(
74
+ 'platformName' => platform_name,
75
+ 'automationName' => automation_name
76
+ )
77
+ end
78
+
53
79
  # Override
54
80
  # Creates session handling.
55
81
  #
@@ -51,10 +51,6 @@ module Appium
51
51
  @wait_timeout = opts.delete(:wait_timeout)
52
52
  @wait_interval = opts.delete(:wait_interval)
53
53
 
54
- # For logging.
55
- # TODO: Remove when appium core no longer uses this in this bridge.
56
- @automation_name = opts.delete(:automation_name)
57
-
58
54
  super
59
55
  end
60
56
 
@@ -63,13 +59,26 @@ module Appium
63
59
  # @return [::Appium::Core::Base::Bridge]
64
60
  #
65
61
  def create_bridge(**opts)
62
+ # for a new session request
66
63
  capabilities = opts.delete(:capabilities)
67
64
  bridge_opts = { http_client: opts.delete(:http_client), url: opts.delete(:url) }
65
+
66
+ # for attaching to an existing session
67
+ session_id = opts.delete(:existing_session_id)
68
+ automation_name = opts.delete(:automation_name)
69
+ platform_name = opts.delete(:platform_name)
70
+
68
71
  raise ::Appium::Core::Error::ArgumentError, "Unable to create a driver with parameters: #{opts}" unless opts.empty?
69
72
 
70
73
  bridge = ::Appium::Core::Base::Bridge.new(**bridge_opts)
71
74
 
72
- bridge.create_session(capabilities)
75
+ if session_id.nil?
76
+ bridge.create_session(capabilities)
77
+ else
78
+ # attach to the existing session id
79
+ bridge.attach_to(session_id, platform_name, automation_name)
80
+ end
81
+
73
82
  bridge
74
83
  end
75
84
 
@@ -566,12 +575,6 @@ module Appium
566
575
  # @driver.launch_app
567
576
  #
568
577
  def launch_app
569
- # TODO: Define only in Windows module when ruby_lib_core removes this method
570
- if @automation_name != :windows
571
- ::Appium::Logger.warn(
572
- '[DEPRECATION] launch_app is deprecated. Please use activate_app instead.'
573
- )
574
- end
575
578
  @bridge.launch_app
576
579
  end
577
580
 
@@ -583,12 +586,6 @@ module Appium
583
586
  # @driver.close_app
584
587
  #
585
588
  def close_app
586
- # TODO: Define only in Windows module when ruby_lib_core removes this method
587
- if @automation_name != :windows
588
- ::Appium::Logger.warn(
589
- '[DEPRECATION] close_app is deprecated. Please use terminate_app instead.'
590
- )
591
- end
592
589
  @bridge.close_app
593
590
  end
594
591
 
@@ -18,10 +18,16 @@ module Appium
18
18
  module Device
19
19
  module AppManagement
20
20
  def launch_app
21
+ ::Appium::Logger.warn(
22
+ '[DEPRECATION] launch_app is deprecated. Please use activate_app instead.'
23
+ )
21
24
  execute :launch_app
22
25
  end
23
26
 
24
27
  def close_app
28
+ ::Appium::Logger.warn(
29
+ '[DEPRECATION] close_app is deprecated. Please use terminate_app instead.'
30
+ )
25
31
  execute :close_app
26
32
  end
27
33
 
@@ -275,7 +275,40 @@ module Appium
275
275
  # @core.start_driver # start driver with 'url'. Connect to 'http://custom-host:8080/wd/hub.com'
276
276
  #
277
277
  def self.for(opts = {})
278
- new(opts)
278
+ new.setup_for_new_session(opts)
279
+ end
280
+
281
+ # Attach to an existing session. The main usage of this method is to attach to
282
+ # an existing session for debugging. The generated driver instance has the capabilities which
283
+ # has the given automationName and platformName only since the W3C WebDriver spec does not provide
284
+ # an endpoint to get running session's capabilities.
285
+ #
286
+ #
287
+ # @param [String] The session id to attach to.
288
+ # @param [String] url The WebDriver URL to attach to with the session_id.
289
+ # @param [String] automation_name The platform name to keep in the dummy capabilities
290
+ # @param [String] platform_name The automation name to keep in the dummy capabilities
291
+ # @return [Selenium::WebDriver] A new driver instance with the given session id.
292
+ #
293
+ # @example
294
+ #
295
+ # new_driver = ::Appium::Core::Driver.attach_to(
296
+ # driver.session_id, # The 'driver' has an existing session id
297
+ # url: 'http://127.0.0.1:4723/wd/hub', automation_name: 'UiAutomator2', platform_name: 'Android'
298
+ # )
299
+ # new_driver.page_source # for example
300
+ #
301
+ def self.attach_to(
302
+ session_id, url: nil, automation_name: nil, platform_name: nil,
303
+ http_client_ops: { http_client: nil, open_timeout: 999_999, read_timeout: 999_999 }
304
+ )
305
+ new.attach_to(
306
+ session_id,
307
+ automation_name: automation_name,
308
+ platform_name: platform_name,
309
+ url: url,
310
+ http_client_ops: http_client_ops
311
+ )
279
312
  end
280
313
 
281
314
  private
@@ -286,12 +319,18 @@ module Appium
286
319
  @delegate_target
287
320
  end
288
321
 
289
- public
290
-
291
322
  # @private
292
- def initialize(opts = {})
323
+ def initialize
293
324
  @delegate_target = self # for testing purpose
294
325
  @automation_name = nil # initialise before 'set_automation_name'
326
+ end
327
+
328
+ public
329
+
330
+ # @private
331
+ # Set up for a neww session
332
+ def setup_for_new_session(opts = {})
333
+ @custom_url = opts.delete :url # to set the custom url as :url
295
334
 
296
335
  # TODO: Remove when we implement Options
297
336
  # The symbolize_keys is to keep compatiility for the legacy code, which allows capabilities to give 'string' as the key.
@@ -299,7 +338,6 @@ module Appium
299
338
  # FIXME: First, please try to remove `nested: true` to `nested: false`.
300
339
  opts = Appium.symbolize_keys(opts, nested: true)
301
340
 
302
- @custom_url = opts.delete :url
303
341
  @caps = get_caps(opts)
304
342
 
305
343
  set_appium_lib_specific_values(get_appium_lib_opts(opts))
@@ -308,8 +346,7 @@ module Appium
308
346
  set_automation_name
309
347
 
310
348
  extend_for(device: @device, automation_name: @automation_name)
311
-
312
- self # rubocop:disable Lint/Void
349
+ self
313
350
  end
314
351
 
315
352
  # Creates a new global driver and quits the old one if it exists.
@@ -320,7 +357,7 @@ module Appium
320
357
  # @option http_client_ops [Hash] :http_client Custom HTTP Client
321
358
  # @option http_client_ops [Hash] :open_timeout Custom open timeout for http client.
322
359
  # @option http_client_ops [Hash] :read_timeout Custom read timeout for http client.
323
- # @return [Selenium::WebDriver] the new global driver
360
+ # @return [Selenium::WebDriver] A new driver instance
324
361
  #
325
362
  # @example
326
363
  #
@@ -377,8 +414,7 @@ module Appium
377
414
  capabilities: @caps, # ::Appium::Core::Base::Capabilities
378
415
  url: @custom_url,
379
416
  wait_timeout: @wait_timeout,
380
- wait_interval: @wait_interval,
381
- automation_name: @automation_name)
417
+ wait_interval: @wait_interval)
382
418
 
383
419
  if @direct_connect
384
420
  d_c = DirectConnections.new(@driver.capabilities)
@@ -396,6 +432,8 @@ module Appium
396
432
  @http_client.additional_headers.delete Appium::Core::Base::Http::RequestHeaders::KEYS[:idempotency]
397
433
  end
398
434
 
435
+ # TODO: this method can be removed after releasing Appium 2.0, and after a while
436
+ # since Appium 2.0 reuqires 'automationName'. This method won't help anymore then.
399
437
  # If "automationName" is set only server side, this method set "automationName" attribute into @automation_name.
400
438
  # Since @automation_name is set only client side before start_driver is called.
401
439
  set_automation_name_if_nil
@@ -405,7 +443,47 @@ module Appium
405
443
  @driver
406
444
  end
407
445
 
408
- private
446
+ # @privvate
447
+ # Attach to an existing session
448
+ def attach_to(session_id, url: nil, automation_name: nil, platform_name: nil,
449
+ http_client_ops: { http_client: nil, open_timeout: 999_999, read_timeout: 999_999 })
450
+
451
+ raise ::Appium::Core::Error::ArgumentError, 'The :url must not be nil' if url.nil?
452
+ raise ::Appium::Core::Error::ArgumentError, 'The :automation_name must not be nil' if automation_name.nil?
453
+ raise ::Appium::Core::Error::ArgumentError, 'The :platform_name must not be nil' if platform_name.nil?
454
+
455
+ @custom_url = url
456
+
457
+ # use lowercase internally
458
+ @automation_name = convert_downcase(automation_name)
459
+ @device = convert_downcase(platform_name)
460
+
461
+ extend_for(device: @device, automation_name: @automation_name)
462
+
463
+ @http_client = get_http_client http_client: http_client_ops.delete(:http_client),
464
+ open_timeout: http_client_ops.delete(:open_timeout),
465
+ read_timeout: http_client_ops.delete(:read_timeout)
466
+
467
+ # Note that 'enable_idempotency_header' works only a new session reqeust. The attach_to method skips
468
+ # the new session request, this it does not needed.
469
+
470
+ begin
471
+ # included https://github.com/SeleniumHQ/selenium/blob/43f8b3f66e7e01124eff6a5805269ee441f65707/rb/lib/selenium/webdriver/remote/driver.rb#L29
472
+ @driver = ::Appium::Core::Base::Driver.new(http_client: @http_client,
473
+ url: @custom_url,
474
+ listener: @listener,
475
+ existing_session_id: session_id,
476
+ automation_name: automation_name,
477
+ platform_name: platform_name)
478
+
479
+ # export session
480
+ write_session_id(@driver.session_id, @export_session_path) if @export_session
481
+ rescue Errno::ECONNREFUSED
482
+ raise "ERROR: Unable to connect to Appium. Is the server running on #{@custom_url}?"
483
+ end
484
+
485
+ @driver
486
+ end
409
487
 
410
488
  def get_http_client(http_client: nil, open_timeout: nil, read_timeout: nil)
411
489
  client = http_client || Appium::Core::Base::Http::Default.new
@@ -431,8 +509,6 @@ module Appium
431
509
  {}
432
510
  end
433
511
 
434
- public
435
-
436
512
  # Quits the driver
437
513
  # @return [void]
438
514
  #
@@ -626,7 +702,7 @@ module Appium
626
702
  @device = @caps[:platformName] || @caps['platformName']
627
703
  return @device unless @device
628
704
 
629
- @device = @device.is_a?(Symbol) ? @device.downcase : @device.downcase.strip.intern
705
+ @device = convert_downcase @device
630
706
  end
631
707
 
632
708
  # @private
@@ -634,9 +710,12 @@ module Appium
634
710
  # TODO: check if the Appium.symbolize_keys(opts, nested: false) enoug with this
635
711
  candidate = @caps[:automationName] || @caps['automationName']
636
712
  @automation_name = candidate if candidate
637
- @automation_name = if @automation_name
638
- @automation_name.is_a?(Symbol) ? @automation_name.downcase : @automation_name.downcase.strip.intern
639
- end
713
+ @automation_name = convert_downcase @automation_name if @automation_name
714
+ end
715
+
716
+ # @private
717
+ def convert_downcase(value)
718
+ value.is_a?(Symbol) ? value.downcase : value.downcase.strip.intern
640
719
  end
641
720
 
642
721
  # @private
@@ -650,6 +729,10 @@ module Appium
650
729
 
651
730
  # @private
652
731
  def write_session_id(session_id, export_path = '/tmp/appium_lib_session')
732
+ ::Appium::Logger.warn(
733
+ '[DEPRECATION] export_session option will be removed. ' \
734
+ 'Please save the session id by yourself with #session_id method like @driver.session_id.'
735
+ )
653
736
  export_path = export_path.tr('/', '\\') if ::Appium::Core::Base.platform.windows?
654
737
  File.write(export_path, session_id)
655
738
  rescue IOError => e
@@ -14,7 +14,7 @@
14
14
 
15
15
  module Appium
16
16
  module Core
17
- VERSION = '5.7.0' unless defined? ::Appium::Core::VERSION
18
- DATE = '2022-12-02' unless defined? ::Appium::Core::DATE
17
+ VERSION = '5.8.0' unless defined? ::Appium::Core::VERSION
18
+ DATE = '2022-12-11' unless defined? ::Appium::Core::DATE
19
19
  end
20
20
  end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ module Appium
16
+ module Core
17
+ module Windows
18
+ module Device
19
+ module AppManagement
20
+ # override
21
+ def self.add_methods
22
+ ::Appium::Core::Device.add_endpoint_method(:launch_app) do
23
+ def launch_app
24
+ execute :launch_app
25
+ end
26
+ end
27
+
28
+ ::Appium::Core::Device.add_endpoint_method(:close_app) do
29
+ def close_app
30
+ execute :close_app
31
+ end
32
+ end
33
+ end
34
+ end # module AppManagement
35
+ end # module Device
36
+ end # module Windows
37
+ end # module Core
38
+ end # module Appium
@@ -13,6 +13,7 @@
13
13
  # limitations under the License.
14
14
 
15
15
  require_relative 'device/screen'
16
+ require_relative 'device/app_management'
16
17
 
17
18
  module Appium
18
19
  module Core
@@ -78,6 +79,7 @@ module Appium
78
79
  class << self
79
80
  def extended(_mod)
80
81
  Screen.add_methods
82
+ AppManagement.add_methods
81
83
  end
82
84
  end # class << self
83
85
  end # module Device
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: appium_lib_core
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.7.0
4
+ version: 5.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kazuaki MATSUO
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-12-03 00:00:00.000000000 Z
11
+ date: 2022-12-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: selenium-webdriver
@@ -267,6 +267,7 @@ files:
267
267
  - lib/appium_lib_core/windows.rb
268
268
  - lib/appium_lib_core/windows/bridge.rb
269
269
  - lib/appium_lib_core/windows/device.rb
270
+ - lib/appium_lib_core/windows/device/app_management.rb
270
271
  - lib/appium_lib_core/windows/device/screen.rb
271
272
  homepage: https://github.com/appium/ruby_lib_core/
272
273
  licenses: