playwright-ruby-client 1.25.0 → 1.27.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 (42) hide show
  1. checksums.yaml +4 -4
  2. data/documentation/docs/api/api_request_context.md +93 -0
  3. data/documentation/docs/api/browser_context.md +3 -3
  4. data/documentation/docs/api/browser_type.md +8 -0
  5. data/documentation/docs/api/download.md +1 -1
  6. data/documentation/docs/api/element_handle.md +1 -1
  7. data/documentation/docs/api/file_chooser.md +1 -1
  8. data/documentation/docs/api/frame.md +103 -4
  9. data/documentation/docs/api/frame_locator.md +105 -5
  10. data/documentation/docs/api/locator.md +121 -6
  11. data/documentation/docs/api/page.md +119 -10
  12. data/documentation/docs/api/tracing.md +1 -1
  13. data/documentation/docs/article/guides/rails_integration_with_null_driver.md +59 -0
  14. data/documentation/docs/include/api_coverage.md +29 -0
  15. data/documentation/src/components/HomepageFeatures.js +1 -1
  16. data/lib/playwright/channel_owners/api_request_context.rb +23 -120
  17. data/lib/playwright/channel_owners/browser_context.rb +4 -5
  18. data/lib/playwright/channel_owners/dialog.rb +1 -1
  19. data/lib/playwright/channel_owners/frame.rb +4 -0
  20. data/lib/playwright/channel_owners/page.rb +7 -6
  21. data/lib/playwright/channel_owners/selectors.rb +4 -0
  22. data/lib/playwright/frame_locator_impl.rb +6 -2
  23. data/lib/playwright/locator_impl.rb +7 -31
  24. data/lib/playwright/locator_utils.rb +142 -0
  25. data/lib/playwright/route_handler.rb +2 -2
  26. data/lib/playwright/version.rb +2 -2
  27. data/lib/playwright_api/api_request_context.rb +92 -7
  28. data/lib/playwright_api/browser_context.rb +3 -3
  29. data/lib/playwright_api/browser_type.rb +6 -0
  30. data/lib/playwright_api/download.rb +1 -1
  31. data/lib/playwright_api/element_handle.rb +1 -1
  32. data/lib/playwright_api/file_chooser.rb +1 -1
  33. data/lib/playwright_api/frame.rb +78 -4
  34. data/lib/playwright_api/frame_locator.rb +79 -4
  35. data/lib/playwright_api/locator.rb +94 -5
  36. data/lib/playwright_api/page.rb +93 -10
  37. data/lib/playwright_api/request.rb +4 -4
  38. data/lib/playwright_api/response.rb +4 -4
  39. data/lib/playwright_api/selectors.rb +11 -0
  40. data/lib/playwright_api/tracing.rb +1 -1
  41. data/lib/playwright_api/worker.rb +4 -4
  42. metadata +4 -3
@@ -1,49 +1,25 @@
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
- case hasText
33
- when Regexp
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
+ text_selector = "text=#{escape_for_text_selector(hasText, false)}"
15
+ selector_scopes << "internal:has=#{text_selector.to_json}"
40
16
  end
41
17
 
42
18
  if has
43
19
  unless same_frame?(has)
44
20
  raise DifferentFrameError.new
45
21
  end
46
- selector_scopes << "has=#{has.send(:selector_json)}"
22
+ selector_scopes << "internal:has=#{has.send(:selector_json)}"
47
23
  end
48
24
 
49
25
  @selector = selector_scopes.join(' >> ')
