playwright-ruby-client 1.38.1 → 1.39.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.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/documentation/docs/api/browser.md +13 -9
  3. data/documentation/docs/api/browser_context.md +51 -32
  4. data/documentation/docs/api/browser_type.md +12 -7
  5. data/documentation/docs/api/dialog.md +18 -15
  6. data/documentation/docs/api/element_handle.md +6 -5
  7. data/documentation/docs/api/frame.md +54 -24
  8. data/documentation/docs/api/locator.md +26 -0
  9. data/documentation/docs/api/page.md +101 -48
  10. data/documentation/docs/api/playwright.md +23 -20
  11. data/documentation/docs/api/selectors.md +34 -29
  12. data/documentation/docs/include/api_coverage.md +0 -43
  13. data/lib/playwright/channel.rb +9 -1
  14. data/lib/playwright/channel_owner.rb +7 -2
  15. data/lib/playwright/channel_owners/browser_context.rb +1 -1
  16. data/lib/playwright/channel_owners/local_utils.rb +27 -0
  17. data/lib/playwright/channel_owners/playwright.rb +1 -24
  18. data/lib/playwright/connection.rb +1 -1
  19. data/lib/playwright/console_message_impl.rb +29 -0
  20. data/lib/playwright/errors.rb +0 -2
  21. data/lib/playwright/javascript/value_serializer.rb +1 -1
  22. data/lib/playwright/locator_impl.rb +5 -24
  23. data/lib/playwright/version.rb +2 -2
  24. data/lib/playwright_api/browser.rb +2 -2
  25. data/lib/playwright_api/browser_context.rb +4 -4
  26. data/lib/playwright_api/browser_type.rb +2 -2
  27. data/lib/playwright_api/console_message.rb +0 -22
  28. data/lib/playwright_api/dialog.rb +2 -2
  29. data/lib/playwright_api/element_handle.rb +1 -1
  30. data/lib/playwright_api/frame.rb +7 -7
  31. data/lib/playwright_api/locator.rb +26 -5
  32. data/lib/playwright_api/page.rb +23 -23
  33. data/lib/playwright_api/playwright.rb +4 -4
  34. data/lib/playwright_api/selectors.rb +2 -2
  35. data/sig/playwright.rbs +0 -43
  36. metadata +4 -8
  37. data/documentation/docs/api/locator_assertions.md +0 -684
  38. data/lib/playwright/channel_owners/console_message.rb +0 -25
  39. data/lib/playwright/locator_assertions_impl.rb +0 -417
  40. data/lib/playwright/test.rb +0 -68
  41. data/lib/playwright_api/locator_assertions.rb +0 -538
@@ -8,19 +8,20 @@ sidebar_position: 10
8
8
  Playwright module provides a method to launch a browser instance. The following is a typical example of using Playwright
9
9
  to drive automation:
10
10
 
11
- ```ruby
12
- require 'playwright'
11
+ ```python sync title=example_6647e5a44b0440884026a6142606dfddad75ba1e643919b015457df4ed2e198f.py
12
+ from playwright.sync_api import sync_playwright, Playwright
13
13
 
14
- Playwright.create(playwright_cli_executable_path: 'npx playwright') do |playwright|
15
- chromium = playwright.chromium # or "firefox" or "webkit".
16
- chromium.launch do |browser|
17
- page = browser.new_page
18
- page.goto('https://example.com/')
14
+ def run(playwright: Playwright):
15
+ chromium = playwright.chromium # or "firefox" or "webkit".
16
+ browser = chromium.launch()
17
+ page = browser.new_page()
18
+ page.goto("http://example.com")
19
+ # other actions...
20
+ browser.close()
19
21
 
20
- # other actions
22
+ with sync_playwright() as playwright:
23
+ run(playwright)
21
24
 
