playwright-ruby-client 1.26.0 → 1.28.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 +4 -4
- data/documentation/docs/api/api_request_context.md +86 -0
- data/documentation/docs/api/browser_context.md +3 -3
- data/documentation/docs/api/download.md +1 -1
- data/documentation/docs/api/element_handle.md +2 -1
- data/documentation/docs/api/file_chooser.md +1 -1
- data/documentation/docs/api/frame.md +151 -4
- data/documentation/docs/api/frame_locator.md +151 -4
- data/documentation/docs/api/js_handle.md +5 -3
- data/documentation/docs/api/keyboard.md +1 -1
- data/documentation/docs/api/locator.md +191 -6
- data/documentation/docs/api/page.md +166 -9
- data/documentation/docs/api/request.md +1 -1
- data/documentation/docs/api/tracing.md +1 -1
- data/documentation/docs/article/guides/rails_integration.md +1 -0
- data/documentation/docs/article/guides/rails_integration_with_null_driver.md +59 -0
- data/documentation/docs/include/api_coverage.md +32 -0
- data/lib/playwright/channel_owner.rb +41 -0
- data/lib/playwright/channel_owners/browser_context.rb +6 -0
- data/lib/playwright/channel_owners/element_handle.rb +8 -1
- data/lib/playwright/channel_owners/frame.rb +6 -0
- data/lib/playwright/channel_owners/page.rb +25 -28
- data/lib/playwright/channel_owners/selectors.rb +4 -0
- data/lib/playwright/connection.rb +4 -1
- data/lib/playwright/frame_locator_impl.rb +6 -2
- data/lib/playwright/locator_impl.rb +21 -31
- data/lib/playwright/locator_utils.rb +136 -0
- data/lib/playwright/utils.rb +6 -0
- data/lib/playwright/version.rb +2 -2
- data/lib/playwright_api/android.rb +12 -6
- data/lib/playwright_api/android_device.rb +6 -6
- data/lib/playwright_api/api_request_context.rb +86 -8
- data/lib/playwright_api/browser.rb +6 -6
- data/lib/playwright_api/browser_context.rb +9 -9
- data/lib/playwright_api/browser_type.rb +6 -6
- data/lib/playwright_api/cdp_session.rb +6 -6
- data/lib/playwright_api/console_message.rb +6 -6
- data/lib/playwright_api/dialog.rb +6 -6
- data/lib/playwright_api/download.rb +1 -1
- data/lib/playwright_api/element_handle.rb +9 -8
- data/lib/playwright_api/file_chooser.rb +1 -1
- data/lib/playwright_api/frame.rb +119 -11
- data/lib/playwright_api/frame_locator.rb +113 -5
- data/lib/playwright_api/js_handle.rb +7 -7
- data/lib/playwright_api/keyboard.rb +1 -1
- data/lib/playwright_api/locator.rb +145 -6
- data/lib/playwright_api/page.rb +133 -16
- data/lib/playwright_api/playwright.rb +6 -6
- data/lib/playwright_api/request.rb +9 -9
- data/lib/playwright_api/response.rb +8 -8
- data/lib/playwright_api/route.rb +6 -6
- data/lib/playwright_api/selectors.rb +14 -3
- data/lib/playwright_api/tracing.rb +7 -7
- data/lib/playwright_api/web_socket.rb +6 -6
- data/lib/playwright_api/worker.rb +8 -8
- metadata +5 -4
| @@ -36,6 +36,7 @@ module Playwright | |
| 36 36 | 
             
                  @type = type
         | 
| 37 37 | 
             
                  @guid = guid
         | 
| 38 38 | 
             
                  @initializer = initializer
         | 
| 39 | 
            +
                  @event_to_subscription_mapping = {}
         | 
| 39 40 |  | 
| 40 41 | 
             
                  after_initialize
         | 
| 41 42 | 
             
                end
         | 
| @@ -59,6 +60,46 @@ module Playwright | |
| 59 60 | 
             
                  @objects.clear
         | 
| 60 61 | 
             
                end
         | 
| 61 62 |  | 
| 63 | 
            +
                private def set_event_to_subscription_mapping(event_to_subscription_mapping)
         | 
| 64 | 
            +
                  @event_to_subscription_mapping = event_to_subscription_mapping
         | 
| 65 | 
            +
                end
         | 
| 66 | 
            +
             | 
| 67 | 
            +
                private def update_subscription(event, enabled)
         | 
| 68 | 
            +
                  protocol_event = @event_to_subscription_mapping[event]
         | 
| 69 | 
            +
                  if protocol_event
         | 
| 70 | 
            +
                    payload = {
         | 
| 71 | 
            +
                      event: protocol_event,
         | 
| 72 | 
            +
                      enabled: enabled,
         | 
| 73 | 
            +
                    }
         | 
| 74 | 
            +
                    @channel.async_send_message_to_server('updateSubscription', payload)
         | 
| 75 | 
            +
                  end
         | 