@@ -0,0 +1,142 @@
1
+ module Playwright
2
+ module LocatorUtils
3
+ def get_by_test_id(test_id)
4
+ locator(get_by_test_id_selector(test_id))
5
+ end
6
+
7
+ def get_by_alt_text(text, exact: false)
8
+ locator(get_by_alt_text_selector(text, exact: exact))
9
+ end
10
+
11
+ def get_by_label(text, exact: false)
12
+ locator(get_by_label_selector(text, exact: exact))
13
+ end
14
+
15
+ def get_by_placeholder(text, exact: false)
16
+ locator(get_by_placeholder_selector(text, exact: exact))
17
+ end
18
+
19
+ def get_by_text(text, exact: false)
20
+ locator(get_by_text_selector(text, exact: exact))
21
+ end
22
+
23
+ def get_by_title(text, exact: false)
24
+ locator(get_by_title_selector(text, exact: exact))
25
+ end
26
+
27
+ def get_by_role(role, **options)
28
+ locator(get_by_role_selector(role, **(options.compact)))
29
+ end
30
+
31
+ # set from Playwright::Selectors#test_id_attribute=
32
+ @test_id_attribute_name = 'data-testid'
33
+
34
+ private def get_by_attribute_text_selector(attr_name, text, exact: false)
35
+ "internal:attr=[#{attr_name}=#{escape_for_attribute_selector_or_regex(text, exact)}]"
36
+ end
37
+
38
+ private def get_by_test_id_selector(test_id)
39
+ get_by_attribute_text_selector(
40
+ ::Playwright::LocatorUtils.instance_variable_get(:@test_id_attribute_name),
41
+ test_id,
42
+ exact: 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
+ "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, false)]},
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
+ "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 = text.gsub(/["]/, '\\"')
107
+ return "\"#{_text}\""
108
+ end
109
+
110
+ if text.include?('"') || text.include?('>>') || text.start_with?('/')
111
+ _text = escape_for_regex(text).gsub(/\s+/, '\\s+')
112
+ return "/#{_text}/i"
113
+ end
114
+
115
+ text
116
+ end
117
+
118
+ # @param text [Regexp|String]
119
+ private def escape_for_attribute_selector_or_regex(text, exact)
120
+ if text.is_a?(Regexp)
121
+ regex = JavaScript::Regex.new(text)
122
+ "/#{regex.source}/#{regex.flag}"
123
+ else
124
+ escape_for_attribute_selector(text, exact)
125
+ end
126
+ end
127
+
128
+ # @param text [String]
129
+ private def escape_for_attribute_selector(text, exact)
130
+ # TODO: this should actually be
131
+ # cssEscape(value).replace(/\\ /g, ' ')
132
+ # However, our attribute selectors do not conform to CSS parsing spec,
133
+ # so we escape them differently.
134
+ _text = text.gsub(/["]/, '\\"')
135
+ if exact
136
+ "\"#{_text}\""
137
+ else
138
+ "\"#{_text}\"i"
139
+ end
140
+ end
141
+ end
142
+ end
@@ -47,10 +47,10 @@ module Playwright
47
47
  @url_matcher.match?(url)
48
48
  end
49
49
 
50
- def async_handle(route, request)
50
+ def async_handle(route)
51
51
  @counter.increment
52
52
 
53
- Concurrent::Promises.future { @handler.call(route, request) }.rescue do |err|
53
+ Concurrent::Promises.future { @handler.call(route, route.request) }.rescue do |err|
54
54
  puts err, err.backtrace
55
55
  end
56
56
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Playwright
4
- VERSION = '1.25.0'
5
- COMPATIBLE_PLAYWRIGHT_VERSION = '1.25.0'
4
+ VERSION = '1.27.0'
5
+ COMPATIBLE_PLAYWRIGHT_VERSION = '1.27.0'
6
6
  end
@@ -75,10 +75,11 @@ module Playwright
75
75
  form: nil,
76
76
  headers: nil,
77
77
  ignoreHTTPSErrors: nil,
78
+ maxRedirects: nil,
78
79
  multipart: nil,
79
80
  params: nil,
80
81
  timeout: nil)
81
- wrap_impl(@impl.delete(unwrap_impl(url), data: unwrap_impl(data), failOnStatusCode: unwrap_impl(failOnStatusCode), form: unwrap_impl(form), headers: unwrap_impl(headers), ignoreHTTPSErrors: unwrap_impl(ignoreHTTPSErrors), multipart: unwrap_impl(multipart), params: unwrap_impl(params), timeout: unwrap_impl(timeout)))
82
+ wrap_impl(@impl.delete(unwrap_impl(url), data: unwrap_impl(data), failOnStatusCode: unwrap_impl(failOnStatusCode), form: unwrap_impl(form), headers: unwrap_impl(headers), ignoreHTTPSErrors: unwrap_impl(ignoreHTTPSErrors), maxRedirects: unwrap_impl(maxRedirects), multipart: unwrap_impl(multipart), params: unwrap_impl(params), timeout: unwrap_impl(timeout)))
82
83
  end
83
84
 
84
85
  # All responses returned by [`method: APIRequestContext.get`] and similar methods are stored in the memory, so that you
@@ -90,6 +91,32 @@ module Playwright
90
91
 
91
92
  # Sends HTTP(S) request and returns its response. The method will populate request cookies from the context and update
92
93
  # context cookies from the response. The method will automatically follow redirects.
94
+ #
95
+ # JSON objects can be passed directly to the request:
96
+ #
97
+ # ```python
98
+ # data = {
99
+ # "title": "Book Title",
100
+ # "body": "John Doe",
101
+ # }
102
+ # api_request_context.fetch("https://example.com/api/createBook", method="post", data=data)
103
+ # ```
104
+ #
105
+ # The common way to send file(s) in the body of a request is to encode it as form fields with `multipart/form-data`
106
+ # encoding. You can achieve that with Playwright API like this:
107
+ #
108
+ # ```python
109
+ # api_request_context.fetch(
110
+ # "https://example.com/api/uploadScrip'",
111
+ # method="post",
112
+ # multipart={
113
+ # "fileField": {
114
+ # "name": "f.js",
115
+ # "mimeType": "text/javascript",
116
+ # "buffer": b"console.log(2022);",
117
+ # },
118
+ # })
119
+ # ```
93
120
  def fetch(
94
121
  urlOrRequest,
95
122
  data: nil,
@@ -97,24 +124,39 @@ module Playwright
97
124
  form: nil,
98
125
  headers: nil,
99
126
  ignoreHTTPSErrors: nil,
127
+ maxRedirects: nil,
100
128
  method: nil,
101
129
  multipart: nil,
102
130
  params: nil,
103
131
  timeout: nil)
104
- wrap_impl(@impl.fetch(unwrap_impl(urlOrRequest), data: unwrap_impl(data), failOnStatusCode: unwrap_impl(failOnStatusCode), form: unwrap_impl(form), headers: unwrap_impl(headers), ignoreHTTPSErrors: unwrap_impl(ignoreHTTPSErrors), method: unwrap_impl(method), multipart: unwrap_impl(multipart), params: unwrap_impl(params), timeout: unwrap_impl(timeout)))
132
+ wrap_impl(@impl.fetch(unwrap_impl(urlOrRequest), data: unwrap_impl(data), failOnStatusCode: unwrap_impl(failOnStatusCode), form: unwrap_impl(form), headers: unwrap_impl(headers), ignoreHTTPSErrors: unwrap_impl(ignoreHTTPSErrors), maxRedirects: unwrap_impl(maxRedirects), method: unwrap_impl(method), multipart: unwrap_impl(multipart), params: unwrap_impl(params), timeout: unwrap_impl(timeout)))
105
133
  end
106
134
 
107
135
  # Sends HTTP(S) [GET](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/GET) request and returns its response. The
108
136
  # method will populate request cookies from the context and update context cookies from the response. The method will
109
137
  # automatically follow redirects.
138
+ #
139
+ # Request parameters can be configured with `params` option, they will be serialized into the URL search parameters:
140
+ #
141
+ # ```python
142
+ # query_params = {
143
+ # "isbn": "1234",
144
+ # "page": "23"
145
+ # }
146
+ # api_request_context.get("https://example.com/api/getText", params=query_params)
147
+ # ```
110
148
  def get(
111
149
  url,
150
+ data: nil,
112
151
  failOnStatusCode: nil,
152
+ form: nil,
113
153
  headers: nil,
114
154
  ignoreHTTPSErrors: nil,
155
+ maxRedirects: nil,
156
+ multipart: nil,
115
157
  params: nil,
116
158
  timeout: nil)
117
- wrap_impl(@impl.get(unwrap_impl(url), failOnStatusCode: unwrap_impl(failOnStatusCode), headers: unwrap_impl(headers), ignoreHTTPSErrors: unwrap_impl(ignoreHTTPSErrors), params: unwrap_impl(params), timeout: unwrap_impl(timeout)))
159
+ wrap_impl(@impl.get(unwrap_impl(url), data: unwrap_impl(data), failOnStatusCode: unwrap_impl(failOnStatusCode), form: unwrap_impl(form), headers: unwrap_impl(headers), ignoreHTTPSErrors: unwrap_impl(ignoreHTTPSErrors), maxRedirects: unwrap_impl(maxRedirects), multipart: unwrap_impl(multipart), params: unwrap_impl(params), timeout: unwrap_impl(timeout)))
118
160
  end
119
161
 
120
162
  # Sends HTTP(S) [HEAD](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/HEAD) request and returns its response.
@@ -122,12 +164,16 @@ module Playwright
122
164
  # automatically follow redirects.
123
165
  def head(
124
166
  url,
167
+ data: nil,
125
168
  failOnStatusCode: nil,
169
+ form: nil,
126
170
  headers: nil,
127
171
  ignoreHTTPSErrors: nil,
172
+ maxRedirects: nil,
173
+ multipart: nil,
128
174
  params: nil,
129
175
  timeout: nil)
130
- wrap_impl(@impl.head(unwrap_impl(url), failOnStatusCode: unwrap_impl(failOnStatusCode), headers: unwrap_impl(headers), ignoreHTTPSErrors: unwrap_impl(ignoreHTTPSErrors), params: unwrap_impl(params), timeout: unwrap_impl(timeout)))
176
+ wrap_impl(@impl.head(unwrap_impl(url), data: unwrap_impl(data), failOnStatusCode: unwrap_impl(failOnStatusCode), form: unwrap_impl(form), headers: unwrap_impl(headers), ignoreHTTPSErrors: unwrap_impl(ignoreHTTPSErrors), maxRedirects: unwrap_impl(maxRedirects), multipart: unwrap_impl(multipart), params: unwrap_impl(params), timeout: unwrap_impl(timeout)))
131
177
  end
132
178
 
133
179
  # Sends HTTP(S) [PATCH](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PATCH) request and returns its response.
@@ -140,15 +186,52 @@ module Playwright
140
186
  form: nil,
141
187
  headers: nil,
142
188
  ignoreHTTPSErrors: nil,
189
+ maxRedirects: nil,
143
190
  multipart: nil,
144
191
  params: nil,
145
192
  timeout: nil)
