playwright-ruby-client 0.0.7 → 0.2.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 (64) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +38 -3
  3. data/docs/api_coverage.md +89 -84
  4. data/lib/playwright.rb +4 -2
  5. data/lib/playwright/android_input_impl.rb +23 -0
  6. data/lib/playwright/api_implementation.rb +18 -0
  7. data/lib/playwright/channel.rb +7 -0
  8. data/lib/playwright/channel_owner.rb +3 -5
  9. data/lib/playwright/channel_owners/android.rb +1 -1
  10. data/lib/playwright/channel_owners/android_device.rb +83 -13
  11. data/lib/playwright/channel_owners/browser.rb +1 -1
  12. data/lib/playwright/channel_owners/browser_context.rb +10 -2
  13. data/lib/playwright/channel_owners/download.rb +27 -0
  14. data/lib/playwright/channel_owners/element_handle.rb +15 -4
  15. data/lib/playwright/channel_owners/frame.rb +228 -19
  16. data/lib/playwright/channel_owners/js_handle.rb +1 -1
  17. data/lib/playwright/channel_owners/page.rb +350 -27
  18. data/lib/playwright/channel_owners/request.rb +9 -1
  19. data/lib/playwright/errors.rb +1 -1
  20. data/lib/playwright/event_emitter.rb +8 -1
  21. data/lib/playwright/event_emitter_proxy.rb +49 -0
  22. data/lib/playwright/file_chooser_impl.rb +23 -0
  23. data/lib/playwright/http_headers.rb +20 -0
  24. data/lib/playwright/input_files.rb +1 -1
  25. data/lib/playwright/javascript/expression.rb +15 -0
  26. data/lib/playwright/javascript/function.rb +15 -0
  27. data/lib/playwright/javascript/value_parser.rb +1 -1
  28. data/lib/playwright/javascript/value_serializer.rb +1 -1
  29. data/lib/playwright/{input_types/keyboard.rb → keyboard_impl.rb} +5 -1
  30. data/lib/playwright/mouse_impl.rb +7 -0
  31. data/lib/playwright/playwright_api.rb +59 -20
  32. data/lib/playwright/select_option_values.rb +14 -4
  33. data/lib/playwright/timeout_settings.rb +1 -1
  34. data/lib/playwright/touchscreen_impl.rb +7 -0
  35. data/lib/playwright/utils.rb +3 -3
  36. data/lib/playwright/version.rb +1 -1
  37. data/lib/playwright/wait_helper.rb +1 -1
  38. data/lib/playwright_api/android.rb +9 -10
  39. data/lib/playwright_api/android_device.rb +43 -14
  40. data/lib/playwright_api/android_input.rb +25 -0
  41. data/lib/playwright_api/binding_call.rb +10 -6
  42. data/lib/playwright_api/browser.rb +20 -21
  43. data/lib/playwright_api/browser_context.rb +29 -20
  44. data/lib/playwright_api/browser_type.rb +16 -56
  45. data/lib/playwright_api/chromium_browser_context.rb +10 -8
  46. data/lib/playwright_api/console_message.rb +10 -6
  47. data/lib/playwright_api/dialog.rb +5 -1
  48. data/lib/playwright_api/download.rb +28 -11
  49. data/lib/playwright_api/element_handle.rb +107 -96
  50. data/lib/playwright_api/file_chooser.rb +17 -9
  51. data/lib/playwright_api/frame.rb +136 -132
  52. data/lib/playwright_api/js_handle.rb +18 -20
  53. data/lib/playwright_api/keyboard.rb +5 -5
  54. data/lib/playwright_api/page.rb +204 -149
  55. data/lib/playwright_api/playwright.rb +32 -44
  56. data/lib/playwright_api/request.rb +7 -8
  57. data/lib/playwright_api/response.rb +10 -6
  58. data/lib/playwright_api/selectors.rb +13 -9
  59. data/lib/playwright_api/web_socket.rb +10 -1
  60. data/lib/playwright_api/worker.rb +13 -13
  61. metadata +12 -6
  62. data/lib/playwright/input_type.rb +0 -19
  63. data/lib/playwright/input_types/mouse.rb +0 -4
  64. data/lib/playwright/input_types/touchscreen.rb +0 -4
@@ -22,7 +22,7 @@ module Playwright
22
22
  # [`method: JSHandle.dispose`]. JSHandles are auto-disposed when their origin frame gets navigated or the parent context
23
23
  # gets destroyed.
24
24
  #
25
- # JSHandle instances can be used as an argument in [`method: Page.$eval`], [`method: Page.evaluate`] and
25
+ # JSHandle instances can be used as an argument in [`method: Page.evalOnSelector`], [`method: Page.evaluate`] and
26
26
  # [`method: Page.evaluateHandle`] methods.
27
27
  class JSHandle < PlaywrightApi
28
28
 
@@ -36,12 +36,11 @@ module Playwright
36
36
  wrap_impl(@impl.dispose)
37
37
  end
38
38
 
39
- # Returns the return value of `pageFunction`
39
+ # Returns the return value of `expression`.
40
40
  #
41
- # This method passes this handle as the first argument to `pageFunction`.
41
+ # This method passes this handle as the first argument to `expression`.
42
42
  #
43
- # If `pageFunction` returns a [Promise], then `handle.evaluate` would wait for the promise to resolve and return its
44
- # value.
43
+ # If `expression` returns a [Promise], then `handle.evaluate` would wait for the promise to resolve and return its value.
45
44
  #
46
45
  # Examples:
47
46
  #
@@ -60,23 +59,23 @@ module Playwright
60
59
  # tweet_handle = page.query_selector(".tweet .retweets")
61
60
  # assert tweet_handle.evaluate("node => node.innerText") == "10 retweets"
62
61
  # ```
63
- def evaluate(pageFunction, arg: nil)
64
- wrap_impl(@impl.evaluate(unwrap_impl(pageFunction), arg: unwrap_impl(arg)))
62
+ def evaluate(expression, arg: nil)
63
+ wrap_impl(@impl.evaluate(unwrap_impl(expression), arg: unwrap_impl(arg)))
65
64
  end
66
65
 
67
- # Returns the return value of `pageFunction` as in-page object (JSHandle).
66
+ # Returns the return value of `expression` as a `JSHandle`.
68
67
  #