| 76 | 
            +
                end
         | 
| 77 | 
            +
             | 
| 78 | 
            +
                # @override
         | 
| 79 | 
            +
                def on(event, callback)
         | 
| 80 | 
            +
                  if listener_count(event) == 0
         | 
| 81 | 
            +
                    update_subscription(event, true)
         | 
| 82 | 
            +
                  end
         | 
| 83 | 
            +
                  super
         | 
| 84 | 
            +
                end
         | 
| 85 | 
            +
             | 
| 86 | 
            +
                # @override
         | 
| 87 | 
            +
                def once(event, callback)
         | 
| 88 | 
            +
                  if listener_count(event) == 0
         | 
| 89 | 
            +
                    update_subscription(event, true)
         | 
| 90 | 
            +
                  end
         | 
| 91 | 
            +
                  super
         | 
| 92 | 
            +
                end
         | 
| 93 | 
            +
             | 
| 94 | 
            +
                # @override
         | 
| 95 | 
            +
                def off(event, callback)
         | 
| 96 | 
            +
                  super
         | 
| 97 | 
            +
                  if listener_count(event) == 0
         | 
| 98 | 
            +
                    update_subscription(event, false)
         | 
| 99 | 
            +
                  end
         | 
| 100 | 
            +
                end
         | 
| 101 | 
            +
             | 
| 102 | 
            +
             | 
| 62 103 | 
             
                # Suppress long long inspect log and avoid RSpec from hanging up...
         | 
| 63 104 | 
             
                def inspect
         | 
| 64 105 | 
             
                  to_s
         | 
| @@ -58,6 +58,12 @@ module Playwright | |
| 58 58 | 
             
                      ChannelOwners::Page.from_nullable(params['page']),
         | 
| 59 59 | 
             
                    )
         | 
| 60 60 | 
             
                  })
         | 
| 61 | 
            +
                  set_event_to_subscription_mapping({
         | 
| 62 | 
            +
                    Events::BrowserContext::Request => "request",
         | 
| 63 | 
            +
                    Events::BrowserContext::Response => "response",
         | 
| 64 | 
            +
                    Events::BrowserContext::RequestFinished => "requestFinished",
         | 
| 65 | 
            +
                    Events::BrowserContext::RequestFailed => "requestFailed",
         | 
| 66 | 
            +
                  })
         | 
| 61 67 |  | 
| 62 68 | 
             
                  @closed_promise = Concurrent::Promises.resolvable_future
         | 
| 63 69 | 
             
                end
         | 
| @@ -76,10 +76,17 @@ module Playwright | |
| 76 76 | 
             
                    nil
         | 
| 77 77 | 
             
                  end
         | 
| 78 78 |  | 
| 79 | 
            -
                  def hover( | 
| 79 | 
            +
                  def hover(
         | 
| 80 | 
            +
                        force: nil,
         | 
| 81 | 
            +
                        modifiers: nil,
         | 
| 82 | 
            +
                        noWaitAfter: nil,
         | 
| 83 | 
            +
                        position: nil,
         | 
| 84 | 
            +
                        timeout: nil,
         | 
| 85 | 
            +
                        trial: nil)
         | 
| 80 86 | 
             
                    params = {
         | 
| 81 87 | 
             
                      force: force,
         | 
| 82 88 | 
             
                      modifiers: modifiers,
         | 
| 89 | 
            +
                      noWaitAfter: noWaitAfter,
         | 
| 83 90 | 
             
                      position: position,
         | 
| 84 91 | 
             
                      timeout: timeout,
         | 
| 85 92 | 
             
                      trial: trial,
         | 
| @@ -1,6 +1,10 @@ | |
| 1 | 
            +
            require_relative '../locator_utils'
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            module Playwright
         | 
| 2 4 | 
             
              # @ref https://github.com/microsoft/playwright-python/blob/master/playwright/_impl/_frame.py
         | 
| 3 5 | 
             
              define_channel_owner :Frame do
         | 
| 6 | 
            +
                include LocatorUtils
         | 
| 7 | 
            +
             | 
| 4 8 | 
             
                private def after_initialize
         | 
| 5 9 | 
             
                  if @initializer['parentFrame']
         | 
| 6 10 | 
             
                    @parent_frame = ChannelOwners::Frame.from(@initializer['parentFrame'])
         | 
| @@ -457,6 +461,7 @@ module Playwright | |
| 457 461 | 
             
                      selector,
         | 
| 458 462 | 
             
                      force: nil,
         | 
| 459 463 | 
             
                      modifiers: nil,
         | 
| 464 | 
            +
                      noWaitAfter: nil,
         | 
| 460 465 | 
             
                      position: nil,
         | 
| 461 466 | 
             
                      strict: nil,
         | 
| 462 467 | 
             
                      timeout: nil,
         | 
| @@ -465,6 +470,7 @@ module Playwright | |
| 465 470 | 
             
                    selector: selector,
         | 
| 466 471 | 
             
                    force: force,
         | 
| 467 472 | 
             
                    modifiers: modifiers,
         | 
| 473 | 
            +
                    noWaitAfter: noWaitAfter,
         | 
| 468 474 | 
             
                    position: position,
         | 
| 469 475 | 
             
                    strict: strict,
         | 
| 470 476 | 
             
                    timeout: timeout,
         | 
| @@ -1,11 +1,14 @@ | |
| 1 1 | 
             
            require 'base64'
         | 
| 2 | 
            +
            require_relative '../locator_utils'
         | 
| 2 3 |  | 
| 3 4 | 
             
            module Playwright
         | 
| 4 5 | 
             
              # @ref https://github.com/microsoft/playwright-python/blob/master/playwright/_impl/_page.py
         | 
| 5 6 | 
             
              define_channel_owner :Page do
         | 
| 6 7 | 
             
                include Utils::Errors::SafeCloseError
         | 
| 8 | 
            +
                include LocatorUtils
         | 
| 7 9 | 
             
                attr_writer :owned_context
         | 
| 8 10 |  | 
| 11 | 
            +
             | 
| 9 12 | 
             
                private def after_initialize
         | 
| 10 13 | 
             
                  @browser_context = @parent
         | 
| 11 14 | 
             
                  @timeout_settings = TimeoutSettings.new(@browser_context.send(:_timeout_settings))
         | 
| @@ -71,6 +74,14 @@ module Playwright | |
| 71 74 | 
             
                    worker = ChannelOwners::Worker.from(params['worker'])
         | 
| 72 75 | 
             
                    on_worker(worker)
         | 
| 73 76 | 
             
                  })
         | 