146
- wrap_impl(@impl.patch(unwrap_impl(url), data: unwrap_impl(data), failOnStatusCode: unwrap_impl(failOnStatusCode), form: unwrap_impl(form), headers: unwrap_impl(headers), ignoreHTTPSErrors: unwrap_impl(ignoreHTTPSErrors), multipart: unwrap_impl(multipart), params: unwrap_impl(params), timeout: unwrap_impl(timeout)))
193
+ wrap_impl(@impl.patch(unwrap_impl(url), data: unwrap_impl(data), failOnStatusCode: unwrap_impl(failOnStatusCode), form: unwrap_impl(form), headers: unwrap_impl(headers), ignoreHTTPSErrors: unwrap_impl(ignoreHTTPSErrors), maxRedirects: unwrap_impl(maxRedirects), multipart: unwrap_impl(multipart), params: unwrap_impl(params), timeout: unwrap_impl(timeout)))
147
194
  end
148
195
 
149
196
  # Sends HTTP(S) [POST](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST) request and returns its response.
150
197
  # The method will populate request cookies from the context and update context cookies from the response. The method will
151
198
  # automatically follow redirects.
199
+ #
200
+ # JSON objects can be passed directly to the request:
201
+ #
202
+ # ```python
203
+ # data = {
204
+ # "title": "Book Title",
205
+ # "body": "John Doe",
206
+ # }
207
+ # api_request_context.post("https://example.com/api/createBook", data=data)
208
+ # ```
209
+ #
210
+ # To send form data to the server use `form` option. Its value will be encoded into the request body with
211
+ # `application/x-www-form-urlencoded` encoding (see below how to use `multipart/form-data` form encoding to send files):
212
+ #
213
+ # ```python
214
+ # formData = {
215
+ # "title": "Book Title",
216
+ # "body": "John Doe",
217
+ # }
218
+ # api_request_context.post("https://example.com/api/findBook", form=formData)
219
+ # ```
220
+ #
221
+ # The common way to send file(s) in the body of a request is to upload them as form fields with `multipart/form-data`
222
+ # encoding. You can achieve that with Playwright API like this:
223
+ #
224
+ # ```python
225
+ # api_request_context.post(
226
+ # "https://example.com/api/uploadScrip'",
227
+ # multipart={
228
+ # "fileField": {
229
+ # "name": "f.js",
230
+ # "mimeType": "text/javascript",
231
+ # "buffer": b"console.log(2022);",
232
+ # },
233
+ # })
234
+ # ```
152
235
  def post(
153
236
  url,
154
237
  data: nil,
@@ -156,10 +239,11 @@ module Playwright
156
239
  form: nil,
157
240
  headers: nil,
158
241
  ignoreHTTPSErrors: nil,
242
+ maxRedirects: nil,
159
243
  multipart: nil,
160
244
  params: nil,
161
245
  timeout: nil)