69
- # This method passes this handle as the first argument to `pageFunction`.
68
+ # This method passes this handle as the first argument to `expression`.
70
69
  #
71
70
  # The only difference between `jsHandle.evaluate` and `jsHandle.evaluateHandle` is that `jsHandle.evaluateHandle` returns
72
- # in-page object (JSHandle).
71
+ # `JSHandle`.
73
72
  #
74
73
  # If the function passed to the `jsHandle.evaluateHandle` returns a [Promise], then `jsHandle.evaluateHandle` would wait
75
74
  # for the promise to resolve and return its value.
76
75
  #
77
76
  # See [`method: Page.evaluateHandle`] for more details.
78
- def evaluate_handle(pageFunction, arg: nil)
79
- wrap_impl(@impl.evaluate_handle(unwrap_impl(pageFunction), arg: unwrap_impl(arg)))
77
+ def evaluate_handle(expression, arg: nil)
78
+ wrap_impl(@impl.evaluate_handle(unwrap_impl(expression), arg: unwrap_impl(arg)))
80
79
  end
81
80
 
82
81
  # The method returns a map with **own property names** as keys and JSHandle instances for the property values.
@@ -123,27 +122,26 @@ module Playwright
123
122
  wrap_impl(@impl.json_value)
124
123
  end
125
124
 
125
+ # -- inherited from EventEmitter --
126
126
  # @nodoc
127
- def after_initialize
128
- wrap_impl(@impl.after_initialize)
127
+ def once(event, callback)
128
+ event_emitter_proxy.once(event, callback)
129
129
  end
130
130
 
131
131
  # -- inherited from EventEmitter --
132
132
  # @nodoc
133
133
  def on(event, callback)
134
- wrap_impl(@impl.on(unwrap_impl(event), unwrap_impl(callback)))
134
+ event_emitter_proxy.on(event, callback)
135
135
  end
136
136
 
137
137
  # -- inherited from EventEmitter --
138
138
  # @nodoc
139
139
  def off(event, callback)
140
- wrap_impl(@impl.off(unwrap_impl(event), unwrap_impl(callback)))
140
+ event_emitter_proxy.off(event, callback)
141
141
  end
142
142
 
143
- # -- inherited from EventEmitter --
144
- # @nodoc
145
- def once(event, callback)
146
- wrap_impl(@impl.once(unwrap_impl(event), unwrap_impl(callback)))
143
+ private def event_emitter_proxy
144
+ @event_emitter_proxy ||= EventEmitterProxy.new(self, @impl)
147
145
  end
148
146
  end
149
147
  end
@@ -114,7 +114,7 @@ module Playwright
114
114
  #
115
115
  # > NOTE: Modifier keys DO influence `keyboard.down`. Holding down `Shift` will type the text in upper case.
116
116
  def down(key)
117
- @impl.down(unwrap_impl(key))
117
+ wrap_impl(@impl.down(unwrap_impl(key)))
118
118
  end
119
119
 
120
120
  # Dispatches only `input` event, does not emit the `keydown`, `keyup` or `keypress` events.
@@ -134,7 +134,7 @@ module Playwright
134
134
  #
135
135
  # > NOTE: Modifier keys DO NOT effect `keyboard.insertText`. Holding down `Shift` will not type the text in upper case.
136
136
  def insert_text(text)
137
- @impl.insert_text(unwrap_impl(text))
137
+ wrap_impl(@impl.insert_text(unwrap_impl(text)))
138
138
  end
139
139
 
140
140
  # `key` can specify the intended [keyboardEvent.key](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key)
@@ -193,7 +193,7 @@ module Playwright
193
193
  #
194
194
  # Shortcut for [`method: Keyboard.down`] and [`method: Keyboard.up`].
195
195
  def press(key, delay: nil)
196
- @impl.press(unwrap_impl(key), delay: unwrap_impl(delay))
196
+ wrap_impl(@impl.press(unwrap_impl(key), delay: unwrap_impl(delay)))
197
197
  end
198
198
 
199
199
  # Sends a `keydown`, `keypress`/`input`, and `keyup` event for each character in the text.
@@ -218,12 +218,12 @@ module Playwright
218
218
  #
219
219
  # > NOTE: Modifier keys DO NOT effect `keyboard.type`. Holding down `Shift` will not type the text in upper case.
220
220
  def type(text, delay: nil)
221
- @impl.type(unwrap_impl(text), delay: unwrap_impl(delay))
221
+ wrap_impl(@impl.type(unwrap_impl(text), delay: unwrap_impl(delay)))
222
222
  end
223
223
 
224
224
  # Dispatches a `keyup` event.
225
225
  def up(key)
226
- @impl.up(unwrap_impl(key))
226
+ wrap_impl(@impl.up(unwrap_impl(key)))
227
227
  end
228
228
  end
229
229
  end
@@ -2,8 +2,8 @@ module Playwright
2
2
  # - extends: [EventEmitter]
3
3
  #
4
4
  # Page provides methods to interact with a single tab in a `Browser`, or an
5
- # [extension background page](https://developer.chrome.com/extensions/background_pages) in Chromium. One [Browser]
6
- # instance might have multiple [Page] instances.
5
+ # [extension background page](https://developer.chrome.com/extensions/background_pages) in Chromium. One `Browser`
6
+ # instance might have multiple `Page` instances.
7
7
  #
8
8
  # This example creates a page, navigates it to a URL, and then saves a screenshot:
9
9
  #
@@ -96,12 +96,6 @@ module Playwright
96
96
  wrap_impl(@impl.accessibility)
97
97
  end
98
98
 
99
- # Browser-specific Coverage implementation, only available for Chromium atm. See
100
- # `ChromiumCoverage`(#class-chromiumcoverage) for more details.
101
- def coverage # property
102
- raise NotImplementedError.new('coverage is not implemented yet.')
103
- end
104
-
105
99
  def keyboard # property
106
100
  wrap_impl(@impl.keyboard)
107
101
  end
@@ -114,78 +108,6 @@ module Playwright
114
108
  wrap_impl(@impl.touchscreen)
115
109
  end
116
110
 