| 77 | 
            +
             | 
| 78 | 
            +
                  set_event_to_subscription_mapping({
         | 
| 79 | 
            +
                    Events::Page::Request => "request",
         | 
| 80 | 
            +
                    Events::Page::Response => "response",
         | 
| 81 | 
            +
                    Events::Page::RequestFinished => "requestFinished",
         | 
| 82 | 
            +
                    Events::Page::RequestFailed => "requestFailed",
         | 
| 83 | 
            +
                    Events::Page::FileChooser => "fileChooser",
         | 
| 84 | 
            +
                  })
         | 
| 74 85 | 
             
                end
         | 
| 75 86 |  | 
| 76 87 | 
             
                attr_reader \
         | 
| @@ -167,30 +178,6 @@ module Playwright | |
| 167 178 | 
             
                  video.send(:set_artifact, artifact)
         | 
| 168 179 | 
             
                end
         | 
| 169 180 |  | 
| 170 | 
            -
                # @override
         | 
| 171 | 
            -
                def on(event, callback)
         | 
| 172 | 
            -
                  if event == Events::Page::FileChooser && listener_count(event) == 0
         | 
| 173 | 
            -
                    @channel.async_send_message_to_server('setFileChooserInterceptedNoReply', intercepted: true)
         | 
| 174 | 
            -
                  end
         | 
| 175 | 
            -
                  super
         | 
| 176 | 
            -
                end
         | 
| 177 | 
            -
             | 
| 178 | 
            -
                # @override
         | 
| 179 | 
            -
                def once(event, callback)
         | 
| 180 | 
            -
                  if event == Events::Page::FileChooser && listener_count(event) == 0
         | 
| 181 | 
            -
                    @channel.async_send_message_to_server('setFileChooserInterceptedNoReply', intercepted: true)
         | 
| 182 | 
            -
                  end
         | 
| 183 | 
            -
                  super
         | 
| 184 | 
            -
                end
         | 
| 185 | 
            -
             | 
| 186 | 
            -
                # @override
         | 
| 187 | 
            -
                def off(event, callback)
         | 
| 188 | 
            -
                  super
         | 
| 189 | 
            -
                  if event == Events::Page::FileChooser && listener_count(event) == 0
         | 
| 190 | 
            -
                    @channel.async_send_message_to_server('setFileChooserInterceptedNoReply', intercepted: false)
         | 
| 191 | 
            -
                  end
         | 
| 192 | 
            -
                end
         | 
| 193 | 
            -
             | 
| 194 181 | 
             
                def context
         | 
| 195 182 | 
             
                  @browser_context
         | 
| 196 183 | 
             
                end
         | 
| @@ -364,16 +351,24 @@ module Playwright | |
| 364 351 |  | 
| 365 352 | 
             
                def emulate_media(colorScheme: nil, forcedColors: nil, media: nil, reducedMotion: nil)
         | 
