async-webdriver 0.8.0 → 0.9.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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/context/debugging.md +252 -0
- data/context/getting-started.md +90 -0
- data/context/github-actions-integration.md +68 -0
- data/context/index.yaml +24 -0
- data/context/sus-integration.md +51 -0
- data/lib/async/webdriver/error.rb +29 -29
- data/lib/async/webdriver/scope/screen_capture.rb +1 -1
- data/lib/async/webdriver/version.rb +1 -1
- data/readme.md +6 -0
- data/releases.md +4 -0
- data.tar.gz.sig +0 -0
- metadata +7 -2
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7d44f03f80dc5674a12fabaeb89138fb2edc8d4aa240644a554d12edd9b70686
|
4
|
+
data.tar.gz: '07129f8f6173caebca9e23629018ceec2299c5093e5eea9bec252ad4641f0b1f'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 729f7b01d41bae86173a3b0c26b7741ebae3ba3254da57c4d1583eb50c4564d1b1eace54bcf54b0f1c993f761e960d4ddaeda4389bb26dfe2255fcafb0885f9a
|
7
|
+
data.tar.gz: bb089d62cdf93ddf7db5799e1d64f7f97c7819b8272694d0c657bf1a3f990bd5f247677d38b631111df99576f290b14507de3f3cc9f4ce8150050b0be7357b3a
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
@@ -0,0 +1,252 @@
|
|
1
|
+
# Debugging
|
2
|
+
|
3
|
+
This guide explains how to debug WebDriver issues by capturing HTML source and screenshots when tests fail.
|
4
|
+
|
5
|
+
## Overview
|
6
|
+
|
7
|
+
When WebDriver tests fail, it's often helpful to capture the current state of the page to understand what went wrong. The most useful debugging artifacts are:
|
8
|
+
|
9
|
+
- **HTML Source**: Shows the current DOM structure, helpful for understanding why element selectors might be failing
|
10
|
+
- **Screenshots**: Provides a visual representation of what the browser is actually showing
|
11
|
+
|
12
|
+
## Core Concepts
|
13
|
+
|
14
|
+
`async-webdriver` provides built-in methods for capturing debugging information:
|
15
|
+
|
16
|
+
- {ruby Async::WebDriver::Session#document_source} returns the HTML source of the current page.
|
17
|
+
- {ruby Async::WebDriver::Session#screenshot} captures a screenshot of the entire page.
|
18
|
+
- {ruby Async::WebDriver::Element#screenshot} captures a screenshot of a specific element.
|
19
|
+
|
20
|
+
## Basic Debugging
|
21
|
+
|
22
|
+
### Capturing HTML Source
|
23
|
+
|
24
|
+
To save the current page HTML to a file:
|
25
|
+
|
26
|
+
```ruby
|
27
|
+
require "async/webdriver"
|
28
|
+
|
29
|
+
Async::WebDriver::Bridge::Pool.open do |pool|
|
30
|
+
pool.session do |session|
|
31
|
+
session.visit("https://example.com")
|
32
|
+
|
33
|
+
# Save HTML source for debugging
|
34
|
+
html = session.document_source
|
35
|
+
File.write("debug.html", html)
|
36
|
+
|
37
|
+
puts "HTML saved to debug.html"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
```
|
41
|
+
|
42
|
+
### Capturing Screenshots
|
43
|
+
|
44
|
+
To save a screenshot of the current page:
|
45
|
+
|
46
|
+
```ruby
|
47
|
+
require "async/webdriver"
|
48
|
+
|
49
|
+
Async::WebDriver::Bridge::Pool.open do |pool|
|
50
|
+
pool.session do |session|
|
51
|
+
session.visit("https://example.com")
|
52
|
+
|
53
|
+
# Take a screenshot (returns PNG binary data)
|
54
|
+
screenshot_data = session.screenshot
|
55
|
+
File.binwrite("debug.png", screenshot_data)
|
56
|
+
|
57
|
+
puts "Screenshot saved to debug.png"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
```
|
61
|
+
|
62
|
+
### Element Screenshots
|
63
|
+
|
64
|
+
To capture a screenshot of a specific element:
|
65
|
+
|
66
|
+
```ruby
|
67
|
+
require "async/webdriver"
|
68
|
+
|
69
|
+
Async::WebDriver::Bridge::Pool.open do |pool|
|
70
|
+
pool.session do |session|
|
71
|
+
session.visit("https://example.com")
|
72
|
+
|
73
|
+
# Find an element and screenshot it
|
74
|
+
element = session.find_element_by_tag_name("body")
|
75
|
+
element_screenshot = element.screenshot
|
76
|
+
File.binwrite("element-debug.png", element_screenshot)
|
77
|
+
|
78
|
+
puts "Element screenshot saved to element-debug.png"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
```
|
82
|
+
|
83
|
+
## Debugging Failed Element Searches
|
84
|
+
|
85
|
+
A common debugging scenario is when `find_element` fails. Here's how to capture debugging information:
|
86
|
+
|
87
|
+
```ruby
|
88
|
+
require "async/webdriver"
|
89
|
+
|
90
|
+
def debug_element_search(session, locator_type, locator_value)
|
91
|
+
begin
|
92
|
+
# Use the correct locator format for async-webdriver
|
93
|
+
locator = {using: locator_type, value: locator_value}
|
94
|
+
element = session.find_element(locator)
|
95
|
+
puts "✅ Element found: #{locator_type}=#{locator_value}"
|
96
|
+
return element
|
97
|
+
rescue Async::WebDriver::NoSuchElementError => e
|
98
|
+
puts "❌ Element not found: #{locator_type}=#{locator_value}"
|
99
|
+
|
100
|
+
# Capture debugging information
|
101
|
+
timestamp = Time.now.strftime("%Y%m%d-%H%M%S")
|
102
|
+
|
103
|
+
# Save HTML source
|
104
|
+
html = session.document_source
|
105
|
+
html_file = "debug-#{timestamp}.html"
|
106
|
+
File.write(html_file, html)
|
107
|
+
puts "📄 HTML saved to #{html_file}"
|
108
|
+
|
109
|
+
# Save screenshot
|
110
|
+
screenshot_data = session.screenshot
|
111
|
+
screenshot_file = "debug-#{timestamp}.png"
|
112
|
+
File.binwrite(screenshot_file, screenshot_data)
|
113
|
+
puts "📸 Screenshot saved to #{screenshot_file}"
|
114
|
+
|
115
|
+
# Re-raise the original error
|
116
|
+
raise e
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
# Usage example
|
121
|
+
Async::WebDriver::Bridge::Pool.open do |pool|
|
122
|
+
pool.session do |session|
|
123
|
+
session.visit("https://example.com")
|
124
|
+
|
125
|
+
# This will save debug files if the element isn't found
|
126
|
+
button = debug_element_search(session, "id", "submit-button")
|
127
|
+
end
|
128
|
+
end
|
129
|
+
```
|
130
|
+
|
131
|
+
## Advanced Debugging Techniques
|
132
|
+
|
133
|
+
### Configuring Timeouts for Debugging
|
134
|
+
|
135
|
+
WebDriver uses different timeout settings that affect how long operations wait:
|
136
|
+
|
137
|
+
```ruby
|
138
|
+
require "async/webdriver"
|
139
|
+
|
140
|
+
Async::WebDriver::Bridge::Pool.open do |pool|
|
141
|
+
pool.session do |session|
|
142
|
+
# Configure timeouts for debugging (values in milliseconds)
|
143
|
+
session.implicit_wait_timeout = 10_000 # 10 seconds for element finding
|
144
|
+
session.page_load_timeout = 30_000 # 30 seconds for page loads
|
145
|
+
session.script_timeout = 5_000 # 5 seconds for JavaScript execution
|
146
|
+
|
147
|
+
puts "Current timeouts: #{session.timeouts}"
|
148
|
+
|
149
|
+
# Now element finding will wait up to 10 seconds
|
150
|
+
session.visit("https://example.com")
|
151
|
+
element = session.find_element(:id, "dynamic-content") # Will wait up to 10s
|
152
|
+
end
|
153
|
+
end
|
154
|
+
```
|
155
|
+
|
156
|
+
### Wait and Debug Pattern
|
157
|
+
|
158
|
+
Sometimes elements appear after a delay. Here's how to debug timing issues:
|
159
|
+
|
160
|
+
```ruby
|
161
|
+
require "async/webdriver"
|
162
|
+
|
163
|
+
def wait_and_debug(session, locator_type, locator_value, timeout: 10000)
|
164
|
+
# Set implicit wait timeout (in milliseconds)
|
165
|
+
original_timeout = session.implicit_wait_timeout
|
166
|
+
session.implicit_wait_timeout = timeout
|
167
|
+
|
168
|
+
start_time = Time.now
|
169
|
+
|
170
|
+
begin
|
171
|
+
# Try to find the element (will use implicit wait timeout)
|
172
|
+
locator = {using: locator_type, value: locator_value}
|
173
|
+
session.find_element(locator)
|
174
|
+
rescue Async::WebDriver::NoSuchElementError => error
|
175
|
+
elapsed = Time.now - start_time
|
176
|
+
puts "⏰ Timeout after #{elapsed.round(2)}s waiting for #{locator_type}=#{locator_value}"
|
177
|
+
|
178
|
+
# Capture final state
|
179
|
+
timestamp = Time.now.strftime("%Y%m%d-%H%M%S")
|
180
|
+
|
181
|
+
html = session.document_source
|
182
|
+
File.write("timeout-debug-#{timestamp}.html", html)
|
183
|
+
|
184
|
+
screenshot_data = session.screenshot
|
185
|
+
File.binwrite("timeout-debug-#{timestamp}.png", screenshot_data)
|
186
|
+
|
187
|
+
puts "📄 Final HTML saved to timeout-debug-#{timestamp}.html"
|
188
|
+
puts "📸 Final screenshot saved to timeout-debug-#{timestamp}.png"
|
189
|
+
|
190
|
+
raise
|
191
|
+
ensure
|
192
|
+
# Restore original timeout
|
193
|
+
session.implicit_wait_timeout = original_timeout
|
194
|
+
end
|
195
|
+
end
|
196
|
+
```
|
197
|
+
|
198
|
+
### Multi-Step Debugging
|
199
|
+
|
200
|
+
For complex test scenarios, capture state at multiple points:
|
201
|
+
|
202
|
+
```ruby
|
203
|
+
require "async/webdriver"
|
204
|
+
|
205
|
+
class DebugHelper
|
206
|
+
def initialize(test_name)
|
207
|
+
@test_name = test_name
|
208
|
+
@step = 0
|
209
|
+
end
|
210
|
+
|
211
|
+
def capture_state(session, description)
|
212
|
+
@step += 1
|
213
|
+
timestamp = Time.now.strftime("%Y%m%d-%H%M%S")
|
214
|
+
prefix = "#{@test_name}-step#{@step}-#{timestamp}"
|
215
|
+
|
216
|
+
# Save HTML
|
217
|
+
html = session.document_source
|
218
|
+
html_file = "#{prefix}-#{description}.html"
|
219
|
+
File.write(html_file, html)
|
220
|
+
|
221
|
+
# Save screenshot
|
222
|
+
screenshot_data = session.screenshot
|
223
|
+
screenshot_file = "#{prefix}-#{description}.png"
|
224
|
+
File.binwrite(screenshot_file, screenshot_data)
|
225
|
+
|
226
|
+
puts "🔍 Step #{@step}: #{description}"
|
227
|
+
puts " 📄 #{html_file}"
|
228
|
+
puts " 📸 #{screenshot_file}"
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
# Usage example
|
233
|
+
debug = DebugHelper.new("login-test")
|
234
|
+
|
235
|
+
Async::WebDriver::Bridge::Pool.open do |pool|
|
236
|
+
pool.session do |session|
|
237
|
+
debug.capture_state(session, "initial-page")
|
238
|
+
|
239
|
+
session.visit("https://example.com/login")
|
240
|
+
debug.capture_state(session, "login-page-loaded")
|
241
|
+
|
242
|
+
session.find_element_by_id("username").send_keys("user@example.com")
|
243
|
+
debug.capture_state(session, "username-entered")
|
244
|
+
|
245
|
+
session.find_element_by_id("password").send_keys("password")
|
246
|
+
debug.capture_state(session, "password-entered")
|
247
|
+
|
248
|
+
session.find_element_by_id("submit").click
|
249
|
+
debug.capture_state(session, "form-submitted")
|
250
|
+
end
|
251
|
+
end
|
252
|
+
```
|
@@ -0,0 +1,90 @@
|
|
1
|
+
# Getting Started
|
2
|
+
|
3
|
+
This guide explains how to use `async-webdriver` for controlling a browser.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add the gem to your project:
|
8
|
+
|
9
|
+
~~~ bash
|
10
|
+
$ bundle add async-webdriver
|
11
|
+
~~~
|
12
|
+
|
13
|
+
## Core Concepts
|
14
|
+
|
15
|
+
`async-webdriver` is a Ruby implementation of the [WebDriver](https://www.w3.org/TR/webdriver/) protocol. It allows you to control a browser from Ruby code. It is built on top of [async](https://github.com/socketry/async) and [async-http](https://github.com/socketry/async-http). It has several core concepts:
|
16
|
+
|
17
|
+
- A {ruby Async::WebDriver::Bridge} can be used to start a web driver process, e.g. `chromedriver`, `geckodriver`, etc. It can be used in isolation, or not at all.
|
18
|
+
- A {ruby Async::WebDriver::Client} is used to connect to a running web driver and can be used to create new sessions.
|
19
|
+
- A {ruby Async::WebDriver::Session} represents a single browser session. It is used to control a browser window and navigate to different pages.
|
20
|
+
- A {ruby Async::WebDriver::Element} represents a single element on a page. It can be used to interact with the element, e.g. click, type, etc.
|
21
|
+
|
22
|
+
## Basic Usage
|
23
|
+
|
24
|
+
The following example shows how to use `async-webdriver` to open a browser, navigate to a page, and click a button:
|
25
|
+
|
26
|
+
~~~ ruby
|
27
|
+
require 'async/webdriver'
|
28
|
+
|
29
|
+
Async do
|
30
|
+
bridge = Async::WebDriver::Bridge::Chrome.new(headless: false)
|
31
|
+
|
32
|
+
driver = bridge.start
|
33
|
+
client = Async::WebDriver::Client.open(driver.endpoint)
|
34
|
+
|
35
|
+
session = client.session(bridge.default_capabilities)
|
36
|
+
# Set the implicit wait timeout to 10 seconds since we are dealing with the real internet (which can be slow):
|
37
|
+
session.implicit_wait_timeout = 10_000
|
38
|
+
|
39
|
+
session.visit('https://google.com')
|
40
|
+
|
41
|
+
session.fill_in('q', 'async-webdriver')
|
42
|
+
session.click_button("I'm Feeling Lucky")
|
43
|
+
|
44
|
+
puts session.document_title
|
45
|
+
ensure
|
46
|
+
session&.close
|
47
|
+
client&.close
|
48
|
+
driver&.close
|
49
|
+
end
|
50
|
+
~~~
|
51
|
+
|
52
|
+
### Using a Pool to Manage Sessions
|
53
|
+
|
54
|
+
If you are running multiple tests in parallel, you may want to use a session pool to manage the sessions. This can be done as follows:
|
55
|
+
|
56
|
+
~~~ ruby
|
57
|
+
require 'async/webdriver'
|
58
|
+
|
59
|
+
Async do
|
60
|
+
bridge = Async::WebDriver::Bridge::Pool.new(Async::WebDriver::Bridge::Chrome.new(headless: false))
|
61
|
+
|
62
|
+
session = bridge.session
|
63
|
+
# Set the implicit wait timeout to 10 seconds since we are dealing with the real internet (which can be slow):
|
64
|
+
session.implicit_wait_timeout = 10_000
|
65
|
+
|
66
|
+
session.visit('https://google.com')
|
67
|
+
|
68
|
+
session.fill_in('q', 'async-webdriver')
|
69
|
+
session.click_button("I'm Feeling Lucky")
|
70
|
+
|
71
|
+
puts session.document_title
|
72
|
+
ensure
|
73
|
+
session&.close
|
74
|
+
bridge&.close
|
75
|
+
end
|
76
|
+
~~~
|
77
|
+
|
78
|
+
The sessions will be cached and reused if possible.
|
79
|
+
|
80
|
+
## Integration vs Unit Testing
|
81
|
+
|
82
|
+
`async-webdriver` is designed for integration testing. It is not designed for unit testing (e.g. wrapping a tool like `rack-test` as `capybara` can do). It is designed for testing your application in a real browser and web server. It is designed for testing your application in the same way that a real user would use it. Unfortunately, this style of integration testing is significantly slower than unit testing, but it is also significantly more representative of how your application will behave in production. There are other tools, e.g. [rack-test](https://github.com/rack/rack-test) which provide significantly faster unit testing, but they do not test how your application will behave in an actual web browser. A comprehensive test suite should include both unit tests and integration tests.
|
83
|
+
|
84
|
+
### Headless Mode
|
85
|
+
|
86
|
+
During testing, often you will want to see the real browser window to determine if the test is working correctly. By default, for performance reasons, `async-webdriver` will run the browser in headless mode. This means that the browser will not be visible on the screen. If you want to see the browser window, you can disable headless mode by setting the `headless` option to `false`:
|
87
|
+
|
88
|
+
~~~ shell
|
89
|
+
$ ASYNC_WEBDRIVER_BRIDGE_HEADLESS=false ./webdriver-script.rb
|
90
|
+
~~~
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# GitHub Actions Integrations
|
2
|
+
|
3
|
+
This guide explains how to use `async-webdriver` with GitHub Actions.
|
4
|
+
|
5
|
+
We recommend using the [browser-actions](https://github.com/browser-actions) for setting up `chromedriver` and `geckodriver`. They are pre-configured to work with `async-webdriver` and are easy to use.
|
6
|
+
|
7
|
+
## Pipeline Configuration
|
8
|
+
|
9
|
+
The following example shows how to setup both `chromedriver` and `geckodriver` in a single pipeline:
|
10
|
+
|
11
|
+
~~~ yaml
|
12
|
+
name: Test
|
13
|
+
|
14
|
+
on: [push, pull_request]
|
15
|
+
|
16
|
+
permissions:
|
17
|
+
contents: read
|
18
|
+
|
19
|
+
env:
|
20
|
+
CONSOLE_OUTPUT: XTerm
|
21
|
+
|
22
|
+
jobs:
|
23
|
+
test:
|
24
|
+
name: ${{matrix.ruby}} on ${{matrix.os}}
|
25
|
+
runs-on: ${{matrix.os}}-latest
|
26
|
+
continue-on-error: ${{matrix.experimental}}
|
27
|
+
|
28
|
+
strategy:
|
29
|
+
matrix:
|
30
|
+
os:
|
31
|
+
- ubuntu
|
32
|
+
- macos
|
33
|
+
|
34
|
+
ruby:
|
35
|
+
- "3.0"
|
36
|
+
- "3.1"
|
37
|
+
- "3.2"
|
38
|
+
|
39
|
+
experimental: [false]
|
40
|
+
|
41
|
+
include:
|
42
|
+
- os: ubuntu
|
43
|
+
ruby: truffleruby
|
44
|
+
experimental: true
|
45
|
+
- os: ubuntu
|
46
|
+
ruby: jruby
|
47
|
+
experimental: true
|
48
|
+
- os: ubuntu
|
49
|
+
ruby: head
|
50
|
+
experimental: true
|
51
|
+
|
52
|
+
steps:
|
53
|
+
- uses: actions/checkout@v3
|
54
|
+
- uses: ruby/setup-ruby@v1
|
55
|
+
with:
|
56
|
+
ruby-version: ${{matrix.ruby}}
|
57
|
+
bundler-cache: true
|
58
|
+
|
59
|
+
- uses: browser-actions/setup-chrome@v1
|
60
|
+
- uses: browser-actions/setup-firefox@v1
|
61
|
+
- uses: browser-actions/setup-geckodriver@latest
|
62
|
+
with:
|
63
|
+
token: ${{secrets.GITHUB_TOKEN}}
|
64
|
+
|
65
|
+
- name: Run tests
|
66
|
+
timeout-minutes: 10
|
67
|
+
run: bundle exec bake test
|
68
|
+
~~~
|
data/context/index.yaml
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# Automatically generated context index for Utopia::Project guides.
|
2
|
+
# Do not edit then files in this directory directly, instead edit the guides and then run `bake utopia:project:agent:context:update`.
|
3
|
+
---
|
4
|
+
description: A native library implementing the W3C WebDriver client specification.
|
5
|
+
metadata:
|
6
|
+
documentation_uri: https://socketry.github.io/async-webdriver/
|
7
|
+
funding_uri: https://github.com/sponsors/ioquatix
|
8
|
+
source_code_uri: https://github.com/socketry/async-webdriver.git
|
9
|
+
files:
|
10
|
+
- path: getting-started.md
|
11
|
+
title: Getting Started
|
12
|
+
description: This guide explains how to use `async-webdriver` for controlling a
|
13
|
+
browser.
|
14
|
+
- path: debugging.md
|
15
|
+
title: Debugging
|
16
|
+
description: This guide explains how to debug WebDriver issues by capturing HTML
|
17
|
+
source and screenshots when tests fail.
|
18
|
+
- path: github-actions-integration.md
|
19
|
+
title: GitHub Actions Integrations
|
20
|
+
description: This guide explains how to use `async-webdriver` with GitHub Actions.
|
21
|
+
- path: sus-integration.md
|
22
|
+
title: Sus Integration
|
23
|
+
description: This guide will show you how to integrate `async-webdriver` with the
|
24
|
+
sus test framework.
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# Sus Integration
|
2
|
+
|
3
|
+
This guide will show you how to integrate `async-webdriver` with the sus test framework.
|
4
|
+
|
5
|
+
## Usage
|
6
|
+
|
7
|
+
Sus has out of the box support for `async-webdriver`. You can use it like this:
|
8
|
+
|
9
|
+
```shell
|
10
|
+
$ bundle add sus-fixtures-async-http sus-fixtures-async-webdriver protocol-rack
|
11
|
+
$ bundle update
|
12
|
+
```
|
13
|
+
|
14
|
+
Then write your integration test:
|
15
|
+
|
16
|
+
```ruby
|
17
|
+
# test/my_integration_test.rb
|
18
|
+
|
19
|
+
require "sus/fixtures/async/http/server_context"
|
20
|
+
require "sus/fixtures/async/webdriver/session_context"
|
21
|
+
|
22
|
+
require "protocol/rack/adapter"
|
23
|
+
require "rack/builder"
|
24
|
+
|
25
|
+
describe "my website" do
|
26
|
+
include Sus::Fixtures::Async::HTTP::ServerContext
|
27
|
+
include Sus::Fixtures::Async::WebDriver::SessionContext
|
28
|
+
|
29
|
+
def middleware
|
30
|
+
Protocol::Rack::Adapter.new(app)
|
31
|
+
end
|
32
|
+
|
33
|
+
def app
|
34
|
+
Rack::Builder.load_file(File.expand_path("../config.ru", __dir__))
|
35
|
+
end
|
36
|
+
|
37
|
+
it "has a title" do
|
38
|
+
navigate_to("/")
|
39
|
+
|
40
|
+
expect(session.document_title).to be == "Example"
|
41
|
+
end
|
42
|
+
|
43
|
+
it "has a paragraph" do
|
44
|
+
navigate_to("/")
|
45
|
+
|
46
|
+
expect(session).to have_element(tag_name: "p")
|
47
|
+
end
|
48
|
+
end
|
49
|
+
```
|
50
|
+
|
51
|
+
For more information, refer to the [sus-fixtures-async-webdriver](https://github.com/socketry/sus-fixtures-async-webdriver) documentation.
|
@@ -9,147 +9,147 @@ module Async
|
|
9
9
|
module WebDriver
|
10
10
|
class Error < StandardError
|
11
11
|
end
|
12
|
-
|
12
|
+
|
13
13
|
# The Element Click command could not be completed because the element receiving the events is obscuring the element that was requested clicked.
|
14
14
|
class ElementClickInterceptedError < Error
|
15
15
|
CODE = "element click intercepted"
|
16
16
|
end
|
17
|
-
|
17
|
+
|
18
18
|
# A command could not be completed because the element is not pointer- or keyboard interactable.
|
19
19
|
class ElementNotInteractableError < Error
|
20
20
|
CODE = "element not interactable"
|
21
21
|
end
|
22
|
-
|
22
|
+
|
23
23
|
# Navigation caused the user agent to hit a certificate warning, which is usually the result of an expired or invalid TLS certificate.
|
24
24
|
class InsecureCertificateError < Error
|
25
25
|
CODE = "insecure certificate"
|
26
26
|
end
|
27
|
-
|
27
|
+
|
28
28
|
# The arguments passed to a command are either invalid or malformed.
|
29
29
|
class InvalidArgumentError < Error
|
30
30
|
CODE = "invalid argument"
|
31
31
|
end
|
32
|
-
|
32
|
+
|
33
33
|
# An illegal attempt was made to set a cookie under a different domain than the current page.
|
34
34
|
class InvalidCookieDomainError < Error
|
35
35
|
CODE = "invalid cookie domain"
|
36
36
|
end
|
37
|
-
|
37
|
+
|
38
38
|
# A command could not be completed because the element is in an invalid state, e.g. attempting to clear an element that isn’t both editable and resettable.
|
39
39
|
class InvalidElementStateError < Error
|
40
40
|
CODE = "invalid element state"
|
41
41
|
end
|
42
|
-
|
42
|
+
|
43
43
|
# Argument was an invalid selector.
|
44
44
|
class InvalidSelectorError < Error
|
45
45
|
CODE = "invalid selector"
|
46
46
|
end
|
47
|
-
|
47
|
+
|
48
48
|
# Occurs if the given session id is not in the list of active sessions, meaning the session either does not exist or that it’s not active.
|
49
49
|
class InvalidSessionIdError < Error
|
50
50
|
CODE = "invalid session id"
|
51
51
|
end
|
52
|
-
|
52
|
+
|
53
53
|
# An error occurred while executing JavaScript supplied by the user.
|
54
54
|
class JavaScriptError < Error
|
55
55
|
CODE = "javascript error"
|
56
56
|
end
|
57
|
-
|
57
|
+
|
58
58
|
# The target for mouse interaction is not in the browser’s viewport and cannot be brought into that viewport.
|
59
59
|
class MoveTargetOutOfBoundsError < Error
|
60
60
|
CODE = "move target out of bounds"
|
61
61
|
end
|
62
|
-
|
62
|
+
|
63
63
|
# An attempt was made to operate on a modal dialog when one was not open.
|
64
64
|
class NoSuchAlertError < Error
|
65
65
|
CODE = "no such alert"
|
66
66
|
end
|
67
|
-
|
67
|
+
|
68
68
|
# No cookie matching the given path name was found amongst the associated cookies of the current browsing context’s active document.
|
69
69
|
class NoSuchCookieError < Error
|
70
70
|
CODE = "no such cookie"
|
71
71
|
end
|
72
|
-
|
72
|
+
|
73
73
|
# An element could not be located on the page using the given search parameters.
|
74
74
|
class NoSuchElementError < Error
|
75
75
|
CODE = "no such element"
|
76
76
|
end
|
77
|
-
|
77
|
+
|
78
78
|
# A command to switch to a frame could not be satisfied because the frame could not be found.
|
79
79
|
class NoSuchFrameError < Error
|
80
80
|
CODE = "no such frame"
|
81
81
|
end
|
82
|
-
|
82
|
+
|
83
83
|
# A command to switch to a window could not be satisfied because the window could not be found.
|
84
84
|
class NoSuchWindowError < Error
|
85
85
|
CODE = "no such window"
|
86
86
|
end
|
87
|
-
|
87
|
+
|
88
88
|
# The element does not have a shadow root.
|
89
89
|
class NoSuchShadowRootError < Error
|
90
90
|
CODE = "no such shadow root"
|
91
91
|
end
|
92
|
-
|
92
|
+
|
93
93
|
# A script did not complete before its timeout expired.
|
94
94
|
class ScriptTimeoutError < Error
|
95
95
|
CODE = "script timeout error"
|
96
96
|
end
|
97
|
-
|
97
|
+
|
98
98
|
# A new session could not be created.
|
99
99
|
class SessionNotCreatedError < Error
|
100
100
|
CODE = "session not created"
|
101
101
|
end
|
102
|
-
|
102
|
+
|
103
103
|
# A command failed because the referenced element is no longer attached to the DOM.
|
104
104
|
class StaleElementReferenceError < Error
|
105
105
|
CODE = "stale element reference"
|
106
106
|
end
|
107
|
-
|
107
|
+
|
108
108
|
# A command failed because the referenced shadow root is no longer attached to the DOM.
|
109
109
|
class DetachedShadowRootError < Error
|
110
110
|
CODE = "detached shadow root"
|
111
111
|
end
|
112
|
-
|
112
|
+
|
113
113
|
# An operation did not complete before its timeout expired.
|
114
114
|
class TimeoutError < Error
|
115
115
|
CODE = "timeout"
|
116
116
|
end
|
117
|
-
|
117
|
+
|
118
118
|
# A command to set a cookie’s value could not be satisfied.
|
119
119
|
class UnableToSetCookieError < Error
|
120
120
|
CODE = "unable to set cookie"
|
121
121
|
end
|
122
|
-
|
122
|
+
|
123
123
|
# A screen capture was made impossible.
|
124
124
|
class UnableToCaptureScreenError < Error
|
125
125
|
CODE = "unable to capture screen"
|
126
126
|
end
|
127
|
-
|
127
|
+
|
128
128
|
# A modal dialog was open, blocking this operation.
|
129
129
|
class UnexpectedAlertOpenError < Error
|
130
130
|
CODE = "unexpected alert open"
|
131
131
|
end
|
132
|
-
|
132
|
+
|
133
133
|
# A command could not be executed because the remote end is not aware of it.
|
134
134
|
class UnknownCommandError < Error
|
135
135
|
CODE = "unknown command"
|
136
136
|
end
|
137
|
-
|
137
|
+
|
138
138
|
# An unknown error occurred in the remote end while processing the command.
|
139
139
|
class UnknownError < Error
|
140
140
|
CODE = "unknown error"
|
141
141
|
end
|
142
|
-
|
142
|
+
|
143
143
|
# The requested command matched a known URL but did not match any method for that URL.
|
144
144
|
class UnknownMethodError < Error
|
145
145
|
CODE = "unknown method"
|
146
146
|
end
|
147
|
-
|
147
|
+
|
148
148
|
# Indicates that a command that should have executed properly cannot be supported for some reason.
|
149
149
|
class UnsupportedOperationError < Error
|
150
150
|
CODE = "unsupported operation"
|
151
151
|
end
|
152
|
-
|
152
|
+
|
153
153
|
ERROR_CODES = {
|
154
154
|
ElementClickInterceptedError::CODE => ElementClickInterceptedError,
|
155
155
|
ElementNotInteractableError::CODE => ElementNotInteractableError,
|
@@ -13,7 +13,7 @@ module Async
|
|
13
13
|
# Take a screenshot of the current page or element.
|
14
14
|
# @returns [String] The screenshot as a Base64 encoded string.
|
15
15
|
def screenshot
|
16
|
-
reply = current_scope.
|
16
|
+
reply = current_scope.get("screenshot")
|
17
17
|
|
18
18
|
return Base64.decode64(reply)
|
19
19
|
end
|
data/readme.md
CHANGED
@@ -16,6 +16,8 @@ Please see the [project documentation](https://socketry.github.io/async-webdrive
|
|
16
16
|
|
17
17
|
- [Getting Started](https://socketry.github.io/async-webdriver/guides/getting-started/index) - This guide explains how to use `async-webdriver` for controlling a browser.
|
18
18
|
|
19
|
+
- [Debugging](https://socketry.github.io/async-webdriver/guides/debugging/index) - This guide explains how to debug WebDriver issues by capturing HTML source and screenshots when tests fail.
|
20
|
+
|
19
21
|
- [GitHub Actions Integrations](https://socketry.github.io/async-webdriver/guides/github-actions-integration/index) - This guide explains how to use `async-webdriver` with GitHub Actions.
|
20
22
|
|
21
23
|
- [Sus Integration](https://socketry.github.io/async-webdriver/guides/sus-integration/index) - This guide will show you how to integrate `async-webdriver` with the sus test framework.
|
@@ -24,6 +26,10 @@ Please see the [project documentation](https://socketry.github.io/async-webdrive
|
|
24
26
|
|
25
27
|
Please see the [project releases](https://socketry.github.io/async-webdriver/releases/index) for all releases.
|
26
28
|
|
29
|
+
### v0.9.0
|
30
|
+
|
31
|
+
- Fix `Scope#screenshot` to use the correct HTTP method (`GET` instead of `POST`).
|
32
|
+
|
27
33
|
### v0.8.0
|
28
34
|
|
29
35
|
- Fix `fill_in` `<select>` on Safari.
|
data/releases.md
CHANGED
data.tar.gz.sig
CHANGED
Binary file
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: async-webdriver
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.9.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Samuel Williams
|
@@ -112,6 +112,11 @@ executables: []
|
|
112
112
|
extensions: []
|
113
113
|
extra_rdoc_files: []
|
114
114
|
files:
|
115
|
+
- context/debugging.md
|
116
|
+
- context/getting-started.md
|
117
|
+
- context/github-actions-integration.md
|
118
|
+
- context/index.yaml
|
119
|
+
- context/sus-integration.md
|
115
120
|
- lib/async/webdriver.rb
|
116
121
|
- lib/async/webdriver/bridge.rb
|
117
122
|
- lib/async/webdriver/bridge/chrome.rb
|
@@ -164,7 +169,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
164
169
|
- !ruby/object:Gem::Version
|
165
170
|
version: '0'
|
166
171
|
requirements: []
|
167
|
-
rubygems_version: 3.6.
|
172
|
+
rubygems_version: 3.6.9
|
168
173
|
specification_version: 4
|
169
174
|
summary: A native library implementing the W3C WebDriver client specification.
|
170
175
|
test_files: []
|
metadata.gz.sig
CHANGED
Binary file
|