22
- end
23
- end
24
25
  ```
25
26
 
26
27
  ## chromium
@@ -33,20 +34,22 @@ This object can be used to launch or connect to Chromium, returning instances of
33
34
 
34
35
  Returns a dictionary of devices to be used with [Browser#new_context](./browser#new_context) or [Browser#new_page](./browser#new_page).
35
36
 
36
- ```ruby
37
- require 'playwright'
37
+ ```python sync title=example_14d627977a4ad16a605ec5472d768a3324812fa8e7c57685561408fa6601e352.py
38
+ from playwright.sync_api import sync_playwright, Playwright
38
39
 
39
- Playwright.create(playwright_cli_executable_path: 'npx playwright') do |playwright|
40
- iphone = playwright.devices["iPhone 6"]
41
- playwright.webkit.launch do |browser|
40
+ def run(playwright: Playwright):
41
+ webkit = playwright.webkit
42
+ iphone = playwright.devices["iPhone 6"]
43
+ browser = webkit.launch()
42
44
  context = browser.new_context(**iphone)
43
- page = context.new_page
44
- page.goto('https://example.com/')
45
+ page = context.new_page()
46
+ page.goto("http://example.com")
47
+ # other actions...
48
+ browser.close()
45
49
 
46
- # other actions
50
+ with sync_playwright() as playwright:
51
+ run(playwright)
47
52
 
48
- end
49
- end
50
53
  ```
51
54
 
52
55
  ## firefox
@@ -21,33 +21,38 @@ Selectors must be registered before creating the page.
21
21
 
22
22
  An example of registering selector engine that queries elements based on a tag name:
23
23
 
