playwright-ruby-client 1.14.beta3 → 1.14.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/documentation/docs/api/element_handle.md +3 -4
- data/documentation/docs/api/locator.md +25 -38
- data/documentation/docs/api/worker.md +12 -11
- data/documentation/docs/article/guides/inspector.md +1 -1
- data/documentation/docs/article/guides/playwright_on_alpine_linux.md +1 -1
- data/documentation/docs/article/guides/semi_automation.md +1 -1
- data/documentation/docs/article/guides/use_storage_state.md +78 -0
- data/lib/playwright/version.rb +1 -1
- metadata +5 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d6f164b2d4296ab3f30bfb22cd5fbec86ab522df916913ab19731dd452c55efa
|
4
|
+
data.tar.gz: 56371e88f29c8a7e7e398582a7cda693f45d8ebbb5bf6ce6e3fa0e748a2175bc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d97fd45d76a1cf4202be4aae7527974b01d8f90fd1de5e4fb4ed1267d3d3eeb601d5dddc49eb70559688c6bc816df82bc8c667e6aec7d2226ce078a2e0182a25
|
7
|
+
data.tar.gz: 602c97a88eb16aab95590391ae26f7ba777904668d4e270e3e24fe05122606d3f23d68901e529bb28b23a91458cdf7ce165de0c87621e0ad4ef9f8a711ccaf5f
|
@@ -641,12 +641,11 @@ become visible/hidden). If at the moment of calling the method `selector` alread
|
|
641
641
|
will return immediately. If the selector doesn't satisfy the condition for the `timeout` milliseconds, the function will
|
642
642
|
throw.
|
643
643
|
|
644
|
-
```
|
645
|
-
page.
|
644
|
+
```ruby
|
645
|
+
page.content = "<div><span></span></div>"
|
646
646
|
div = page.query_selector("div")
|
647
647
|
# waiting for the "span" selector relative to the div.
|
648
|
-
span = div.wait_for_selector("span", state
|
649
|
-
|
648
|
+
span = div.wait_for_selector("span", state: "attached")
|
650
649
|
```
|
651
650
|
|
652
651
|
> NOTE: This method does not work across navigations, use [Page#wait_for_selector](./page#wait_for_selector) instead.
|
@@ -7,10 +7,9 @@ sidebar_position: 10
|
|
7
7
|
Locator represents a view to the element(s) on the page. It captures the logic sufficient to retrieve the element at any
|
8
8
|
given moment. Locator can be created with the [Page#locator](./page#locator) method.
|
9
9
|
|
10
|
-
```
|
10
|
+
```ruby
|
11
11
|
locator = page.locator("text=Submit")
|
12
|
-
locator.click
|
13
|
-
|
12
|
+
locator.click
|
14
13
|
```
|
15
14
|
|
16
15
|
The difference between the Locator and [ElementHandle](./element_handle) is that the latter points to a particular element, while Locator
|
@@ -72,10 +71,12 @@ Elements from child frames return the bounding box relative to the main frame, u
|
|
72
71
|
Assuming the page is static, it is safe to use bounding box coordinates to perform input. For example, the following
|
73
72
|
snippet should click the center of the element.
|
74
73
|
|
75
|
-
```
|
76
|
-
box = element.bounding_box
|
77
|
-
page.mouse.click(
|
78
|
-
|
74
|
+
```ruby
|
75
|
+
box = element.bounding_box
|
76
|
+
page.mouse.click(
|
77
|
+
box["x"] + box["width"] / 2,
|
78
|
+
box["y"] + box["height"] / 2,
|
79
|
+
)
|
79
80
|
```
|
80
81
|
|
81
82
|
|
@@ -177,9 +178,8 @@ The snippet below dispatches the `click` event on the element. Regardless of the
|
|
177
178
|
`click` is dispatched. This is equivalent to calling
|
178
179
|
[element.click()](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/click).
|
179
180
|
|
180
|
-
```
|
181
|
+
```ruby
|
181
182
|
element.dispatch_event("click")
|
182
|
-
|
183
183
|
```
|
184
184
|
|
185
185
|
Under the hood, it creates an instance of an event based on the given `type`, initializes it with `eventInit` properties
|
@@ -196,11 +196,10 @@ Since `eventInit` is event-specific, please refer to the events documentation fo
|
|
196
196
|
|
197
197
|
You can also specify [JSHandle](./js_handle) as the property value if you want live objects to be passed into the event:
|
198
198
|
|
199
|
-
```
|
199
|
+
```ruby
|
200
200
|
# note you can only create data_transfer in chromium and firefox
|
201
201
|
data_transfer = page.evaluate_handle("new DataTransfer()")
|
202
|
-
element.dispatch_event("
|
203
|
-
|
202
|
+
element.dispatch_event("dragstart", eventInit: { dataTransfer: data_transfer })
|
204
203
|
```
|
205
204
|
|
206
205
|
|
@@ -236,10 +235,9 @@ If `expression` returns a [Promise](https://developer.mozilla.org/en-US/docs/Web
|
|
236
235
|
|
237
236
|
Examples:
|
238
237
|
|
239
|
-
```
|
240
|
-
|
241
|
-
|
242
|
-
|
238
|
+
```ruby
|
239
|
+
tweet = page.query_selector(".tweet .retweets")
|
240
|
+
tweet.evaluate("node => node.innerText") # => "10 retweets"
|
243
241
|
```
|
244
242
|
|
245
243
|
|
@@ -258,10 +256,9 @@ return its value.
|
|
258
256
|
|
259
257
|
Examples:
|
260
258
|
|
261
|
-
```
|
259
|
+
```ruby
|
262
260
|
elements = page.locator("div")
|
263
|
-
|
264
|
-
|
261
|
+
elements.evaluate_all("(divs, min) => divs.length >= min", arg: 10)
|
265
262
|
```
|
266
263
|
|
267
264
|
|
@@ -518,26 +515,18 @@ Returns the array of option values that have been successfully selected.
|
|
518
515
|
|
519
516
|
Triggers a `change` and `input` event once all the provided options have been selected.
|
520
517
|
|
521
|
-
```
|
518
|
+
```ruby
|
522
519
|
# single selection matching the value
|
523
|
-
element.select_option("blue")
|
520
|
+
element.select_option(value: "blue")
|
524
521
|
# single selection matching both the label
|
525
|
-
element.select_option(label
|
522
|
+
element.select_option(label: "blue")
|
526
523
|
# multiple selection
|
527
|
-
element.select_option(value
|
528
|
-
|
524
|
+
element.select_option(value: ["red", "green", "blue"])
|
529
525
|
```
|
530
526
|
|
531
|
-
```
|
532
|
-
# single selection matching the value
|
533
|
-
element.select_option("blue")
|
534
|
-
# single selection matching both the value and the label
|
535
|
-
element.select_option(label="blue")
|
536
|
-
# multiple selection
|
537
|
-
element.select_option("red", "green", "blue")
|
527
|
+
```ruby
|
538
528
|
# multiple selection for blue, red and second option
|
539
|
-
element.select_option(value
|
540
|
-
|
529
|
+
element.select_option(value: "blue", index: 2, label: "red")
|
541
530
|
```
|
542
531
|
|
543
532
|
|
@@ -607,19 +596,17 @@ Focuses the element, and then sends a `keydown`, `keypress`/`input`, and `keyup`
|
|
607
596
|
|
608
597
|
To press a special key, like `Control` or `ArrowDown`, use [Locator#press](./locator#press).
|
609
598
|
|
610
|
-
```
|
599
|
+
```ruby
|
611
600
|
element.type("hello") # types instantly
|
612
|
-
element.type("world", delay
|
613
|
-
|
601
|
+
element.type("world", delay: 100) # types slower, like a user
|
614
602
|
```
|
615
603
|
|
616
604
|
An example of typing into a text field and then submitting the form:
|
617
605
|
|
618
|
-
```
|
606
|
+
```ruby
|
619
607
|
element = page.locator("input")
|
620
608
|
element.type("some text")
|
621
609
|
element.press("Enter")
|
622
|
-
|
623
610
|
```
|
624
611
|
|
625
612
|
|
@@ -8,17 +8,18 @@ The Worker class represents a [WebWorker](https://developer.mozilla.org/en-US/do
|
|
8
8
|
event is emitted on the page object to signal a worker creation. `close` event is emitted on the worker object when the
|
9
9
|
worker is gone.
|
10
10
|
|
11
|
-
```
|
12
|
-
def handle_worker(worker)
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
11
|
+
```ruby
|
12
|
+
def handle_worker(worker)
|
13
|
+
puts "worker created: #{worker.url}"
|
14
|
+
worker.once("close", -> (w) { puts "worker destroyed: #{w.url}" })
|
15
|
+
end
|
16
|
+
|
17
|
+
page.on('worker', method(:handle_worker))
|
18
|
+
|
19
|
+
puts "current workers:"
|
20
|
+
page.workers.each do |worker|
|
21
|
+
puts " #{worker.url}"
|
22
|
+
end
|
22
23
|
```
|
23
24
|
|
24
25
|
|
@@ -10,7 +10,7 @@ This allow us to intermediate into automation, for example
|
|
10
10
|
* Authenticate with OAuth2 manually before automation
|
11
11
|
* Testing a page after some chrome extensions are installed manually
|
12
12
|
|
13
|
-
Keep in mind repeatedly that persistent browser context is NOT RECOMMENDED for most cases because it would bring many side effects.
|
13
|
+
Keep in mind repeatedly that persistent browser context is NOT RECOMMENDED for most cases because it would bring many side effects. Consider [reusing cookie and local storage](./use_storage_state) when you just want to keep authenticated across browser contexts.
|
14
14
|
|
15
15
|
## Pause automation for manual operation
|
16
16
|
|
@@ -0,0 +1,78 @@
|
|
1
|
+
---
|
2
|
+
sidebar_position: 6
|
3
|
+
---
|
4
|
+
|
5
|
+
# Reuse Cookie and LocalStorage
|
6
|
+
|
7
|
+
In most cases, authentication state is stored in cookie or local storage. When we just want to keep authenticated, it is a good solution to dump/load 'storage state' (= Cookie + LocalStorage).
|
8
|
+
https://playwright.dev/docs/next/auth#reuse-authentication-state
|
9
|
+
|
10
|
+
* Dump storage state using [BrowserContext#storage_state](/docs/api/browser_context#storage_state) with `path: /path/to/state.json`
|
11
|
+
* Load storage state by specifying the parameter `storageState: /path/to/state.json` into [Browser#new_context](/docs/api/browser#new_context) or [Browser#new_page](/docs/api/browser#new_page)
|
12
|
+
|
13
|
+
## Example
|
14
|
+
|
15
|
+
Generally in browser automation, it is very difficult to bypass 2FA or reCAPTCHA in login screen. In such cases, we would consider
|
16
|
+
|
17
|
+
* Authenticate manually by hand
|
18
|
+
* Resume automation with the authentication result
|
19
|
+
|
20
|
+
|
21
|
+
```ruby {16,21}
|
22
|
+
require 'playwright'
|
23
|
+
require 'pry'
|
24
|
+
|
25
|
+
force_login = !File.exist?('github_state.json')
|
26
|
+
|
27
|
+
Playwright.create(playwright_cli_executable_path: 'npx playwright') do |playwright|
|
28
|
+
if force_login
|
29
|
+
# Use headful mode for manual operation.
|
30
|
+
playwright.chromium.launch(headless: false, channel: 'chrome') do |browser|
|
31
|
+
page = browser.new_page
|
32
|
+
page.goto('https://github.com/login')
|
33
|
+
|
34
|
+
# Login manually.
|
35
|
+
binding.pry
|
36
|
+
|
37
|
+
page.context.storage_state(path: 'github_state.json')
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
playwright.chromium.launch do |browser|
|
42
|
+
page = browser.new_page(storageState: 'github_state.json')
|
43
|
+
page.goto('https://github.com/notifications')
|
44
|
+
page.screenshot(path: 'github_notification.png')
|
45
|
+
end
|
46
|
+
end
|
47
|
+
```
|
48
|
+
|
49
|
+
When we execute this script at the first time (without github_state.json), login screen is shown:
|
50
|
+
|
51
|
+
![login screen is shown](https://user-images.githubusercontent.com/11763113/129394130-7a248f6a-56f0-40b0-a4dd-f0f65d71b3a9.png)
|
52
|
+
|
53
|
+
and input credentials manually:
|
54
|
+
|
55
|
+
![input credentials manually](https://user-images.githubusercontent.com/11763113/129394155-fccc280e-5e6b-46c7-8a4d-a99d7db02c7f.png)
|
56
|
+
|
57
|
+
and hit `exit` in Pry console.
|
58
|
+
|
59
|
+
```
|
60
|
+
|
61
|
+
9:
|
62
|
+
10: # Login manually. Hit `exit` in Pry console after authenticated.
|
63
|
+
11: require 'pry'
|
64
|
+
12: binding.pry
|
65
|
+
13:
|
66
|
+
=> 14: page.context.storage_state(path: 'github_state.json')
|
67
|
+
15: end if force_login
|
68
|
+
16:
|
69
|
+
17: playwright.chromium.launch do |browser|
|
70
|
+
18: page = browser.new_page(storageState: 'github_state.json')
|
71
|
+
19: page.goto('https://github.com/notifications')
|
72
|
+
|
73
|
+
[1] pry(main)> exit
|
74
|
+
```
|
75
|
+
|
76
|
+
then we can enjoy automation with keeping authenticated. Login screen is never shown until github_state.json is deleted :)
|
77
|
+
|
78
|
+
![github_notification.png](https://user-images.githubusercontent.com/11763113/129394879-838797eb-135f-41ab-b965-8d6fabde6109.png)
|
data/lib/playwright/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: playwright-ruby-client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.14.
|
4
|
+
version: 1.14.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- YusukeIwaki
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-08-
|
11
|
+
date: 2021-08-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: concurrent-ruby
|
@@ -250,6 +250,7 @@ files:
|
|
250
250
|
- documentation/docs/article/guides/rails_integration.md
|
251
251
|
- documentation/docs/article/guides/recording_video.md
|
252
252
|
- documentation/docs/article/guides/semi_automation.md
|
253
|
+
- documentation/docs/article/guides/use_storage_state.md
|
253
254
|
- documentation/docs/include/api_coverage.md
|
254
255
|
- documentation/docusaurus.config.js
|
255
256
|
- documentation/package.json
|
@@ -371,9 +372,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
371
372
|
version: '2.4'
|
372
373
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
373
374
|
requirements:
|
374
|
-
- - "
|
375
|
+
- - ">="
|
375
376
|
- !ruby/object:Gem::Version
|
376
|
-
version:
|
377
|
+
version: '0'
|
377
378
|
requirements: []
|
378
379
|
rubygems_version: 3.2.22
|
379
380
|
signing_key:
|