playwright-ruby-client 1.37.1 → 1.38.1

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 (36) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +13 -7
  3. data/documentation/docs/api/download.md +17 -7
  4. data/documentation/docs/api/element_handle.md +1 -14
  5. data/documentation/docs/api/frame.md +1 -6
  6. data/documentation/docs/api/keyboard.md +4 -0
  7. data/documentation/docs/api/locator.md +31 -16
  8. data/documentation/docs/api/locator_assertions.md +684 -0
  9. data/documentation/docs/api/page.md +1 -6
  10. data/documentation/docs/api/request.md +17 -0
  11. data/documentation/docs/include/api_coverage.md +44 -0
  12. data/lib/playwright/channel.rb +1 -1
  13. data/lib/playwright/channel_owners/browser_context.rb +15 -0
  14. data/lib/playwright/channel_owners/page.rb +2 -0
  15. data/lib/playwright/channel_owners/request.rb +17 -1
  16. data/lib/playwright/channel_owners/route.rb +5 -1
  17. data/lib/playwright/errors.rb +15 -2
  18. data/lib/playwright/events.rb +1 -0
  19. data/lib/playwright/javascript/value_parser.rb +8 -0
  20. data/lib/playwright/javascript/value_serializer.rb +11 -5
  21. data/lib/playwright/locator_assertions_impl.rb +417 -0
  22. data/lib/playwright/locator_impl.rb +28 -5
  23. data/lib/playwright/test.rb +68 -0
  24. data/lib/playwright/utils.rb +4 -0
  25. data/lib/playwright/version.rb +2 -2
  26. data/lib/playwright_api/download.rb +12 -3
  27. data/lib/playwright_api/element_handle.rb +1 -14
  28. data/lib/playwright_api/frame.rb +1 -6
  29. data/lib/playwright_api/keyboard.rb +4 -0
  30. data/lib/playwright_api/locator.rb +31 -16
  31. data/lib/playwright_api/locator_assertions.rb +538 -0
  32. data/lib/playwright_api/page.rb +1 -6
  33. data/lib/playwright_api/request.rb +17 -0
  34. data/lib/playwright_api/worker.rb +4 -4
  35. data/sig/playwright.rbs +44 -0
  36. metadata +7 -3
@@ -304,11 +304,7 @@ module Playwright
304
304
  end
305
305
 
306
306
  def all
307
- Enumerator.new do |out|
308
- count.times do |i|
309
- out << nth(i)
310
- end
311
- end
307
+ count.times.map { |i| nth(i) }
312
308
  end
313
309
 
314
310
  def count
@@ -446,6 +442,10 @@ module Playwright
446
442
  @frame.type(@selector, text, strict: true, delay: delay, noWaitAfter: noWaitAfter, timeout: timeout)
447
443
  end
448
444
 