24
- ```ruby
25
- tag_selector = <<~JAVASCRIPT
26
- {
27
- // Returns the first element matching given selector in the root's subtree.
28
- query(root, selector) {
29
- return root.querySelector(selector);
30
- },
31
- // Returns all elements matching given selector in the root's subtree.
32
- queryAll(root, selector) {
33
- return Array.from(root.querySelectorAll(selector));
34
- }
35
- }
36
- JAVASCRIPT
37
-
38
- # Register the engine. Selectors will be prefixed with "tag=".
39
- playwright.selectors.register("tag", script: tag_selector)
40
- playwright.chromium.launch do |browser|
41
- page = browser.new_page
42
- page.content = '<div><button>Click me</button></div>'
43
-
44
- # Use the selector prefixed with its name.
45
- button = page.locator('tag=button')
46
- # Combine it with other selector engines.
47
- page.locator('tag=div').get_by_text('Click me').click
48
-
49
- # Can use it in any methods supporting selectors.
50
- button_count = page.locator('tag=button').count
51
- button_count # => 1
52
- end
24
+ ```python sync title=example_3e739d4f0e30e20a6a698e0e17605a841c35e65e75aa3c2642f8bfc368b33f9e.py
25
+ from playwright.sync_api import sync_playwright, Playwright
26
+
27
+ def run(playwright: Playwright):
28
+ tag_selector = """
29
+ {
30
+ // Returns the first element matching given selector in the root's subtree.
31
+ query(root, selector) {
32
+ return root.querySelector(selector);
33
+ },
34
+ // Returns all elements matching given selector in the root's subtree.
35
+ queryAll(root, selector) {
36
+ return Array.from(root.querySelectorAll(selector));
37
+ }
38
+ }"""
39
+
40
+ # Register the engine. Selectors will be prefixed with "tag=".
41
+ playwright.selectors.register("tag", tag_selector)
42
+ browser = playwright.chromium.launch()
43
+ page = browser.new_page()
44
+ page.set_content('<div><button>Click me</button></div>')
45
+
46
+ # Use the selector prefixed with its name.
47
+ button = page.locator('tag=button')
48
+ # Combine it with built-in locators.
49
+ page.locator('tag=div').get_by_text('Click me').click()
50
+ # Can use it in any methods supporting selectors.
51
+ button_count = page.locator('tag=button').count()
52
+ print(button_count)
53
+ browser.close()
54
+
55
+ with sync_playwright() as playwright:
56
+ run(playwright)
57
+
53
58
  ```
@@ -527,49 +527,6 @@
527
527
 
528
528
  * ~~new_context~~
529
529
 
530
- ## LocatorAssertions
531
-
532
- * not_to_be_attached
533
- * not_to_be_checked
534
- * not_to_be_disabled
535
- * not_to_be_editable
536
- * not_to_be_empty
537
- * not_to_be_enabled
538
- * not_to_be_focused
539
- * not_to_be_hidden
540
- * not_to_be_in_viewport
541
- * not_to_be_visible
542
- * not_to_contain_text
543
- * not_to_have_attribute
544
- * not_to_have_class
545
- * not_to_have_count
546
- * not_to_have_css
547
- * not_to_have_id
548
- * not_to_have_js_property
549
- * not_to_have_text
550
- * not_to_have_value
551
- * not_to_have_values
552
- * to_be_attached
553
- * to_be_checked
554
- * to_be_disabled
555
- * to_be_editable
556
- * to_be_empty
557
- * to_be_enabled
558
- * to_be_focused
559
- * to_be_hidden
560
- * to_be_in_viewport
561
- * to_be_visible
562
- * to_contain_text
563
- * to_have_attribute
564
- * to_have_class
565
- * to_have_count
566
- * to_have_css
567
- * to_have_id
568
- * to_have_js_property
569
- * to_have_text
570
- * to_have_value
571
- * to_have_values
572
-
573
530
  ## Android
574
531
 
575
532
  * ~~connect~~
@@ -30,6 +30,7 @@ module Playwright
30
30
  # @param params [Hash]
31
31
  # @return [Hash]
32
32
  def send_message_to_server_result(method, params)
33
+ check_not_collected
33
34
  with_logging do |metadata|
34
35
  @connection.send_message_to_server(@guid, method, params, metadata: metadata)
35
36
  end
@@ -39,6 +40,7 @@ module Playwright
39
40
  # @param params [Hash]
40
41
  # @returns [Concurrent::Promises::Future]
41
42
  def async_send_message_to_server(method, params = {})
43
+ check_not_collected
42
44
  with_logging do |metadata|
43
45
  @connection.async_send_message_to_server(@guid, method, params, metadata: metadata)
44
46
  end
@@ -46,7 +48,7 @@ module Playwright
46
48
 
47
49
  private def with_logging(&block)
48
50
  locations = caller_locations
49
- first_api_call_location_idx = locations.index { |loc| loc.absolute_path&.include?('playwright_api') }
51
+ first_api_call_location_idx = locations.index { |loc| loc.absolute_path.include?('playwright_api') }
50
52
  unless first_api_call_location_idx
51
53
  return block.call(nil)
52
54
  end
@@ -74,5 +76,11 @@ module Playwright
74
76
  end,
75
77
  }
76
78
  end
79
+
80
+ private def check_not_collected
81
+ if @object.was_collected?
82
+ raise "The object has been collected to prevent unbounded heap growth."
83
+ end
84
+ end
77
85
  end
78
86
  end
@@ -50,13 +50,18 @@ module Playwright
50
50
  child.send(:update_parent, self)
51
51
  end
52
52
 
53
+ def was_collected?
54
+ @was_collected
55
+ end
56
+
53
57
  # used only from Connection. Not intended for public use. So keep private.
54
- private def dispose!
58
+ private def dispose!(reason: nil)
55
59
  # Clean up from parent and connection.
56
60
  @connection.send(:delete_object_from_channel_owner, @guid)
61
+ @was_collected = reason == 'gc'
57
62
 
58
63
  # Dispose all children.
59
- @objects.each_value { |object| object.send(:dispose!) }
64
+ @objects.each_value { |object| object.send(:dispose!, reason: reason) }
60
65
  @objects.clear
61
66
  end
62
67
 
@@ -36,7 +36,7 @@ module Playwright
36
36
  on_service_worker(ChannelOwners::Worker.from(params['worker']))
37
37
  })
38
38
  @channel.on('console', ->(params) {
39
- on_console_message(ChannelOwners::ConsoleMessage.from(params['message']))
39
+ on_console_message(ConsoleMessageImpl.new(params))
40
40
  })
41
41
  @channel.on('pageError', ->(params) {
42
42
  on_page_error(
@@ -1,5 +1,11 @@
1
1
  module Playwright
2
2
  define_channel_owner :LocalUtils do
3
+ def devices
4
+ @devices ||= @initializer['deviceDescriptors'].map do |device|
5
+ [device['name'], parse_device_descriptor(device['descriptor'])]
6
+ end.to_h
7
+ end
8
+
3
9
  # @param zip_file [String]
4
10
  def zip(params)
5
11
  @channel.send_message_to_server('zip', params)
@@ -51,5 +57,26 @@ module Playwright
51
57
  @channel.async_send_message_to_server('addStackToTracingNoReply', callData: { id: id, stack: stack })
52
58
  nil
53
59
  end
60
+
61
+ private def parse_device_descriptor(descriptor)
62
+ # This return value can be passed into Browser#new_context as it is.
63
+ # ex:
64
+ # ```
65
+ # iPhone = playwright.devices['iPhone 6']
66
+ # context = browser.new_context(**iPhone)
67
+ # page = context.new_page
68
+ #
69
+ # ```
70
+ {
71
+ userAgent: descriptor['userAgent'],
72
+ viewport: {
73
+ width: descriptor['viewport']['width'],
74
+ height: descriptor['viewport']['height'],
75
+ },
76
+ deviceScaleFactor: descriptor['deviceScaleFactor'],
77
+ isMobile: descriptor['isMobile'],
78
+ hasTouch: descriptor['hasTouch'],
79
+ }
80
+ end
54
81
  end