| 366 353 | 
             
                  params = {
         | 
| 367 | 
            -
                    colorScheme: colorScheme,
         | 
| 368 | 
            -
                    forcedColors: forcedColors,
         | 
| 369 | 
            -
                    media: media,
         | 
| 370 | 
            -
                    reducedMotion: reducedMotion,
         | 
| 354 | 
            +
                    colorScheme: no_override_if_null(colorScheme),
         | 
| 355 | 
            +
                    forcedColors: no_override_if_null(forcedColors),
         | 
| 356 | 
            +
                    media: no_override_if_null(media),
         | 
| 357 | 
            +
                    reducedMotion: no_override_if_null(reducedMotion),
         | 
| 371 358 | 
             
                  }.compact
         | 
| 372 359 | 
             
                  @channel.send_message_to_server('emulateMedia', params)
         | 
| 373 360 |  | 
| 374 361 | 
             
                  nil
         | 
| 375 362 | 
             
                end
         | 
| 376 363 |  | 
| 364 | 
            +
                private def no_override_if_null(target)
         | 
| 365 | 
            +
                  if target == 'null'
         | 
| 366 | 
            +
                    'no-override'
         | 
| 367 | 
            +
                  else
         | 
| 368 | 
            +
                    target
         | 
| 369 | 
            +
                  end
         | 
| 370 | 
            +
                end
         | 
| 371 | 
            +
             | 
| 377 372 | 
             
                def set_viewport_size(viewportSize)
         | 
| 378 373 | 
             
                  @viewport_size = viewportSize
         | 
| 379 374 | 
             
                  @channel.send_message_to_server('setViewportSize', { viewportSize: viewportSize })
         | 
| @@ -635,6 +630,7 @@ module Playwright | |
| 635 630 | 
             
                      selector,
         | 
| 636 631 | 
             
                      force: nil,
         | 
| 637 632 | 
             
                      modifiers: nil,
         | 
| 633 | 
            +
                      noWaitAfter: nil,
         | 
| 638 634 | 
             
                      position: nil,
         | 
| 639 635 | 
             
                      strict: nil,
         | 
| 640 636 | 
             
                      timeout: nil,
         | 
| @@ -643,6 +639,7 @@ module Playwright | |
| 643 639 | 
             
                    selector,
         | 
| 644 640 | 
             
                    force: force,
         | 
| 645 641 | 
             
                    modifiers: modifiers,
         | 
| 642 | 
            +
                    noWaitAfter: noWaitAfter,
         | 
| 646 643 | 
             
                    position: position,
         | 
| 647 644 | 
             
                    strict: strict,
         | 
| 648 645 | 
             
                    timeout: timeout,
         | 
| @@ -43,7 +43,10 @@ module Playwright | |
| 43 43 | 
             
                end
         | 
| 44 44 |  | 
| 45 45 | 
             
                def initialize_playwright
         | 
| 46 | 
            -
                   | 
| 46 | 
            +
                  # Avoid Error: sdkLanguage: expected one of (javascript|python|java|csharp)
         | 
| 47 | 
            +
                  # ref: https://github.com/microsoft/playwright/pull/18308
         | 
| 48 | 
            +
                  # ref: https://github.com/YusukeIwaki/playwright-ruby-client/issues/228
         | 
| 49 | 
            +
                  result = send_message_to_server('', 'initialize', { sdkLanguage: 'python' })
         | 
| 47 50 | 
             
                  ChannelOwners::Playwright.from(result['playwright'])
         | 
| 48 51 | 
             
                end
         | 
| 49 52 |  | 
| @@ -1,5 +1,9 @@ | |
| 1 | 
            +
            require_relative './locator_utils'
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            module Playwright
         | 
| 2 4 | 
             
              define_api_implementation :FrameLocatorImpl do
         | 
| 5 | 
            +
                include LocatorUtils
         | 
| 6 | 
            +
             | 
| 3 7 | 
             
                def initialize(frame:, timeout_settings:, frame_selector:)
         | 
| 4 8 | 
             
                  @frame = frame
         | 
| 5 9 | 
             
                  @timeout_settings = timeout_settings
         | 
| @@ -10,7 +14,7 @@ module Playwright | |
| 10 14 | 
             
                  LocatorImpl.new(
         | 
| 11 15 | 
             
                    frame: @frame,
         | 
| 12 16 | 
             
                    timeout_settings: @timeout_settings,
         | 
| 13 | 
            -
                    selector: "#{@frame_selector} >> control=enter-frame >> #{selector}",
         | 
| 17 | 
            +
                    selector: "#{@frame_selector} >> internal:control=enter-frame >> #{selector}",
         | 
| 14 18 | 
             
                    hasText: hasText,
         | 
| 15 19 | 
             
                    has: has,
         | 
| 16 20 | 
             
                  )
         | 
| @@ -20,7 +24,7 @@ module Playwright | |
| 20 24 | 
             
                  FrameLocatorImpl.new(
         | 
| 21 25 | 
             
                    frame: @frame,
         | 
| 22 26 | 
             
                    timeout_settings: @timeout_settings,
         | 
| 23 | 
            -
                    frame_selector: "#{@frame_selector} >> control=enter-frame >> #{selector}",
         | 
| 27 | 
            +
                    frame_selector: "#{@frame_selector} >> internal:control=enter-frame >> #{selector}",
         | 
| 24 28 | 
             
                  )
         | 