117
- # The method finds an element matching the specified selector within the page. If no elements match the selector, the
118
- # return value resolves to `null`.
119
- #
120
- # Shortcut for main frame's [`method: Frame.$`].
121
- def query_selector(selector)
122
- wrap_impl(@impl.query_selector(unwrap_impl(selector)))
123
- end
124
-
125
- # The method finds all elements matching the specified selector within the page. If no elements match the selector, the
126
- # return value resolves to `[]`.
127
- #
128
- # Shortcut for main frame's [`method: Frame.$$`].
129
- def query_selector_all(selector)
130
- wrap_impl(@impl.query_selector_all(unwrap_impl(selector)))
131
- end
132
-
133
- # The method finds an element matching the specified selector within the page and passes it as a first argument to
134
- # `pageFunction`. If no elements match the selector, the method throws an error. Returns the value of `pageFunction`.
135
- #
136
- # If `pageFunction` returns a [Promise], then [`method: Page.$eval`] would wait for the promise to resolve and return its
137
- # value.
138
- #
139
- # Examples:
140
- #
141
- #
142
- # ```js
143
- # const searchValue = await page.$eval('#search', el => el.value);
144
- # const preloadHref = await page.$eval('link[rel=preload]', el => el.href);
145
- # const html = await page.$eval('.main-container', (e, suffix) => e.outerHTML + suffix, 'hello');
146
- # ```
147
- #
148
- # ```python async
149
- # search_value = await page.eval_on_selector("#search", "el => el.value")
150
- # preload_href = await page.eval_on_selector("link[rel=preload]", "el => el.href")
151
- # html = await page.eval_on_selector(".main-container", "(e, suffix) => e.outer_html + suffix", "hello")
152
- # ```
153
- #
154
- # ```python sync
155
- # search_value = page.eval_on_selector("#search", "el => el.value")
156
- # preload_href = page.eval_on_selector("link[rel=preload]", "el => el.href")
157
- # html = page.eval_on_selector(".main-container", "(e, suffix) => e.outer_html + suffix", "hello")
158
- # ```
159
- #
160
- # Shortcut for main frame's [`method: Frame.$eval`].
161
- def eval_on_selector(selector, pageFunction, arg: nil)
162
- wrap_impl(@impl.eval_on_selector(unwrap_impl(selector), unwrap_impl(pageFunction), arg: unwrap_impl(arg)))
163
- end
164
-
165
- # The method finds all elements matching the specified selector within the page and passes an array of matched elements as
166
- # a first argument to `pageFunction`. Returns the result of `pageFunction` invocation.
167
- #
168
- # If `pageFunction` returns a [Promise], then [`method: Page.$$eval`] would wait for the promise to resolve and return its
169
- # value.
170
- #
171
- # Examples:
172
- #
173
- #
174
- # ```js
175
- # const divCounts = await page.$$eval('div', (divs, min) => divs.length >= min, 10);
176
- # ```
177
- #
178
- # ```python async
179
- # div_counts = await page.eval_on_selector_all("div", "(divs, min) => divs.length >= min", 10)
180
- # ```
181
- #
182
- # ```python sync
183
- # div_counts = page.eval_on_selector_all("div", "(divs, min) => divs.length >= min", 10)
184
- # ```
185
- def eval_on_selector_all(selector, pageFunction, arg: nil)
186
- wrap_impl(@impl.eval_on_selector_all(unwrap_impl(selector), unwrap_impl(pageFunction), arg: unwrap_impl(arg)))
187
- end
188
-
189
111
  # Adds a script which would be evaluated in one of the following scenarios:
190
112
  # - Whenever the page is navigated.
191
113
  # - Whenever the child frame is attached or navigated. In this case, the script is evaluated in the context of the newly
@@ -220,8 +142,8 @@ module Playwright
220
142
  #
221
143
  # > NOTE: The order of evaluation of multiple scripts installed via [`method: BrowserContext.addInitScript`] and
222
144
  # [`method: Page.addInitScript`] is not defined.
223
- def add_init_script(script, arg: nil)
224
- raise NotImplementedError.new('add_init_script is not implemented yet.')
145
+ def add_init_script(path: nil, script: nil)
146
+ wrap_impl(@impl.add_init_script(path: unwrap_impl(path), script: unwrap_impl(script)))
225
147
  end
226
148
 
227
149
  # Adds a `<script>` tag into the page with the desired url or content. Returns the added tag when the script's onload
@@ -229,7 +151,7 @@ module Playwright
229
151
  #
230
152
  # Shortcut for main frame's [`method: Frame.addScriptTag`].
231
153
  def add_script_tag(content: nil, path: nil, type: nil, url: nil)
232
- raise NotImplementedError.new('add_script_tag is not implemented yet.')
154
+ wrap_impl(@impl.add_script_tag(content: unwrap_impl(content), path: unwrap_impl(path), type: unwrap_impl(type), url: unwrap_impl(url)))
233
155
  end
234
156
 
235
157
  # Adds a `<link rel="stylesheet">` tag into the page with the desired url or a `<style type="text/css">` tag with the
@@ -237,12 +159,12 @@ module Playwright
237
159
  #
238
160
  # Shortcut for main frame's [`method: Frame.addStyleTag`].
239
161
  def add_style_tag(content: nil, path: nil, url: nil)
240
- raise NotImplementedError.new('add_style_tag is not implemented yet.')
162
+ wrap_impl(@impl.add_style_tag(content: unwrap_impl(content), path: unwrap_impl(path), url: unwrap_impl(url)))
241
163
  end
242
164
 
243
165
  # Brings page to front (activates tab).
244
166
  def bring_to_front
245
- raise NotImplementedError.new('bring_to_front is not implemented yet.')
167
+ wrap_impl(@impl.bring_to_front)
246
168
  end
247
169
 
248
170
  # This method checks an element matching `selector` by performing the following steps:
@@ -261,7 +183,7 @@ module Playwright
261
183
  #
262
184
  # Shortcut for main frame's [`method: Frame.check`].
263
185
  def check(selector, force: nil, noWaitAfter: nil, timeout: nil)
264
- raise NotImplementedError.new('check is not implemented yet.')
186
+ wrap_impl(@impl.check(unwrap_impl(selector), force: unwrap_impl(force), noWaitAfter: unwrap_impl(noWaitAfter), timeout: unwrap_impl(timeout)))
265
187
  end
266
188
 
267
189
  # This method clicks an element matching `selector` by performing the following steps:
@@ -387,7 +309,7 @@ module Playwright
387
309
  # page.dispatch_event("#source", "dragstart", { "dataTransfer": data_transfer })
388
310
  # ```