162
- wrap_impl(@impl.post(unwrap_impl(url), data: unwrap_impl(data), failOnStatusCode: unwrap_impl(failOnStatusCode), form: unwrap_impl(form), headers: unwrap_impl(headers), ignoreHTTPSErrors: unwrap_impl(ignoreHTTPSErrors), multipart: unwrap_impl(multipart), params: unwrap_impl(params), timeout: unwrap_impl(timeout)))
246
+ wrap_impl(@impl.post(unwrap_impl(url), data: unwrap_impl(data), failOnStatusCode: unwrap_impl(failOnStatusCode), form: unwrap_impl(form), headers: unwrap_impl(headers), ignoreHTTPSErrors: unwrap_impl(ignoreHTTPSErrors), maxRedirects: unwrap_impl(maxRedirects), multipart: unwrap_impl(multipart), params: unwrap_impl(params), timeout: unwrap_impl(timeout)))
163
247
  end
164
248
 
165
249
  # Sends HTTP(S) [PUT](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PUT) request and returns its response. The
@@ -172,10 +256,11 @@ module Playwright
172
256
  form: nil,
173
257
  headers: nil,
174
258
  ignoreHTTPSErrors: nil,
259
+ maxRedirects: nil,
175
260
  multipart: nil,
176
261
  params: nil,