| 25 29 | 
             
                end
         | 
| 26 30 |  | 
| @@ -1,49 +1,24 @@ | |
| 1 1 | 
             
            require 'json'
         | 
| 2 | 
            +
            require_relative './locator_utils'
         | 
| 2 3 |  | 
| 3 4 | 
             
            module Playwright
         | 
| 4 | 
            -
              class EscapeWithQuotes
         | 
| 5 | 
            -
                def initialize(text, char = "'")
         | 
| 6 | 
            -
                  stringified = text.to_json
         | 
| 7 | 
            -
                  escaped_text = stringified[1...-1].gsub(/\\"/, '"')
         | 
| 8 | 
            -
             | 
| 9 | 
            -
                  case char
         | 
| 10 | 
            -
                  when '"'
         | 
| 11 | 
            -
                    text = escaped_text.gsub(/["]/, '\\"')
         | 
| 12 | 
            -
                    @text = "\"#{text}\""
         | 
| 13 | 
            -
                  when "'"
         | 
| 14 | 
            -
                    text = escaped_text.gsub(/[']/, '\\\'')
         | 
| 15 | 
            -
                    @text = "'#{text}'"
         | 
| 16 | 
            -
                  else
         | 
| 17 | 
            -
                    raise ArgumentError.new('Invalid escape char')
         | 
| 18 | 
            -
                  end
         | 
| 19 | 
            -
                end
         | 
| 20 | 
            -
             | 
| 21 | 
            -
                def to_s
         | 
| 22 | 
            -
                  @text
         | 
| 23 | 
            -
                end
         | 
| 24 | 
            -
              end
         | 
| 25 | 
            -
             | 
| 26 5 | 
             
              define_api_implementation :LocatorImpl do
         | 
| 6 | 
            +
                include LocatorUtils
         | 
| 7 | 
            +
             | 
| 27 8 | 
             
                def initialize(frame:, timeout_settings:, selector:, hasText: nil, has: nil)
         | 
| 28 9 | 
             
                  @frame = frame
         | 
| 29 10 | 
             
                  @timeout_settings = timeout_settings
         | 
| 30 11 | 
             
                  selector_scopes = [selector]
         | 
| 31 12 |  | 
| 32 | 
            -
                   | 
| 33 | 
            -
             | 
| 34 | 
            -
                    regex = JavaScript::Regex.new(hasText)
         | 
| 35 | 
            -
                    source = EscapeWithQuotes.new(regex.source, '"')
         | 
| 36 | 
            -
                    selector_scopes << "has=#{"text=/#{regex.source}/#{regex.flag}".to_json}"
         | 
| 37 | 
            -
                  when String
         | 
| 38 | 
            -
                    text = EscapeWithQuotes.new(hasText, '"')
         | 
| 39 | 
            -
                    selector_scopes << ":scope:has-text(#{text})"
         | 
| 13 | 
            +
                  if hasText
         | 
| 14 | 
            +
                    selector_scopes << "internal:has-text=#{escape_for_text_selector(hasText, false)}"
         | 
| 40 15 | 
             
                  end
         | 
| 41 16 |  | 
| 42 17 | 
             
                  if has
         | 
| 43 18 | 
             
                    unless same_frame?(has)
         | 
| 44 19 | 
             
                      raise DifferentFrameError.new
         | 
| 45 20 | 
             
                    end
         | 
| 46 | 
            -
                    selector_scopes << "has=#{has.send(:selector_json)}"
         | 
| 21 | 
            +
                    selector_scopes << "internal:has=#{has.send(:selector_json)}"
         | 
| 47 22 | 
             
                  end
         | 
| 48 23 |  | 
| 49 24 | 
             
                  @selector = selector_scopes.join(' >> ')
         | 
| @@ -211,6 +186,10 @@ module Playwright | |
| 211 186 | 
             
                  @frame.fill(@selector, value, strict: true, force: force, noWaitAfter: noWaitAfter, timeout: timeout)
         | 
| 212 187 | 
             
                end
         | 
| 213 188 |  | 
| 189 | 
            +
                def clear(force: nil, noWaitAfter: nil, timeout: nil)
         | 
| 190 | 
            +
                  @frame.fill(@selector, '', strict: true, force: force, noWaitAfter: noWaitAfter, timeout: timeout)
         | 
| 191 | 
            +
                end
         | 
| 192 | 
            +
             | 
| 214 193 | 
             
                def locator(selector, hasText: nil, has: nil)
         | 
| 215 194 | 
             
                  LocatorImpl.new(
         | 
| 216 195 | 
             
                    frame: @frame,
         | 
| @@ -275,6 +254,15 @@ module Playwright | |
| 275 254 | 
             
                  @frame.focus(@selector, strict: true, timeout: timeout)
         | 
| 276 255 | 
             
                end
         | 
| 277 256 |  | 
| 257 | 
            +
                def blur(timeout: nil)
         | 
| 258 | 
            +
                  params = {
         | 
| 259 | 
            +
                    selector: @selector,
         | 
| 260 | 
            +
                    strict: true,
         | 
| 261 | 
            +
                    timeout: timeout,
         | 
| 262 | 
            +
                  }.compact
         | 
| 263 | 
            +
                  @frame.channel.send_message_to_server('blur', params)
         | 
| 264 | 
            +
                end
         | 
| 265 | 
            +
             | 
| 278 266 | 
             
                def count
         | 
| 279 267 | 
             
                  @frame.eval_on_selector_all(@selector, 'ee => ee.length')
         | 
| 280 268 | 
             
                end
         | 
| @@ -286,6 +274,7 @@ module Playwright | |
| 286 274 | 
             
                def hover(
         | 
| 287 275 | 
             
                      force: nil,
         | 
| 288 276 | 
             
                      modifiers: nil,
         | 
| 277 | 
            +
                      noWaitAfter: nil,
         | 
| 289 278 | 
             
                      position: nil,
         | 
| 290 279 | 
             
                      timeout: nil,
         | 
| 291 280 | 
             
                      trial: nil)
         | 
| @@ -293,6 +282,7 @@ module Playwright | |
| 293 282 | 
             
                    strict: true,
         | 
| 294 283 | 
             
                    force: force,
         | 
| 295 284 | 
             
                    modifiers: modifiers,
         | 
| 285 | 
            +
                    noWaitAfter: noWaitAfter,
         | 
| 296 286 | 
             
                    position: position,
         | 
| 297 287 | 
             
                    timeout: timeout,
         | 
| 298 288 | 
             
                    trial: trial)
         | 
| @@ -0,0 +1,136 @@ | |
| 1 | 
            +
            require 'json'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Playwright
         | 
| 4 | 
            +
              module LocatorUtils
         | 
| 5 | 
            +
                def get_by_test_id(test_id)
         | 
| 6 | 
            +
                  test_id_attribute_name = ::Playwright::LocatorUtils.instance_variable_get(:@test_id_attribute_name)
         | 
| 7 | 
            +
                  locator(get_by_test_id_selector(test_id_attribute_name, test_id))
         | 
| 8 | 
            +
                end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                def get_by_alt_text(text, exact: false)
         | 
| 11 | 
            +
                  locator(get_by_alt_text_selector(text, exact: exact))
         | 
| 12 | 
            +
                end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                def get_by_label(text, exact: false)
         | 
| 15 | 
            +
                  locator(get_by_label_selector(text, exact: exact))
         | 
| 16 | 
            +
                end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                def get_by_placeholder(text, exact: false)
         | 
| 19 | 
            +
                  locator(get_by_placeholder_selector(text, exact: exact))
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                def get_by_text(text, exact: false)
         | 
| 23 | 
            +
                  locator(get_by_text_selector(text, exact: exact))
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                def get_by_title(text, exact: false)
         | 
| 27 | 
            +
                  locator(get_by_title_selector(text, exact: exact))
         | 
| 28 | 
            +
                end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                def get_by_role(role, **options)
         | 
| 31 | 
            +
                  locator(get_by_role_selector(role, **(options.compact)))
         | 
| 32 | 
            +
                end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                # set from Playwright::Selectors#test_id_attribute=
         | 
| 35 | 
            +
                @test_id_attribute_name = 'data-testid'
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                private def get_by_attribute_text_selector(attr_name, text, exact: false)
         | 
| 38 | 
            +
                  "internal:attr=[#{attr_name}=#{escape_for_attribute_selector_or_regex(text, exact)}]"
         | 
| 39 | 
            +
                end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                private def get_by_test_id_selector(test_id_attribute_name, test_id)
         | 
| 42 | 
            +
                  "internal:testid=[#{test_id_attribute_name}=#{escape_for_attribute_selector(test_id, true)}]"
         | 
| 43 | 
            +
                end
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                private def get_by_label_selector(text, exact:)
         | 
| 46 | 
            +
                  "internal:label=#{escape_for_text_selector(text, exact)}"
         | 
| 47 | 
            +
                end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                private def get_by_alt_text_selector(text, exact:)
         | 
| 50 | 
            +
                  get_by_attribute_text_selector('alt', text, exact: exact)
         | 
| 51 | 
            +
                end
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                private def get_by_title_selector(text, exact:)
         | 
| 54 | 
            +
                  get_by_attribute_text_selector('title', text, exact: exact)
         | 
| 55 | 
            +
                end
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                private def get_by_placeholder_selector(text, exact:)
         | 
| 58 | 
            +
                  get_by_attribute_text_selector('placeholder', text, exact: exact)
         | 
| 59 | 
            +
                end
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                private def get_by_text_selector(text, exact:)
         | 
| 62 | 
            +
                  "internal:text=#{escape_for_text_selector(text, exact)}"
         | 
| 63 | 
            +
                end
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                private def get_by_role_selector(role, **options)
         | 
| 66 | 
            +
                  props = []
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                  ex = {
         | 
| 69 | 
            +
                    includeHidden: -> (value) { ['include-hidden', value.to_s] },
         | 
| 70 | 
            +
                    name: -> (value) { ['name', escape_for_attribute_selector_or_regex(value, options[:exact])]},
         | 
| 71 | 
            +
                  }
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                  %i[
         | 
| 74 | 
            +
                    checked
         | 
| 75 | 
            +
                    disabled
         | 
| 76 | 
            +
                    selected
         | 
| 77 | 
            +
                    expanded
         | 
| 78 | 
            +
                    includeHidden
         | 
| 79 | 
            +
                    level
         | 
| 80 | 
            +
                    name
         | 
| 81 | 
            +
                    pressed
         | 
| 82 | 
            +
                  ].each do |attr_name|
         | 
| 83 | 
            +
                    if options.key?(attr_name)
         | 
| 84 | 
            +
                      attr_value = options[attr_name]
         | 
| 85 | 
            +
                      props << (ex[attr_name]&.call(attr_value) || [attr_name, attr_value.to_s])
         | 
| 86 | 
            +
                    end
         | 
| 87 | 
            +
                  end
         | 
| 88 | 
            +
             | 
| 89 | 
            +
                  opts = props.map { |k, v| "[#{k}=#{v}]"}.join('')
         | 
| 90 | 
            +
                  "internal:role=#{role}#{opts}"
         | 
| 91 | 
            +
                end
         | 
| 92 | 
            +
             | 
| 93 | 
            +
                # @param text [String]
         | 
| 94 | 
            +
                private def escape_for_regex(text)
         | 
| 95 | 
            +
                  text.gsub(/[.*+?^>${}()|\[\]\\]/) { "\\#{$&}" }
         | 
| 96 | 
            +
                end
         | 
| 97 | 
            +
             | 
| 98 | 
            +
                # @param text [Regexp|String]
         | 
| 99 | 
            +
                private def escape_for_text_selector(text, exact)
         | 
| 100 | 
            +
                  if text.is_a?(Regexp)
         | 
| 101 | 
            +
                    regex = JavaScript::Regex.new(text)
         | 
| 102 | 
            +
                    return "/#{regex.source}/#{regex.flag}"
         | 
| 103 | 
            +
                  end
         | 
| 104 | 
            +
             | 
| 105 | 
            +
                  if exact
         | 
| 106 | 
            +
                    "#{text.to_json}s"
         | 
| 107 | 
            +
                  else
         | 
| 108 | 
            +
                    "#{text.to_json}i"
         | 
| 109 | 
            +
                  end
         | 
| 110 | 
            +
                end
         | 
| 111 | 
            +
             | 
| 112 | 
            +
                # @param text [Regexp|String]
         | 
| 113 | 
            +
                private def escape_for_attribute_selector_or_regex(text, exact)
         | 
| 114 | 
            +
                  if text.is_a?(Regexp)
         | 
| 115 | 
            +
                    regex = JavaScript::Regex.new(text)
         | 
| 116 | 
            +
                    "/#{regex.source}/#{regex.flag}"
         | 
| 117 | 
            +
                  else
         | 
| 118 | 
            +
                    escape_for_attribute_selector(text, exact)
         | 
| 119 | 
            +
                  end
         | 
| 120 | 
            +
                end
         | 
| 121 | 
            +
             | 
| 122 | 
            +
                # @param text [String]
         | 
| 123 | 
            +
                private def escape_for_attribute_selector(text, exact)
         | 
| 124 | 
            +
                  # TODO: this should actually be
         | 
| 125 | 
            +
                  # cssEscape(value).replace(/\\ /g, ' ')
         | 
| 126 | 
            +
                  # However, our attribute selectors do not conform to CSS parsing spec,
         | 
| 127 | 
            +
                  # so we escape them differently.
         | 
| 128 | 
            +
                  _text = text.gsub(/["]/, '\\"')
         | 
| 129 | 
            +
                  if exact
         | 
| 130 | 
            +
                    "\"#{_text}\""
         | 
| 131 | 
            +
                  else
         | 
| 132 | 
            +
                    "\"#{_text}\"i"
         | 
| 133 | 
            +
                  end
         | 
| 134 | 
            +
                end
         | 
| 135 | 
            +
              end
         | 
| 136 | 
            +
            end
         | 
    
        data/lib/playwright/utils.rb
    CHANGED
    
    | @@ -55,6 +55,12 @@ module Playwright | |
| 55 55 | 
             
                      params[:storageState] = JSON.parse(File.read(params[:storageState]))
         | 
| 56 56 | 
             
                    end
         | 
| 57 57 |  | 
| 58 | 
            +
                    %i[colorScheme reducedMotion forcedColors].each do |key|
         | 
| 59 | 
            +
                      if params[key] == 'null'
         | 
| 60 | 
            +
                        params[key] = 'no-override'
         | 
| 61 | 
            +
                      end
         | 
| 62 | 
            +
                    end
         | 
| 63 | 
            +
             | 
| 58 64 | 
             
                    params
         | 
| 59 65 | 
             
                  end
         | 
| 60 66 | 
             
                end
         | 
    
        data/lib/playwright/version.rb
    CHANGED
    
    
| @@ -25,6 +25,12 @@ module Playwright | |
| 25 25 | 
             
              # ```
         | 
| 26 26 | 
             
              class Android < PlaywrightApi
         | 
| 27 27 |  | 
| 28 | 
            +
                # This methods attaches Playwright to an existing Android device. Use [`method: Android.launchServer`] to launch a new
         | 
| 29 | 
            +
                # Android server instance.
         | 
| 30 | 
            +
                def connect(wsEndpoint, headers: nil, slowMo: nil, timeout: nil)
         | 
| 31 | 
            +
                  raise NotImplementedError.new('connect is not implemented yet.')
         | 
| 32 | 
            +
                end
         | 
| 33 | 
            +
             | 
| 28 34 | 
             
                # Returns the list of detected Android devices.
         | 
| 29 35 | 
             
                def devices(host: nil, omitDriverInstall: nil, port: nil)
         | 
| 30 36 | 
             
                  wrap_impl(@impl.devices(host: unwrap_impl(host), omitDriverInstall: unwrap_impl(omitDriverInstall), port: unwrap_impl(port)))
         | 
| @@ -36,12 +42,6 @@ module Playwright | |
| 36 42 | 
             
                end
         | 
| 37 43 | 
             
                alias_method :default_timeout=, :set_default_timeout
         | 
| 38 44 |  | 
| 39 | 
            -
                # -- inherited from EventEmitter --
         | 
| 40 | 
            -
                # @nodoc
         | 
| 41 | 
            -
                def off(event, callback)
         | 
| 42 | 
            -
                  event_emitter_proxy.off(event, callback)
         | 
| 43 | 
            -
                end
         | 
| 44 | 
            -
             | 
| 45 45 | 
             
                # -- inherited from EventEmitter --
         | 
| 46 46 | 
             
                # @nodoc
         | 
| 47 47 | 
             
                def once(event, callback)
         | 
| @@ -54,6 +54,12 @@ module Playwright | |
| 54 54 | 
             
                  event_emitter_proxy.on(event, callback)
         | 
| 55 55 | 
             
                end
         | 
| 56 56 |  | 
| 57 | 
            +
                # -- inherited from EventEmitter --
         | 
| 58 | 
            +
                # @nodoc
         | 
| 59 | 
            +
                def off(event, callback)
         | 
| 60 | 
            +
                  event_emitter_proxy.off(event, callback)
         | 
| 61 | 
            +
                end
         | 
| 62 | 
            +
             | 
| 57 63 | 
             
                private def event_emitter_proxy
         | 
| 58 64 | 
             
                  @event_emitter_proxy ||= EventEmitterProxy.new(self, @impl)
         | 
| 59 65 | 
             
                end
         | 
| @@ -173,12 +173,6 @@ module Playwright | |
| 173 173 | 
             
                  wrap_impl(@impl.tap_on(unwrap_impl(selector), duration: unwrap_impl(duration), timeout: unwrap_impl(timeout)))
         | 
| 174 174 | 
             
                end
         | 
| 175 175 |  | 
| 176 | 
            -
                # -- inherited from EventEmitter --
         | 
| 177 | 
            -
                # @nodoc
         | 
| 178 | 
            -
                def off(event, callback)
         | 
| 179 | 
            -
                  event_emitter_proxy.off(event, callback)
         | 
| 180 | 
            -
                end
         | 
| 181 | 
            -
             | 
| 182 176 | 
             
                # -- inherited from EventEmitter --
         | 
| 183 177 | 
             
                # @nodoc
         | 
| 184 178 | 
             
                def once(event, callback)
         | 
| @@ -191,6 +185,12 @@ module Playwright | |
| 191 185 | 
             
                  event_emitter_proxy.on(event, callback)
         | 
| 192 186 | 
             
                end
         | 
| 193 187 |  | 
| 188 | 
            +
                # -- inherited from EventEmitter --
         | 
| 189 | 
            +
                # @nodoc
         | 
| 190 | 
            +
                def off(event, callback)
         | 
| 191 | 
            +
                  event_emitter_proxy.off(event, callback)
         | 
| 192 | 
            +
                end
         | 
| 193 | 
            +
             | 
| 194 194 | 
             
                private def event_emitter_proxy
         | 
| 195 195 | 
             
                  @event_emitter_proxy ||= EventEmitterProxy.new(self, @impl)
         | 
| 196 196 | 
             
                end
         |