389
311
  def dispatch_event(selector, type, eventInit: nil, timeout: nil)
390
- raise NotImplementedError.new('dispatch_event is not implemented yet.')
312
+ wrap_impl(@impl.dispatch_event(unwrap_impl(selector), unwrap_impl(type), eventInit: unwrap_impl(eventInit), timeout: unwrap_impl(timeout)))
391
313
  end
392
314
 
393
315
  #
@@ -478,20 +400,76 @@ module Playwright
478
400
  # # → False
479
401
  # page.evaluate("matchMedia('(prefers-color-scheme: no-preference)').matches")
480
402
  # ```
481
- def emulate_media(params)
482
- raise NotImplementedError.new('emulate_media is not implemented yet.')
403
+ def emulate_media(colorScheme: nil, media: nil)
404
+ wrap_impl(@impl.emulate_media(colorScheme: unwrap_impl(colorScheme), media: unwrap_impl(media)))
483
405
  end
484
406
 
485
- # Returns the value of the `pageFunction` invocation.
407
+ # The method finds an element matching the specified selector within the page and passes it as a first argument to
408
+ # `expression`. If no elements match the selector, the method throws an error. Returns the value of `expression`.
409
+ #
410
+ # If `expression` returns a [Promise], then [`method: Page.evalOnSelector`] would wait for the promise to resolve and
411
+ # return its value.
412
+ #
413
+ # Examples:
414
+ #
415
+ #
416
+ # ```js
417
+ # const searchValue = await page.$eval('#search', el => el.value);
418
+ # const preloadHref = await page.$eval('link[rel=preload]', el => el.href);
419
+ # const html = await page.$eval('.main-container', (e, suffix) => e.outerHTML + suffix, 'hello');
420
+ # ```
421
+ #
422
+ # ```python async
423
+ # search_value = await page.eval_on_selector("#search", "el => el.value")
424
+ # preload_href = await page.eval_on_selector("link[rel=preload]", "el => el.href")
425
+ # html = await page.eval_on_selector(".main-container", "(e, suffix) => e.outer_html + suffix", "hello")
426
+ # ```
427
+ #
428
+ # ```python sync
429
+ # search_value = page.eval_on_selector("#search", "el => el.value")
430
+ # preload_href = page.eval_on_selector("link[rel=preload]", "el => el.href")
431
+ # html = page.eval_on_selector(".main-container", "(e, suffix) => e.outer_html + suffix", "hello")
432
+ # ```
433
+ #
434
+ # Shortcut for main frame's [`method: Frame.evalOnSelector`].
435
+ def eval_on_selector(selector, expression, arg: nil)
436
+ wrap_impl(@impl.eval_on_selector(unwrap_impl(selector), unwrap_impl(expression), arg: unwrap_impl(arg)))
437
+ end
438
+
439
+ # The method finds all elements matching the specified selector within the page and passes an array of matched elements as
440
+ # a first argument to `expression`. Returns the result of `expression` invocation.
441
+ #
442
+ # If `expression` returns a [Promise], then [`method: Page.evalOnSelectorAll`] would wait for the promise to resolve and
443
+ # return its value.
444
+ #
445
+ # Examples:
446
+ #
447
+ #
448
+ # ```js
449
+ # const divCounts = await page.$$eval('div', (divs, min) => divs.length >= min, 10);
450
+ # ```
451
+ #
452
+ # ```python async
453
+ # div_counts = await page.eval_on_selector_all("div", "(divs, min) => divs.length >= min", 10)
454
+ # ```
455
+ #
456
+ # ```python sync
457
+ # div_counts = page.eval_on_selector_all("div", "(divs, min) => divs.length >= min", 10)
458
+ # ```
459
+ def eval_on_selector_all(selector, expression, arg: nil)
460
+ wrap_impl(@impl.eval_on_selector_all(unwrap_impl(selector), unwrap_impl(expression), arg: unwrap_impl(arg)))
461
+ end
462
+
463
+ # Returns the value of the `expression` invocation.
486
464
  #
487
465
  # If the function passed to the [`method: Page.evaluate`] returns a [Promise], then [`method: Page.evaluate`] would wait
488
466
  # for the promise to resolve and return its value.
489
467
  #
490
- # If the function passed to the [`method: Page.evaluate`] returns a non-[Serializable] value,
491
- # then[ method: `Page.evaluate`] resolves to `undefined`. DevTools Protocol also supports transferring some additional
492
- # values that are not serializable by `JSON`: `-0`, `NaN`, `Infinity`, `-Infinity`, and bigint literals.
468
+ # If the function passed to the [`method: Page.evaluate`] returns a non-[Serializable] value, then
469
+ # [`method: Page.evaluate`] resolves to `undefined`. Playwright also supports transferring some additional values that are
470
+ # not serializable by `JSON`: `-0`, `NaN`, `Infinity`, `-Infinity`.
493
471
  #
494
- # Passing argument to `pageFunction`:
472
+ # Passing argument to `expression`:
495
473
  #
496
474
  #
497
475
  # ```js
@@ -554,14 +532,14 @@ module Playwright
554
532
  # ```
555
533
  #
556
534
  # Shortcut for main frame's [`method: Frame.evaluate`].
557
- def evaluate(pageFunction, arg: nil)
558
- wrap_impl(@impl.evaluate(unwrap_impl(pageFunction), arg: unwrap_impl(arg)))
535
+ def evaluate(expression, arg: nil)
536
+ wrap_impl(@impl.evaluate(unwrap_impl(expression), arg: unwrap_impl(arg)))
559
537
  end
560
538
 
561
- # Returns the value of the `pageFunction` invocation as in-page object (JSHandle).
539
+ # Returns the value of the `expression` invocation as a `JSHandle`.
562
540
  #
563
541
  # The only difference between [`method: Page.evaluate`] and [`method: Page.evaluateHandle`] is that
564
- # [`method: Page.evaluateHandle`] returns in-page object (JSHandle).
542
+ # [`method: Page.evaluateHandle`] returns `JSHandle`.
565
543
  #
566
544
  # If the function passed to the [`method: Page.evaluateHandle`] returns a [Promise], then [`method: Page.evaluateHandle`]
567
545
  # would wait for the promise to resolve and return its value.
@@ -573,7 +551,6 @@ module Playwright
573
551
  # ```
574
552
  #
575
553
  # ```python async