177
262
  timeout: nil)
178
- wrap_impl(@impl.put(unwrap_impl(url), data: unwrap_impl(data), failOnStatusCode: unwrap_impl(failOnStatusCode), form: unwrap_impl(form), headers: unwrap_impl(headers), ignoreHTTPSErrors: unwrap_impl(ignoreHTTPSErrors), multipart: unwrap_impl(multipart), params: unwrap_impl(params), timeout: unwrap_impl(timeout)))
263
+ wrap_impl(@impl.put(unwrap_impl(url), data: unwrap_impl(data), failOnStatusCode: unwrap_impl(failOnStatusCode), form: unwrap_impl(form), headers: unwrap_impl(headers), ignoreHTTPSErrors: unwrap_impl(ignoreHTTPSErrors), maxRedirects: unwrap_impl(maxRedirects), multipart: unwrap_impl(multipart), params: unwrap_impl(params), timeout: unwrap_impl(timeout)))
179
264
  end
180
265
 
181
266
  # Returns storage state for this request context, contains current cookies and local storage snapshot if it was passed to
@@ -131,7 +131,7 @@ module Playwright
131
131
  # <button onclick="onClick()">Click me</button>
132
132
  # <div></div>
133
133
  # """)
134
- # page.locator("button").click()
134
+ # page.get_by_role("button").click()
135
135
  #
136
136
  # with sync_playwright() as playwright:
137
137
  # run(playwright)
@@ -190,7 +190,7 @@ module Playwright
190
190
  # <button onclick="onClick()">Click me</button>
191
191
  # <div></div>
192
192
  # """)
193
- # page.locator("button").click()
193
+ # page.get_by_role("button").click()
194
194
  #
195
195
  # with sync_playwright() as playwright:
196
196
  # run(playwright)
@@ -358,7 +358,7 @@ module Playwright
358
358
  #
359
359
  # ```python sync
360
360
  # with context.expect_event("page") as event_info:
361
- # page.locator("button").click()
361
+ # page.get_by_role("button").click()
362
362
  # page = event_info.value
363
363
  # ```
364
364
  def expect_event(event, predicate: nil, timeout: nil, &block)
@@ -30,6 +30,12 @@ module Playwright
30
30
  # The default browser context is accessible via [`method: Browser.contexts`].
31
31
  #
32
32
  # > NOTE: Connecting over the Chrome DevTools Protocol is only supported for Chromium-based browsers.
33
+ #
34
+ # ```python sync
35
+ # browser = playwright.chromium.connect_over_cdp("http://localhost:9222")
36
+ # default_context = browser.contexts[0]
37
+ # page = default_context.pages[0]
38
+ # ```
33
39
  def connect_over_cdp(
34
40
  endpointURL,
35
41
  headers: nil,
@@ -7,7 +7,7 @@ module Playwright
7
7
  #
8
8
  # ```python sync
9
9
  # with page.expect_download() as download_info:
10
- # page.locator("a").click()
10
+ # page.get_by_text("Download file").click()
11
11
  # download = download_info.value
12
12
  # # wait for download to complete
13
13
  # path = download.path()
@@ -36,7 +36,7 @@ module Playwright
36
36
  # in the snippet below, underlying DOM element is going to be located twice.
37
37
  #
38
38
  # ```python sync
39
- # locator = page.locator("text=Submit")
39
+ # locator = page.get_by_text("Submit")
40
40
  # locator.hover()
41
41
  # locator.click()
42
42
  # ```
@@ -3,7 +3,7 @@ module Playwright
3
3
  #
4
4
  # ```python sync
5
5
  # with page.expect_file_chooser() as fc_info:
6
- # page.locator("upload").click()
6
+ # page.get_by_text("Upload").click()
7
7
  # file_chooser = fc_info.value
8
8
  # file_chooser.set_files("myfile.pdf")
9
9
  # ```
@@ -335,7 +335,7 @@ module Playwright
335
335
  # id="my-frame">`:
336
336
  #
337
337
  # ```python sync
338
- # locator = frame.frame_locator("#my-iframe").locator("text=Submit")
338
+ # locator = frame.frame_locator("#my-iframe").get_by_text("Submit")
339
339
  # locator.click()
340
340
  # ```
341
341
  def frame_locator(selector)
@@ -347,6 +347,78 @@ module Playwright
347
347
  wrap_impl(@impl.get_attribute(unwrap_impl(selector), unwrap_impl(name), strict: unwrap_impl(strict), timeout: unwrap_impl(timeout)))
348
348
  end
349
349
 
350
+ # Allows locating elements by their alt text. For example, this method will find the image by alt text "Castle":
351
+ #
352
+ # ```html
353
+ # <img alt='Castle'>
354
+ # ```
355
+ def get_by_alt_text(text, exact: nil)
356
+ wrap_impl(@impl.get_by_alt_text(unwrap_impl(text), exact: unwrap_impl(exact)))
357
+ end
358
+
359
+ # Allows locating input elements by the text of the associated label. For example, this method will find the input by
360
+ # label text Password in the following DOM:
361
+ #
362
+ # ```html
363
+ # <label for="password-input">Password:</label>
364
+ # <input id="password-input">
365
+ # ```
366
+ def get_by_label(text, exact: nil)
367
+ wrap_impl(@impl.get_by_label(unwrap_impl(text), exact: unwrap_impl(exact)))
368
+ end
369
+
370
+ # Allows locating input elements by the placeholder text. For example, this method will find the input by placeholder
371
+ # "Country":
372
+ #
373
+ # ```html
374
+ # <input placeholder="Country">
375
+ # ```
376
+ def get_by_placeholder(text, exact: nil)
377
+ wrap_impl(@impl.get_by_placeholder(unwrap_impl(text), exact: unwrap_impl(exact)))
378
+ end
379
+
380
+ # Allows locating elements by their [ARIA role](https://www.w3.org/TR/wai-aria-1.2/#roles),
381
+ # [ARIA attributes](https://www.w3.org/TR/wai-aria-1.2/#aria-attributes) and
382
+ # [accessible name](https://w3c.github.io/accname/#dfn-accessible-name). Note that role selector **does not replace**
383
+ # accessibility audits and conformance tests, but rather gives early feedback about the ARIA guidelines.
384
+ #
385
+ # Note that many html elements have an implicitly
386
+ # [defined role](https://w3c.github.io/html-aam/#html-element-role-mappings) that is recognized by the role selector. You
387
+ # can find all the [supported roles here](https://www.w3.org/TR/wai-aria-1.2/#role_definitions). ARIA guidelines **do not
388
+ # recommend** duplicating implicit roles and attributes by setting `role` and/or `aria-*` attributes to default values.
389
+ def get_by_role(
390
+ role,
391
+ checked: nil,
392
+ disabled: nil,
393
+ expanded: nil,
394
+ includeHidden: nil,
395
+ level: nil,
396
+ name: nil,
397
+ pressed: nil,
398
+ selected: nil)
399
+ wrap_impl(@impl.get_by_role(unwrap_impl(role), checked: unwrap_impl(checked), disabled: unwrap_impl(disabled), expanded: unwrap_impl(expanded), includeHidden: unwrap_impl(includeHidden), level: unwrap_impl(level), name: unwrap_impl(name), pressed: unwrap_impl(pressed), selected: unwrap_impl(selected)))
400
+ end
401
+
402
+ # Locate element by the test id. By default, the `data-testid` attribute is used as a test id. Use
403
+ # [`method: Selectors.setTestIdAttribute`] to configure a different test id attribute if necessary.
404
+ def get_by_test_id(testId)
405
+ wrap_impl(@impl.get_by_test_id(unwrap_impl(testId)))
406
+ end
407
+
408
+ # Allows locating elements that contain given text.
409
+ def get_by_text(text, exact: nil)
410
+ wrap_impl(@impl.get_by_text(unwrap_impl(text), exact: unwrap_impl(exact)))
411
+ end
412
+
413
+ # Allows locating elements by their title. For example, this method will find the button by its title "Submit":
414
+ #
415
+ # ```html
416
+ # <button title='Place the order'>Order Now</button>
417
+ # ```
418
+ def get_by_title(text, exact: nil)
419
+ wrap_impl(@impl.get_by_title(unwrap_impl(text), exact: unwrap_impl(exact)))
420
+ end
421
+
350
422
  # Returns the main resource response. In case of multiple redirects, the navigation will resolve with the response of the
351
423
  # last redirect.
352
424
  #
@@ -445,9 +517,11 @@ module Playwright
445
517
  wrap_impl(@impl.visible?(unwrap_impl(selector), strict: unwrap_impl(strict), timeout: unwrap_impl(timeout)))
446
518
  end
447
519
 
448
- # The method returns an element locator that can be used to perform actions in the frame. Locator is resolved to the
449
- # element immediately before performing an action, so a series of actions on the same locator can in fact be performed on
450
- # different DOM elements. That would happen if the DOM structure between those actions has changed.
520
+ # The method returns an element locator that can be used to perform actions on this page / frame. Locator is resolved to
521
+ # the element immediately before performing an action, so a series of actions on the same locator can in fact be performed
522
+ # on different DOM elements. That would happen if the DOM structure between those actions has changed.
523
+ #
524
+ # [Learn more about locators](../locators.md).
451
525
  #
452
526
  # [Learn more about locators](../locators.md).
453
527
  def locator(selector, has: nil, hasText: nil)