445
+ def press_sequentially(text, delay: nil, noWaitAfter: nil, timeout: nil)
446
+ type(text, delay: delay, noWaitAfter: noWaitAfter, timeout: timeout)
447
+ end
448
+
449
449
  def uncheck(
450
450
  force: nil,
451
451
  noWaitAfter: nil,
@@ -484,5 +484,28 @@ module Playwright
484
484
  def highlight
485
485
  @frame.highlight(@selector)
486
486
  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
487
510
  end
488
511
  end
@@ -0,0 +1,68 @@
1
+ module Playwright
2
+ # this module is responsible for running playwright assertions and integrating
3
+ # with test frameworks.
4
+ module Test
5
+ # ref: https://github.com/microsoft/playwright-python/blob/main/playwright/sync_api/__init__.py#L90
6
+ class Expect
7
+ def initialize
8
+ @timeout_settings = TimeoutSettings.new
9
+ end
10
+
11
+ def call(actual, message = nil)
12
+ if actual.is_a?(Locator)
13
+ LocatorAssertions.new(
14
+ LocatorAssertionsImpl.new(
15
+ actual,
16
+ @timeout_settings.timeout,
17
+ false,
18
+ message,
19
+ )
20
+ )
21
+ else
22
+ raise NotImplementedError.new("Only locator assertions are currently implemented")
23
+ end
24
+ end
25
+ end
26
+
27
+ module Matchers
28
+ class PlaywrightMatcher
29
+ def initialize(expectation_method, *args, **kwargs)
30
+ @method = expectation_method
31
+ @args = args
32
+ @kwargs = kwargs
33
+ end
34
+
35
+ def matches?(actual)
36
+ Expect.new.call(actual).send(@method, *@args, **@kwargs)
37
+ true
38
+ rescue AssertionError => e
39
+ @failure_message = e.full_message
40
+ false
41
+ end
42
+
43
+ def failure_message
44
+ @failure_message
45
+ end
46
+
47
+ # we have to invert the message again here because RSpec wants to control
48
+ # its own negation
49
+ def failure_message_when_negated
50
+ @failure_message.gsub("expected to", "not expected to")
51
+ end
52
+ end
53
+ end
54
+
55
+ ALL_ASSERTIONS = LocatorAssertions.instance_methods(false)
56
+
57
+ ALL_ASSERTIONS
58
+ .map(&:to_s)
59
+ .each do |method_name|
60
+ # to_be_visible => be_visible
61
+ # not_to_be_visible => not_be_visible
62
+ root_method_name = method_name.gsub("to_", "")
63
+ Matchers.define_method(root_method_name) do |*args, **kwargs|
64
+ Matchers::PlaywrightMatcher.new(method_name, *args, **kwargs)
65
+ end
66
+ end
67
+ end
68
+ end
@@ -61,6 +61,10 @@ module Playwright
61
61
  end
62
62
  end
63
63
 
64
+ if params[:acceptDownloads] || params[:acceptDownloads] == false
65
+ params[:acceptDownloads] = params[:acceptDownloads] ? 'accept' : 'deny'
66
+ end
67
+
64
68
  params
65
69
  end
66
70
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Playwright
4
- VERSION = '1.37.1'
5
- COMPATIBLE_PLAYWRIGHT_VERSION = '1.37.0'
4
+ VERSION = '1.38.1'
5
+ COMPATIBLE_PLAYWRIGHT_VERSION = '1.38.1'
6
6
  end
@@ -5,14 +5,17 @@ module Playwright
5
5
  # All the downloaded files belonging to the browser context are deleted when the
6
6
  # browser context is closed.
7
7
  #
8
- # Download event is emitted once the download starts. Download path becomes available once download completes:
8
+ # Download event is emitted once the download starts. Download path becomes available once download completes.
9
9
  #
10
10
  # ```python sync
11
+ # # Start waiting for the download
11
12
  # with page.expect_download() as download_info:
13
+ # # Perform the action that initiates download
12
14
  # page.get_by_text("Download file").click()
13
15
  # download = download_info.value
14
- # # wait for download to complete
15
- # path = download.path()
16
+ #
17
+ # # Wait for the download process to complete and save the downloaded file somewhere
18
+ # download.save_as("/path/to/save/at/" + download.suggested_filename)
16
19
  # ```
17
20
  class Download < PlaywrightApi
18
21
 
@@ -54,6 +57,12 @@ module Playwright
54
57
  #
55
58
  # Copy the download to a user-specified path. It is safe to call this method while the download
56
59
  # is still in progress. Will wait for the download to finish if necessary.
60
+ #
61
+ # **Usage**
62
+ #
63
+ # ```python sync
64
+ # download.save_as("/path/to/save/at/" + download.suggested_filename)
65
+ # ```
57
66
  def save_as(path)
58
67
  wrap_impl(@impl.save_as(unwrap_impl(path)))
59
68
  end
@@ -224,7 +224,7 @@ module Playwright
224
224
  #
225
225
  # If the target element is not an `<input>`, `<textarea>` or `[contenteditable]` element, this method throws an error. However, if the element is inside the `<label>` element that has an associated [control](https://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement/control), the control will be filled instead.
226
226
  #
227
- # To send fine-grained keyboard events, use [`method: ElementHandle.type`].
227
+ # To send fine-grained keyboard events, use [`method: Locator.pressSequentially`].
228
228
  def fill(value, force: nil, noWaitAfter: nil, timeout: nil)
229
229
  wrap_impl(@impl.fill(unwrap_impl(value), force: unwrap_impl(force), noWaitAfter: unwrap_impl(noWaitAfter), timeout: unwrap_impl(timeout)))
230
230
  end
@@ -503,19 +503,6 @@ module Playwright
503
503
  # To press a special key, like `Control` or `ArrowDown`, use [`method: ElementHandle.press`].
504
504
  #
505
505
  # **Usage**
506
- #
507
- # ```python sync
508
- # element_handle.type("hello") # types instantly
509
- # element_handle.type("world", delay=100) # types slower, like a user
510
- # ```
511
- #
512
- # An example of typing into a text field and then submitting the form:
513
- #
514
- # ```python sync
515
- # element_handle = page.query_selector("input")
516
- # element_handle.type("some text")
517
- # element_handle.press("Enter")
518
- # ```
519
506
  def type(text, delay: nil, noWaitAfter: nil, timeout: nil)
520
507
  wrap_impl(@impl.type(unwrap_impl(text), delay: unwrap_impl(delay), noWaitAfter: unwrap_impl(noWaitAfter), timeout: unwrap_impl(timeout)))
521
508
  end
@@ -300,7 +300,7 @@ module Playwright
300
300
  #
301
301
  # If the target element is not an `<input>`, `<textarea>` or `[contenteditable]` element, this method throws an error. However, if the element is inside the `<label>` element that has an associated [control](https://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement/control), the control will be filled instead.
302
302
  #
303
- # To send fine-grained keyboard events, use [`method: Frame.type`].
303
+ # To send fine-grained keyboard events, use [`method: Locator.pressSequentially`].
304
304
  def fill(
305
305
  selector,
306
306
  value,
@@ -867,11 +867,6 @@ module Playwright
867
867
  # To press a special key, like `Control` or `ArrowDown`, use [`method: Keyboard.press`].
868
868
  #
869
869
  # **Usage**
870
- #
871
- # ```python sync
872
- # frame.type("#mytextarea", "hello") # types instantly
873
- # frame.type("#mytextarea", "world", delay=100) # types slower, like a user
874
- # ```
875
870
  def type(
876
871
  selector,
877
872
  text,
@@ -81,6 +81,8 @@ module Playwright
81
81
  wrap_impl(@impl.insert_text(unwrap_impl(text)))
82
82
  end
83
83
 
84
+ #
85
+ # **NOTE**: In most cases, you should use [`method: Locator.press`] instead.
84
86
  #
85
87
  # `key` can specify the intended
86
88
  # [keyboardEvent.key](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key) value or a single character to
@@ -119,6 +121,8 @@ module Playwright
119
121
  wrap_impl(@impl.press(unwrap_impl(key), delay: unwrap_impl(delay)))
120
122
  end
121
123
 
124
+ #
125
+ # **NOTE**: In most cases, you should use [`method: Locator.fill`] instead. You only need to press keys one by one if there is special keyboard handling on the page - in this case use [`method: Locator.pressSequentially`].
122
126
  #
123
127
  # Sends a `keydown`, `keypress`/`input`, and `keyup` event for each character in the text.
124
128
  #
@@ -391,7 +391,7 @@ module Playwright
391
391
  #
392
392
  # If the target element is not an `<input>`, `<textarea>` or `[contenteditable]` element, this method throws an error. However, if the element is inside the `<label>` element that has an associated [control](https://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement/control), the control will be filled instead.
393
393
  #
394
- # To send fine-grained keyboard events, use [`method: Locator.type`].
394
+ # To send fine-grained keyboard events, use [`method: Locator.pressSequentially`].
395
395
  def fill(value, force: nil, noWaitAfter: nil, timeout: nil)
396
396
  wrap_impl(@impl.fill(unwrap_impl(value), force: unwrap_impl(force), noWaitAfter: unwrap_impl(noWaitAfter), timeout: unwrap_impl(timeout)))
397
397
  end
@@ -869,6 +869,31 @@ module Playwright
869
869
  wrap_impl(@impl.press(unwrap_impl(key), delay: unwrap_impl(delay), noWaitAfter: unwrap_impl(noWaitAfter), timeout: unwrap_impl(timeout)))
870
870
  end
871
871
 
872
+ #
873
+ # **NOTE**: In most cases, you should use [`method: Locator.fill`] instead. You only need to press keys one by one if there is special keyboard handling on the page.
874
+ #
875
+ # Focuses the element, and then sends a `keydown`, `keypress`/`input`, and `keyup` event for each character in the text.
876
+ #
877
+ # To press a special key, like `Control` or `ArrowDown`, use [`method: Locator.press`].
878
+ #
879
+ # **Usage**
880
+ #
881
+ # ```python sync
882
+ # locator.press_sequentially("hello") # types instantly
883
+ # locator.press_sequentially("world", delay=100) # types slower, like a user
884
+ # ```
885
+ #
886
+ # An example of typing into a text field and then submitting the form:
887
+ #
888
+ # ```python sync
889
+ # locator = page.get_by_label("Password")
890
+ # locator.press_sequentially("my password")
891
+ # locator.press("Enter")
892
+ # ```
893
+ def press_sequentially(text, delay: nil, noWaitAfter: nil, timeout: nil)
894
+ wrap_impl(@impl.press_sequentially(unwrap_impl(text), delay: unwrap_impl(delay), noWaitAfter: unwrap_impl(noWaitAfter), timeout: unwrap_impl(timeout)))
895
+ end
896
+
872
897
  #
873
898
  # Take a screenshot of the element matching the locator.
874
899
  #
@@ -1066,27 +1091,12 @@ module Playwright
1066
1091
  wrap_impl(@impl.text_content(timeout: unwrap_impl(timeout)))
1067
1092
  end
1068
1093
 
1069
- #
1070
- # **NOTE**: In most cases, you should use [`method: Locator.fill`] instead. You only need to type characters if there is special keyboard handling on the page.
1071
1094
  #
1072
1095
  # Focuses the element, and then sends a `keydown`, `keypress`/`input`, and `keyup` event for each character in the text.
1073
1096
  #
1074
1097
  # To press a special key, like `Control` or `ArrowDown`, use [`method: Locator.press`].
1075
1098
  #
1076
1099
  # **Usage**
1077
- #
1078
- # ```python sync
1079
- # element.type("hello") # types instantly
1080
- # element.type("world", delay=100) # types slower, like a user
1081
- # ```
1082
- #
1083
- # An example of typing into a text field and then submitting the form:
1084
- #
1085
- # ```python sync
1086
- # element = page.get_by_label("Password")
1087
- # element.type("my password")
1088
- # element.press("Enter")
1089
- # ```
1090
1100
  def type(text, delay: nil, noWaitAfter: nil, timeout: nil)
1091
1101
  wrap_impl(@impl.type(unwrap_impl(text), delay: unwrap_impl(delay), noWaitAfter: unwrap_impl(noWaitAfter), timeout: unwrap_impl(timeout)))
1092
1102
  end
@@ -1139,6 +1149,11 @@ module Playwright
1139
1149
  wrap_impl(@impl.wait_for(state: unwrap_impl(state), timeout: unwrap_impl(timeout)))
1140
1150
  end
1141
1151
 
1152
+ # @nodoc
1153
+ def expect(expression, options)
1154
+ wrap_impl(@impl.expect(unwrap_impl(expression), unwrap_impl(options)))
1155
+ end
1156
+
1142
1157
  # @nodoc
1143
1158
  def to_s
1144
1159
  wrap_impl(@impl.to_s)