576
- # # FIXME
577
554
  # a_window_handle = await page.evaluate_handle("Promise.resolve(window)")
578
555
  # a_window_handle # handle for the window object.
579
556
  # ```
@@ -621,8 +598,8 @@ module Playwright
621
598
  # print(result_handle.json_value())
622
599
  # result_handle.dispose()
623
600
  # ```
624
- def evaluate_handle(pageFunction, arg: nil)
625
- wrap_impl(@impl.evaluate_handle(unwrap_impl(pageFunction), arg: unwrap_impl(arg)))
601
+ def evaluate_handle(expression, arg: nil)
602
+ wrap_impl(@impl.evaluate_handle(unwrap_impl(expression), arg: unwrap_impl(arg)))
626
603
  end
627
604
 
628
605
  # The method adds a function called `name` on the `window` object of every frame in this page. When called, the function
@@ -755,7 +732,7 @@ module Playwright
755
732
  # """)
756
733
  # ```
757
734
  def expose_binding(name, callback, handle: nil)
758
- raise NotImplementedError.new('expose_binding is not implemented yet.')
735
+ wrap_impl(@impl.expose_binding(unwrap_impl(name), unwrap_impl(callback), handle: unwrap_impl(handle)))
759
736
  end
760
737
 
761
738
  # The method adds a function called `name` on the `window` object of every frame in the page. When called, the function
@@ -854,13 +831,14 @@ module Playwright
854
831
  # run(playwright)
855
832
  # ```
856
833
  def expose_function(name, callback)
857
- raise NotImplementedError.new('expose_function is not implemented yet.')
834
+ wrap_impl(@impl.expose_function(unwrap_impl(name), unwrap_impl(callback)))
858
835
  end
859
836
 
860
837
  # This method waits for an element matching `selector`, waits for [actionability](./actionability.md) checks, focuses the
861
- # element, fills it and triggers an `input` event after filling. If the element matching `selector` is not an `<input>`,
862
- # `<textarea>` or `[contenteditable]` element, this method throws an error. Note that you can pass an empty string to
863
- # clear the input field.
838
+ # element, fills it and triggers an `input` event after filling. If the element is inside the `<label>` element that has
839
+ # associated [control](https://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement/control), that control will be
840
+ # filled instead. If the element to be filled is not an `<input>`, `<textarea>` or `[contenteditable]` element, this
841
+ # method throws an error. Note that you can pass an empty string to clear the input field.
864
842
  #
865
843
  # To send fine-grained keyboard events, use [`method: Page.type`].
866
844
  #
@@ -896,8 +874,8 @@ module Playwright
896
874
  # ```py
897
875
  # frame = page.frame(url=r".*domain.*")
898
876
  # ```
899
- def frame(frameSelector)
900
- wrap_impl(@impl.frame(unwrap_impl(frameSelector)))
877
+ def frame(name: nil, url: nil)
878
+ wrap_impl(@impl.frame(name: unwrap_impl(name), url: unwrap_impl(url)))
901
879
  end
902
880
 
903
881
  # An array of all frames attached to the page.
@@ -907,16 +885,15 @@ module Playwright
907
885
 
908
886
  # Returns element attribute value.
909
887
  def get_attribute(selector, name, timeout: nil)
910
- raise NotImplementedError.new('get_attribute is not implemented yet.')
888
+ wrap_impl(@impl.get_attribute(unwrap_impl(selector), unwrap_impl(name), timeout: unwrap_impl(timeout)))
911
889
  end
912
- alias_method :[], :get_attribute
913
890
 
914
891
  # Returns the main resource response. In case of multiple redirects, the navigation will resolve with the response of the
915
892
  # last redirect. If can not go back, returns `null`.
916
893
  #
917
894
  # Navigate to the previous page in history.
918
895
  def go_back(timeout: nil, waitUntil: nil)
919
- raise NotImplementedError.new('go_back is not implemented yet.')
896
+ wrap_impl(@impl.go_back(timeout: unwrap_impl(timeout), waitUntil: unwrap_impl(waitUntil)))
920
897
  end
921
898
 
922
899
  # Returns the main resource response. In case of multiple redirects, the navigation will resolve with the response of the
@@ -924,7 +901,7 @@ module Playwright
924
901
  #
925
902
  # Navigate to the next page in history.
926
903
  def go_forward(timeout: nil, waitUntil: nil)
927
- raise NotImplementedError.new('go_forward is not implemented yet.')
904
+ wrap_impl(@impl.go_forward(timeout: unwrap_impl(timeout), waitUntil: unwrap_impl(waitUntil)))
928
905
  end
929
906
 
930
907
  # Returns the main resource response. In case of multiple redirects, the navigation will resolve with the response of the
@@ -969,22 +946,22 @@ module Playwright
969
946
  modifiers: nil,
970
947
  position: nil,
971
948
  timeout: nil)
972
- raise NotImplementedError.new('hover is not implemented yet.')
949
+ wrap_impl(@impl.hover(unwrap_impl(selector), force: unwrap_impl(force), modifiers: unwrap_impl(modifiers), position: unwrap_impl(position), timeout: unwrap_impl(timeout)))
973
950
  end
974
951
 
975
952
  # Returns `element.innerHTML`.
976
953
  def inner_html(selector, timeout: nil)
977
- raise NotImplementedError.new('inner_html is not implemented yet.')
954
+ wrap_impl(@impl.inner_html(unwrap_impl(selector), timeout: unwrap_impl(timeout)))
978
955
  end
979
956
 
980
957
  # Returns `element.innerText`.
981
958
  def inner_text(selector, timeout: nil)
982
- raise NotImplementedError.new('inner_text is not implemented yet.')
959
+ wrap_impl(@impl.inner_text(unwrap_impl(selector), timeout: unwrap_impl(timeout)))
983
960
  end
984
961
 
985
962
  # Returns whether the element is checked. Throws if the element is not a checkbox or radio input.
986
963
  def checked?(selector, timeout: nil)
987
- raise NotImplementedError.new('checked? is not implemented yet.')
964
+ wrap_impl(@impl.checked?(unwrap_impl(selector), timeout: unwrap_impl(timeout)))
988
965
  end
989
966
 
990
967
  # Indicates that the page has been closed.
@@ -994,27 +971,27 @@ module Playwright
994
971
 
995
972
  # Returns whether the element is disabled, the opposite of [enabled](./actionability.md#enabled).