55
82
  end
@@ -25,9 +25,7 @@ module Playwright
25
25
  end
26
26
 
27
27
  def devices
28
- @devices ||= @initializer['deviceDescriptors'].map do |item|
29
- [item['name'], parse_device_descriptor(item['descriptor'])]
30
- end.to_h
28
+ @connection.local_utils.devices
31
29
  end
32
30
 
33
31
  # used only from Playwright#connect_to_browser_server
@@ -44,26 +42,5 @@ module Playwright
44
42
  end
45
43
  ::Playwright::ChannelOwners::AndroidDevice.from(@initializer['preConnectedAndroidDevice'])
46
44
  end
47
-
48
- private def parse_device_descriptor(descriptor)
49
- # This return value can be passed into Browser#new_context as it is.
50
- # ex:
51
- # ```
52
- # iPhone = playwright.devices['iPhone 6']
53
- # context = browser.new_context(**iPhone)
54
- # page = context.new_page
55
- #
56
- # ```
57
- {
58
- userAgent: descriptor['userAgent'],
59
- viewport: {
60
- width: descriptor['viewport']['width'],
61
- height: descriptor['viewport']['height'],
62
- },
63
- deviceScaleFactor: descriptor['deviceScaleFactor'],
64
- isMobile: descriptor['isMobile'],
65
- hasTouch: descriptor['hasTouch'],
66
- }
67
- end
68
45
  end
69
46
  end
@@ -181,7 +181,7 @@ module Playwright
181
181
  end
182
182
 
183
183
  if method == "__dispose__"
184
- object.send(:dispose!)
184
+ object.send(:dispose!, reason: params["reason"])
185
185
  return
186
186
  end
187
187
 
@@ -0,0 +1,29 @@
1
+ module Playwright
2
+ define_api_implementation :ConsoleMessageImpl do
3
+ def initialize(event)
4
+ @event = event
5
+ end
6
+
7
+ def page
8
+ @page ||= ChannelOwners::Page.from_nullable(@event['page'])
9
+ end
10
+
11
+ def type
12
+ @event['type']
13
+ end
14
+
15
+ def text
16
+ @event['text']
17
+ end
18
+
19
+ def args
20
+ @event['args']&.map do |arg|
21
+ ChannelOwner.from(arg)
22
+ end
23
+ end
24
+
25
+ def location
26
+ @event['location']
27
+ end
28
+ end
29
+ end
@@ -49,6 +49,4 @@ module Playwright
49
49
 
