playwright-ruby-client 1.25.0 → 1.27.0

Sign up to get free protection for your applications and to get access to all the features.
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)