996
973
  def disabled?(selector, timeout: nil)
997
- raise NotImplementedError.new('disabled? is not implemented yet.')
974
+ wrap_impl(@impl.disabled?(unwrap_impl(selector), timeout: unwrap_impl(timeout)))
998
975
  end
999
976
 
1000
977
  # Returns whether the element is [editable](./actionability.md#editable).
1001
978
  def editable?(selector, timeout: nil)
1002
- raise NotImplementedError.new('editable? is not implemented yet.')
979
+ wrap_impl(@impl.editable?(unwrap_impl(selector), timeout: unwrap_impl(timeout)))
1003
980
  end
1004
981
 
1005
982
  # Returns whether the element is [enabled](./actionability.md#enabled).
1006
983
  def enabled?(selector, timeout: nil)
1007
- raise NotImplementedError.new('enabled? is not implemented yet.')
984
+ wrap_impl(@impl.enabled?(unwrap_impl(selector), timeout: unwrap_impl(timeout)))
1008
985
  end
1009
986
 
1010
987
  # Returns whether the element is hidden, the opposite of [visible](./actionability.md#visible).
1011
988
  def hidden?(selector, timeout: nil)
1012
- raise NotImplementedError.new('hidden? is not implemented yet.')
989
+ wrap_impl(@impl.hidden?(unwrap_impl(selector), timeout: unwrap_impl(timeout)))
1013
990
  end
1014
991
 
1015
992
  # Returns whether the element is [visible](./actionability.md#visible).
1016
993
  def visible?(selector, timeout: nil)
1017
- raise NotImplementedError.new('visible? is not implemented yet.')
994
+ wrap_impl(@impl.visible?(unwrap_impl(selector), timeout: unwrap_impl(timeout)))
1018
995
  end
1019
996
 
1020
997
  # The page's main frame. Page is guaranteed to have a main frame which persists during navigations.
@@ -1027,6 +1004,18 @@ module Playwright
1027
1004
  wrap_impl(@impl.opener)
1028
1005
  end
1029
1006
 
1007
+ # Pauses script execution. Playwright will stop executing the script and wait for the user to either press 'Resume' button
1008
+ # in the page overlay or to call `playwright.resume()` in the DevTools console.
1009
+ #
1010
+ # User can inspect selectors or perform manual steps while paused. Resume will continue running the original script from
1011
+ # the place it was paused.
1012
+ #
1013
+ # > NOTE: This method requires Playwright to be started in a headed mode, with a falsy [`options: headless`] value in the
1014
+ # [`method: BrowserType.launch`].
1015
+ def pause
1016
+ raise NotImplementedError.new('pause is not implemented yet.')
1017
+ end
1018
+
1030
1019
  # Returns the PDF buffer.
1031
1020
  #
1032
1021
  # > NOTE: Generating a pdf is currently only supported in Chromium headless.
@@ -1099,7 +1088,7 @@ module Playwright
1099
1088
  printBackground: nil,
1100
1089
  scale: nil,
1101
1090
  width: nil)
1102
- raise NotImplementedError.new('pdf is not implemented yet.')
1091
+ wrap_impl(@impl.pdf(displayHeaderFooter: unwrap_impl(displayHeaderFooter), footerTemplate: unwrap_impl(footerTemplate), format: unwrap_impl(format), headerTemplate: unwrap_impl(headerTemplate), height: unwrap_impl(height), landscape: unwrap_impl(landscape), margin: unwrap_impl(margin), pageRanges: unwrap_impl(pageRanges), path: unwrap_impl(path), preferCSSPageSize: unwrap_impl(preferCSSPageSize), printBackground: unwrap_impl(printBackground), scale: unwrap_impl(scale), width: unwrap_impl(width)))
1103
1092
  end
1104
1093
 
1105
1094
  # Focuses the element, and then uses [`method: Keyboard.down`] and [`method: Keyboard.up`].
@@ -1166,6 +1155,22 @@ module Playwright
1166
1155
  wrap_impl(@impl.press(unwrap_impl(selector), unwrap_impl(key), delay: unwrap_impl(delay), noWaitAfter: unwrap_impl(noWaitAfter), timeout: unwrap_impl(timeout)))
1167
1156
  end
1168
1157
 
1158
+ # The method finds an element matching the specified selector within the page. If no elements match the selector, the
1159
+ # return value resolves to `null`.
1160
+ #
1161
+ # Shortcut for main frame's [`method: Frame.querySelector`].
1162
+ def query_selector(selector)
1163
+ wrap_impl(@impl.query_selector(unwrap_impl(selector)))
1164
+ end
1165
+
1166
+ # The method finds all elements matching the specified selector within the page. If no elements match the selector, the
1167
+ # return value resolves to `[]`.
1168
+ #
1169
+ # Shortcut for main frame's [`method: Frame.querySelectorAll`].
1170
+ def query_selector_all(selector)
1171
+ wrap_impl(@impl.query_selector_all(unwrap_impl(selector)))
1172
+ end
1173
+
1169
1174
  # Returns the main resource response. In case of multiple redirects, the navigation will resolve with the response of the
1170
1175
  # last redirect.
1171
1176
  def reload(timeout: nil, waitUntil: nil)
@@ -1288,8 +1293,15 @@ module Playwright
1288
1293
  # ```
1289
1294
  #
1290
1295
  # Shortcut for main frame's [`method: Frame.selectOption`]
1291
- def select_option(selector, values, noWaitAfter: nil, timeout: nil)
1292
- raise NotImplementedError.new('select_option is not implemented yet.')
1296
+ def select_option(
1297
+ selector,
1298
+ element: nil,
1299
+ index: nil,
1300
+ value: nil,
1301
+ label: nil,
1302
+ noWaitAfter: nil,
1303
+ timeout: nil)
1304
+ wrap_impl(@impl.select_option(unwrap_impl(selector), element: unwrap_impl(element), index: unwrap_impl(index), value: unwrap_impl(value), label: unwrap_impl(label), noWaitAfter: unwrap_impl(noWaitAfter), timeout: unwrap_impl(timeout)))
1293
1305
  end
1294
1306
 
1295
1307
  def set_content(html, timeout: nil, waitUntil: nil)
@@ -1308,7 +1320,7 @@ module Playwright
1308
1320
  # > NOTE: [`method: Page.setDefaultNavigationTimeout`] takes priority over [`method: Page.setDefaultTimeout`],