50
50
  attr_reader :error, :page
51
51
  end
52
-
53
- class AssertionError < StandardError; end
54
52
  end
@@ -24,7 +24,7 @@ module Playwright
24
24
  @handles << value.channel
25
25
  { h: index }
26
26
  when nil
27
- { v: 'null' }
27
+ { v: 'undefined' }
28
28
  when Float::NAN
29
29
  { v: 'NaN'}
30
30
  when Float::INFINITY
@@ -304,7 +304,11 @@ module Playwright
304
304
  end
305
305
 
306
306
  def all
307
- count.times.map { |i| nth(i) }
307
+ Enumerator.new do |out|
308
+ count.times do |i|
309
+ out << nth(i)
310
+ end
311
+ end
308
312
  end
309
313
 
310
314
  def count
@@ -484,28 +488,5 @@ module Playwright
484
488
  def highlight
485
489
  @frame.highlight(@selector)
486
490
  end
487
-
488
- def expect(expression, options)
489
- if options.key?(:expectedValue)
490
- options[:expectedValue] = JavaScript::ValueSerializer
491
- .new(options[:expectedValue])
492
- .serialize
493
- end
494
-
495
- result = @frame.channel.send_message_to_server_result(
496
- "expect",
497
- {
498
- selector: @selector,
499
- expression: expression,
500
- **options,
501
- }
502
- )
503
-
504
- if result.key?('received')
505
- result['received'] = JavaScript::ValueParser.new(result['received']).parse
506
- end
507
-
508
- result
509
- end
510
491
  end
511
492
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Playwright
4
- VERSION = '1.38.1'
5
- COMPATIBLE_PLAYWRIGHT_VERSION = '1.38.1'
4
+ VERSION = '1.39.0'
5
+ COMPATIBLE_PLAYWRIGHT_VERSION = '1.39.0'
6
6
  end
@@ -4,9 +4,9 @@ module Playwright
4
4
  # A Browser is created via [`method: BrowserType.launch`]. An example of using a `Browser` to create a `Page`:
5
5
  #
6
6
  # ```python sync
7
- # from playwright.sync_api import sync_playwright
7
+ # from playwright.sync_api import sync_playwright, Playwright
8
8
  #
9
- # def run(playwright):
9
+ # def run(playwright: Playwright):
10
10
  # firefox = playwright.firefox
11
11
  # browser = firefox.launch()
12
12
  # page = browser.new_page()
@@ -131,9 +131,9 @@ module Playwright
131
131
  # An example of exposing page URL to all frames in all pages in the context:
132
132
  #
133
133
  # ```python sync
134
- # from playwright.sync_api import sync_playwright
134
+ # from playwright.sync_api import sync_playwright, Playwright
135
135
  #
136
- # def run(playwright):
136
+ # def run(playwright: Playwright):
137
137
  # webkit = playwright.webkit
138
138
  # browser = webkit.launch(headless=false)
139
139
  # context = browser.new_context()
@@ -190,13 +190,13 @@ module Playwright
190
190
  # import hashlib
191
191
  # from playwright.sync_api import sync_playwright
192
192
  #
193
- # def sha256(text):
193
+ # def sha256(text: str) -> str:
194
194
  # m = hashlib.sha256()
195
195
  # m.update(bytes(text, "utf8"))
196
196
  # return m.hexdigest()
197
197
  #
198
198
  #
199
- # def run(playwright):
199
+ # def run(playwright: Playwright):
200
200
  # webkit = playwright.webkit
201
201
  # browser = webkit.launch(headless=False)
202
202
  # context = browser.new_context()
@@ -4,9 +4,9 @@ module Playwright
4
4
  # typical example of using Playwright to drive automation:
5
5
  #
6
6
  # ```python sync
7
- # from playwright.sync_api import sync_playwright
7
+ # from playwright.sync_api import sync_playwright, Playwright
8
8
  #