1309
1321
  # [`method: BrowserContext.setDefaultTimeout`] and [`method: BrowserContext.setDefaultNavigationTimeout`].
1310
1322
  def set_default_navigation_timeout(timeout)
1311
- raise NotImplementedError.new('set_default_navigation_timeout is not implemented yet.')
1323
+ wrap_impl(@impl.set_default_navigation_timeout(unwrap_impl(timeout)))
1312
1324
  end
1313
1325
  alias_method :default_navigation_timeout=, :set_default_navigation_timeout
1314
1326
 
@@ -1316,7 +1328,7 @@ module Playwright
1316
1328
  #
1317
1329
  # > NOTE: [`method: Page.setDefaultNavigationTimeout`] takes priority over [`method: Page.setDefaultTimeout`].
1318
1330
  def set_default_timeout(timeout)
1319
- raise NotImplementedError.new('set_default_timeout is not implemented yet.')
1331
+ wrap_impl(@impl.set_default_timeout(unwrap_impl(timeout)))
1320
1332
  end
1321
1333
  alias_method :default_timeout=, :set_default_timeout
1322
1334
 
@@ -1324,7 +1336,7 @@ module Playwright
1324
1336
  #
1325
1337
  # > NOTE: [`method: Page.setExtraHTTPHeaders`] does not guarantee the order of headers in the outgoing requests.
1326
1338
  def set_extra_http_headers(headers)
1327
- raise NotImplementedError.new('set_extra_http_headers is not implemented yet.')
1339
+ wrap_impl(@impl.set_extra_http_headers(unwrap_impl(headers)))
1328
1340
  end
1329
1341
  alias_method :extra_http_headers=, :set_extra_http_headers
1330
1342
 
@@ -1334,7 +1346,7 @@ module Playwright
1334
1346
  # Sets the value of the file input to these file paths or files. If some of the `filePaths` are relative paths, then they
1335
1347
  # are resolved relative to the the current working directory. For empty array, clears the selected files.
1336
1348
  def set_input_files(selector, files, noWaitAfter: nil, timeout: nil)
1337
- raise NotImplementedError.new('set_input_files is not implemented yet.')
1349
+ wrap_impl(@impl.set_input_files(unwrap_impl(selector), unwrap_impl(files), noWaitAfter: unwrap_impl(noWaitAfter), timeout: unwrap_impl(timeout)))
1338
1350
  end
1339
1351
 
1340
1352
  # In the case of multiple pages in a single browser, each page can have its own viewport size. However,
@@ -1390,12 +1402,12 @@ module Playwright
1390
1402
  noWaitAfter: nil,
1391
1403
  position: nil,
1392
1404
  timeout: nil)
1393
- raise NotImplementedError.new('tap_point is not implemented yet.')
1405
+ wrap_impl(@impl.tap_point(unwrap_impl(selector), force: unwrap_impl(force), modifiers: unwrap_impl(modifiers), noWaitAfter: unwrap_impl(noWaitAfter), position: unwrap_impl(position), timeout: unwrap_impl(timeout)))
1394
1406
  end
1395
1407
 
1396
1408
  # Returns `element.textContent`.
1397
1409
  def text_content(selector, timeout: nil)
1398
- raise NotImplementedError.new('text_content is not implemented yet.')
1410
+ wrap_impl(@impl.text_content(unwrap_impl(selector), timeout: unwrap_impl(timeout)))
1399
1411
  end
1400
1412
 
1401
1413
  # Returns the page's title. Shortcut for main frame's [`method: Frame.title`].
@@ -1450,7 +1462,7 @@ module Playwright
1450
1462
  #
1451
1463
  # Shortcut for main frame's [`method: Frame.uncheck`].
1452
1464
  def uncheck(selector, force: nil, noWaitAfter: nil, timeout: nil)
1453
- raise NotImplementedError.new('uncheck is not implemented yet.')
1465
+ wrap_impl(@impl.uncheck(unwrap_impl(selector), force: unwrap_impl(force), noWaitAfter: unwrap_impl(noWaitAfter), timeout: unwrap_impl(timeout)))
1454
1466
  end
1455
1467
 
1456
1468
  # Removes a route created with [`method: Page.route`]. When `handler` is not specified, removes all routes for the `url`.
@@ -1494,13 +1506,13 @@ module Playwright
1494
1506
  # page.click("button")
1495
1507
  # frame = event_info.value
1496
1508
  # ```
1497
- def expect_event(event, optionsOrPredicate: nil, &block)
1498
- wrap_impl(@impl.expect_event(unwrap_impl(event), optionsOrPredicate: unwrap_impl(optionsOrPredicate), &wrap_block_call(block)))
1509
+ def expect_event(event, predicate: nil, timeout: nil, &block)
1510
+ wrap_impl(@impl.expect_event(unwrap_impl(event), predicate: unwrap_impl(predicate), timeout: unwrap_impl(timeout), &wrap_block_call(block)))
1499
1511
  end
1500
1512
 
1501
- # Returns when the `pageFunction` returns a truthy value. It resolves to a JSHandle of the truthy value.
1513
+ # Returns when the `expression` returns a truthy value. It resolves to a JSHandle of the truthy value.
1502
1514
  #
1503
- # The `waitForFunction` can be used to observe viewport size change:
1515
+ # The [`method: Page.waitForFunction`] can be used to observe viewport size change:
1504
1516
  #
1505
1517
  #
1506
1518
  # ```js
@@ -1524,7 +1536,7 @@ module Playwright
1524
1536
  # webkit = playwright.webkit
1525
1537
  # browser = await webkit.launch()
1526
1538
  # page = await browser.new_page()
1527
- # await page.evaluate("window.x = 0; setTimeout(() => { window.x = 100 }, 1000);", force_expr=True)
1539
+ # await page.evaluate("window.x = 0; setTimeout(() => { window.x = 100 }, 1000);")
1528
1540
  # await page.wait_for_function("() => window.x > 0")
1529
1541
  # await browser.close()
1530
1542
  #
@@ -1541,7 +1553,7 @@ module Playwright
1541
1553
  # webkit = playwright.webkit
1542
1554
  # browser = webkit.launch()
1543
1555
  # page = browser.new_page()
1544
- # page.evaluate("window.x = 0; setTimeout(() => { window.x = 100 }, 1000);", force_expr=True)
1556
+ # page.evaluate("window.x = 0; setTimeout(() => { window.x = 100 }, 1000);")
1545
1557
  # page.wait_for_function("() => window.x > 0")
1546
1558
  # browser.close()
1547
1559
  #
@@ -1568,8 +1580,8 @@ module Playwright
1568
1580
  # ```
1569
1581
  #
1570
1582
  # Shortcut for main frame's [`method: Frame.waitForFunction`].
1571
- def wait_for_function(pageFunction, arg: nil, polling: nil, timeout: nil)
1572
- raise NotImplementedError.new('wait_for_function is not implemented yet.')
1583
+ def wait_for_function(expression, arg: nil, polling: nil, timeout: nil)
1584
+ wrap_impl(@impl.wait_for_function(unwrap_impl(expression), arg: unwrap_impl(arg), polling: unwrap_impl(polling), timeout: unwrap_impl(timeout)))
1573
1585
  end
1574
1586
 
1575
1587
  # Returns when the required load state has been reached.
@@ -1785,7 +1797,7 @@ module Playwright
1785
1797
  # run(playwright)
1786
1798
  # ```
1787
1799
  def wait_for_selector(selector, state: nil, timeout: nil)
1788
- raise NotImplementedError.new('wait_for_selector is not implemented yet.')
1800
+ wrap_impl(@impl.wait_for_selector(unwrap_impl(selector), state: unwrap_impl(state), timeout: unwrap_impl(timeout)))
1789
1801
  end
1790
1802
 
1791
1803
  # Waits for the given `timeout` in milliseconds.
@@ -1822,9 +1834,48 @@ module Playwright
1822
1834
  raise NotImplementedError.new('workers is not implemented yet.')
1823
1835
  end
1824
1836
 
1825
- # @nodoc
1826
- def after_initialize
1827
- wrap_impl(@impl.after_initialize)
1837
+ # Performs action and waits for `download` event to fire. If predicate is provided, it passes `Download` value into the
1838
+ # `predicate` function and waits for `predicate(event)` to return a truthy value. Will throw an error if the page is
1839
+ # closed before the download event is fired.
1840
+ def expect_download(predicate: nil, timeout: nil, &block)
1841
+ wrap_impl(@impl.expect_download(predicate: unwrap_impl(predicate), timeout: unwrap_impl(timeout), &wrap_block_call(block)))
1842
+ end
1843
+
1844
+ # Performs action and waits for `popup` event to fire. If predicate is provided, it passes [Popup] value into the
1845
+ # `predicate` function and waits for `predicate(event)` to return a truthy value. Will throw an error if the page is
1846
+ # closed before the popup event is fired.
1847
+ def expect_popup(predicate: nil, timeout: nil, &block)
1848
+ wrap_impl(@impl.expect_popup(predicate: unwrap_impl(predicate), timeout: unwrap_impl(timeout), &wrap_block_call(block)))
1849
+ end
1850
+
1851
+ # Performs action and waits for `worker` event to fire. If predicate is provided, it passes `Worker` value into the
1852
+ # `predicate` function and waits for `predicate(event)` to return a truthy value. Will throw an error if the page is
1853
+ # closed before the worker event is fired.
1854
+ def expect_worker(predicate: nil, timeout: nil)
1855
+ raise NotImplementedError.new('expect_worker is not implemented yet.')
1856
+ end
1857
+
1858
+ # Performs action and waits for `console` event to fire. If predicate is provided, it passes `ConsoleMessage` value into
1859
+ # the `predicate` function and waits for `predicate(event)` to return a truthy value. Will throw an error if the page is
1860
+ # closed before the worker event is fired.
1861
+ def expect_console_message(predicate: nil, timeout: nil, &block)
1862
+ wrap_impl(@impl.expect_console_message(predicate: unwrap_impl(predicate), timeout: unwrap_impl(timeout), &wrap_block_call(block)))
1863
+ end
1864
+
1865
+ # Performs action and waits for `filechooser` event to fire. If predicate is provided, it passes `FileChooser` value into
1866
+ # the `predicate` function and waits for `predicate(event)` to return a truthy value. Will throw an error if the page is
1867
+ # closed before the worker event is fired.
1868
+ def expect_file_chooser(predicate: nil, timeout: nil, &block)
1869
+ wrap_impl(@impl.expect_file_chooser(predicate: unwrap_impl(predicate), timeout: unwrap_impl(timeout), &wrap_block_call(block)))
1870
+ end
1871
+
1872
+ # > NOTE: In most cases, you should use [`method: Page.waitForEvent`].
1873
+ #
1874
+ # Waits for given `event` to fire. If predicate is provided, it passes event's value into the `predicate` function and
1875
+ # waits for `predicate(event)` to return a truthy value. Will throw an error if the socket is closed before the `event` is
1876
+ # fired.
1877
+ def wait_for_event(event, predicate: nil, timeout: nil)
1878
+ raise NotImplementedError.new('wait_for_event is not implemented yet.')
1828
1879
  end
1829
1880
 
1830
1881
  # @nodoc
@@ -1834,20 +1885,24 @@ module Playwright
1834
1885
 
1835
1886
  # -- inherited from EventEmitter --
1836
1887
  # @nodoc
1837
- def on(event, callback)
1838
- wrap_impl(@impl.on(unwrap_impl(event), unwrap_impl(callback)))
1888
+ def once(event, callback)
1889
+ event_emitter_proxy.once(event, callback)
1839
1890
  end
1840
1891
 
1841
1892
  # -- inherited from EventEmitter --
1842
1893
  # @nodoc
1843
- def off(event, callback)
1844
- wrap_impl(@impl.off(unwrap_impl(event), unwrap_impl(callback)))
1894
+ def on(event, callback)
1895
+ event_emitter_proxy.on(event, callback)
1845
1896
  end
1846
1897
 
1847
1898
  # -- inherited from EventEmitter --
1848
1899
  # @nodoc
1849
- def once(event, callback)
1850
- wrap_impl(@impl.once(unwrap_impl(event), unwrap_impl(callback)))
1900
+ def off(event, callback)
1901
+ event_emitter_proxy.off(event, callback)
1902
+ end
1903
+
1904
+ private def event_emitter_proxy
1905
+ @event_emitter_proxy ||= EventEmitterProxy.new(self, @impl)
1851
1906
  end
1852
1907
  end
1853
1908
  end