9
- # def run(playwright):
9
+ # def run(playwright: Playwright):
10
10
  # chromium = playwright.chromium
11
11
  # browser = chromium.launch()
12
12
  # page = browser.new_page()
@@ -52,27 +52,5 @@ module Playwright
52
52
  def type
53
53
  wrap_impl(@impl.type)
54
54
  end
55
-
56
- # -- inherited from EventEmitter --
57
- # @nodoc
58
- def off(event, callback)
59
- event_emitter_proxy.off(event, callback)
60
- end
61
-
62
- # -- inherited from EventEmitter --
63
- # @nodoc
64
- def once(event, callback)
65
- event_emitter_proxy.once(event, callback)
66
- end
67
-
68
- # -- inherited from EventEmitter --
69
- # @nodoc
70
- def on(event, callback)
71
- event_emitter_proxy.on(event, callback)
72
- end
73
-
74
- private def event_emitter_proxy
75
- @event_emitter_proxy ||= EventEmitterProxy.new(self, @impl)
76
- end
77
55
  end
78
56
  end
@@ -5,13 +5,13 @@ module Playwright
5
5
  # An example of using `Dialog` class:
6
6
  #
7
7
  # ```python sync
8
- # from playwright.sync_api import sync_playwright
8
+ # from playwright.sync_api import sync_playwright, Playwright
9
9
  #
10
10
  # def handle_dialog(dialog):
11
11
  # print(dialog.message)
12
12
  # dialog.dismiss()
13
13
  #
14
- # def run(playwright):
14
+ # def run(playwright: Playwright):
15
15
  # chromium = playwright.chromium
16
16
  # browser = chromium.launch()
17
17
  # page = browser.new_page()
@@ -407,7 +407,7 @@ module Playwright
407
407
  # **Usage**
408
408
  #
409
409
  # ```python sync
410
- # # single selection matching the value
410
+ # # Single selection matching the value or label
411
411
  # handle.select_option("blue")
412
412
  # # single selection matching both the label
413
413
  # handle.select_option(label="blue")
@@ -11,9 +11,9 @@ module Playwright
11
11
  # An example of dumping frame tree:
12
12
  #
13
13
  # ```python sync
14
- # from playwright.sync_api import sync_playwright
14
+ # from playwright.sync_api import sync_playwright, Playwright
15
15
  #
16
- # def run(playwright):
16
+ # def run(playwright: Playwright):
17
17
  # firefox = playwright.firefox
18
18
  # browser = firefox.launch()
19
19
  # page = browser.new_page()
@@ -757,7 +757,7 @@ module Playwright
757
757
  # **Usage**
758
758
  #
759
759
  # ```python sync
760
- # # single selection matching the value
760
+ # # Single selection matching the value or label
761
761
  # frame.select_option("select#colors", "blue")
762
762
  # # single selection matching both the label
763
763
  # frame.select_option("select#colors", label="blue")
@@ -914,9 +914,9 @@ module Playwright
914
914
  # The [`method: Frame.waitForFunction`] can be used to observe viewport size change:
915
915
  #
916
916
  # ```python sync
917
- # from playwright.sync_api import sync_playwright
917
+ # from playwright.sync_api import sync_playwright, Playwright
918
918
  #
919
- # def run(playwright):
919
+ # def run(playwright: Playwright):
920
920
  # webkit = playwright.webkit
921
921
  # browser = webkit.launch()
922
922
  # page = browser.new_page()
@@ -993,9 +993,9 @@ module Playwright
993
993
  # This method works across navigations:
994
994
  #
995
995
  # ```python sync
996
- # from playwright.sync_api import sync_playwright
996
+ # from playwright.sync_api import sync_playwright, Playwright
997
997
  #
998
- # def run(playwright):
998
+ # def run(playwright: Playwright):
999
999
  # chromium = playwright.chromium
1000
1000
  # browser = chromium.launch()
1001
1001
  # page = browser.new_page()