async-webdriver 0.1.2 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/lib/async/webdriver/bridge/chrome.rb +81 -0
- data/lib/async/webdriver/bridge/firefox.rb +80 -0
- data/lib/async/webdriver/bridge/generic.rb +91 -0
- data/lib/async/webdriver/bridge/pool.rb +99 -0
- data/lib/async/webdriver/bridge/process_group.rb +77 -0
- data/lib/async/webdriver/bridge.rb +30 -0
- data/lib/async/webdriver/client.rb +71 -26
- data/lib/async/webdriver/element.rb +270 -17
- data/lib/async/webdriver/error.rb +214 -0
- data/lib/async/webdriver/locator.rb +127 -0
- data/lib/async/webdriver/request_helper.rb +120 -0
- data/lib/async/webdriver/scope/alerts.rb +40 -0
- data/lib/async/webdriver/scope/cookies.rb +43 -0
- data/lib/async/webdriver/scope/document.rb +41 -0
- data/lib/async/webdriver/scope/elements.rb +111 -0
- data/lib/async/webdriver/scope/fields.rb +66 -0
- data/lib/async/webdriver/scope/frames.rb +33 -0
- data/lib/async/webdriver/scope/navigation.rb +50 -0
- data/lib/async/webdriver/scope/printing.rb +22 -0
- data/lib/async/webdriver/scope/screen_capture.rb +23 -0
- data/lib/async/webdriver/scope/timeouts.rb +63 -0
- data/lib/async/webdriver/scope.rb +15 -0
- data/lib/async/webdriver/session.rb +107 -65
- data/lib/async/webdriver/version.rb +8 -3
- data/lib/async/webdriver/xpath.rb +29 -0
- data/lib/async/webdriver.rb +7 -12
- data/{LICENSE.txt → license.md} +6 -6
- data/readme.md +37 -0
- data.tar.gz.sig +0 -0
- metadata +71 -149
- metadata.gz.sig +0 -0
- data/.gitignore +0 -11
- data/.rspec +0 -3
- data/.ruby-gemset +0 -1
- data/.ruby-version +0 -1
- data/.travis.yml +0 -7
- data/Gemfile +0 -6
- data/Gemfile.lock +0 -103
- data/Guardfile +0 -45
- data/README.md +0 -3
- data/Rakefile +0 -6
- data/async-webdriver.gemspec +0 -37
- data/bin/console +0 -12
- data/bin/setup +0 -8
- data/examples/multiple_sessions.rb +0 -29
- data/lib/async/webdriver/connection.rb +0 -78
- data/lib/async/webdriver/connection_path.rb +0 -25
- data/lib/async/webdriver/execute.rb +0 -29
- data/lib/async/webdriver/session_creator.rb +0 -22
@@ -0,0 +1,120 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2023, by Samuel Williams.
|
5
|
+
|
6
|
+
require_relative 'version'
|
7
|
+
require_relative 'error'
|
8
|
+
|
9
|
+
module Async
|
10
|
+
module WebDriver
|
11
|
+
# Wraps the HTTP client to provide a consistent interface.
|
12
|
+
module RequestHelper
|
13
|
+
# The web element identifier is the string constant "element-6066-11e4-a52e-4f735466cecf".
|
14
|
+
ELEMENT_KEY = "element-6066-11e4-a52e-4f735466cecf"
|
15
|
+
|
16
|
+
# The content type for requests and responses.
|
17
|
+
CONTENT_TYPE = "application/json"
|
18
|
+
|
19
|
+
# Headers to send with GET requests.
|
20
|
+
GET_HEADERS = [
|
21
|
+
["user-agent", "Async::WebDriver/#{VERSION}"],
|
22
|
+
["accept", CONTENT_TYPE],
|
23
|
+
].freeze
|
24
|
+
|
25
|
+
# Headers to send with POST requests.
|
26
|
+
POST_HEADERS = GET_HEADERS + [
|
27
|
+
["content-type", "#{CONTENT_TYPE}; charset=UTF-8"],
|
28
|
+
].freeze
|
29
|
+
|
30
|
+
# The path used for making requests to the web driver bridge.
|
31
|
+
# @parameter path [String | Nil] The path to append to the request path.
|
32
|
+
# @returns [String] The path used for making requests to the web driver bridge.
|
33
|
+
def request_path(path = nil)
|
34
|
+
if path
|
35
|
+
"/#{path}"
|
36
|
+
else
|
37
|
+
"/"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# Unwrap JSON objects into their corresponding Ruby objects.
|
42
|
+
#
|
43
|
+
# If the value is a Hash and represents an element, then it will be unwrapped into an {ruby Element}.
|
44
|
+
#
|
45
|
+
# @parameter value [Hash | Array | Object] The value to unwrap.
|
46
|
+
# @returns [Object] The unwrapped value.
|
47
|
+
def unwrap_object(value)
|
48
|
+
if value.is_a?(Hash) and value.key?(ELEMENT_KEY)
|
49
|
+
Element.new(self.session, value[ELEMENT_KEY])
|
50
|
+
else
|
51
|
+
value
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# Used by `JSON.load` to unwrap objects.
|
56
|
+
def unwrap_objects(value)
|
57
|
+
case value
|
58
|
+
when Hash
|
59
|
+
value.transform_values!(&method(:unwrap_object))
|
60
|
+
when Array
|
61
|
+
value.map!(&method(:unwrap_object))
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# Extract the value from the reply.
|
66
|
+
#
|
67
|
+
# If the value is a Hash and represents an error, then it will be raised as an appropriate subclass of {ruby Error}.
|
68
|
+
#
|
69
|
+
# @parameter reply [Hash] The reply from the server.
|
70
|
+
# @returns [Object] The value of the reply.
|
71
|
+
def extract_value(reply)
|
72
|
+
value = reply["value"]
|
73
|
+
|
74
|
+
if value.is_a?(Hash) and error = value["error"]
|
75
|
+
raise ERROR_CODES.fetch(error, Error), value["message"]
|
76
|
+
end
|
77
|
+
|
78
|
+
if block_given?
|
79
|
+
return yield(reply)
|
80
|
+
else
|
81
|
+
return value
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# Make a GET request to the bridge and extract the value.
|
86
|
+
# @parameter path [String | Nil] The path to append to the request path.
|
87
|
+
# @returns [Object | Nil] The value of the reply.
|
88
|
+
def get(path)
|
89
|
+
Console.debug(self, "GET #{request_path(path)}")
|
90
|
+
response = @delegate.get(request_path(path), GET_HEADERS)
|
91
|
+
reply = JSON.load(response.read, self.method(:unwrap_objects))
|
92
|
+
|
93
|
+
return extract_value(reply)
|
94
|
+
end
|
95
|
+
|
96
|
+
# Make a POST request to the bridge and extract the value.
|
97
|
+
# @parameter path [String | Nil] The path to append to the request path.
|
98
|
+
# @parameter arguments [Hash | Nil] The arguments to send with the request.
|
99
|
+
# @returns [Object | Nil] The value of the reply.
|
100
|
+
def post(path, arguments = {}, &block)
|
101
|
+
Console.debug(self, "POST #{request_path(path)}", arguments: arguments)
|
102
|
+
response = @delegate.post(request_path(path), POST_HEADERS, arguments ? JSON.dump(arguments) : nil)
|
103
|
+
reply = JSON.load(response.read, self.method(:unwrap_objects))
|
104
|
+
|
105
|
+
return extract_value(reply, &block)
|
106
|
+
end
|
107
|
+
|
108
|
+
# Make a DELETE request to the bridge and extract the value.
|
109
|
+
# @parameter path [String | Nil] The path to append to the request path.
|
110
|
+
# @returns [Object | Nil] The value of the reply, if any.
|
111
|
+
def delete(path = nil)
|
112
|
+
Console.debug(self, "DELETE #{request_path(path)}")
|
113
|
+
response = @delegate.delete(request_path(path), POST_HEADERS)
|
114
|
+
reply = JSON.load(response.read, self.method(:unwrap_objects))
|
115
|
+
|
116
|
+
return extract_value(reply)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2023, by Samuel Williams.
|
5
|
+
|
6
|
+
module Async
|
7
|
+
module WebDriver
|
8
|
+
module Scope
|
9
|
+
# Helpers for working with alerts.
|
10
|
+
#
|
11
|
+
# ``` ruby
|
12
|
+
# session.dismiss_alert
|
13
|
+
# session.accept_alert
|
14
|
+
# session.alert_text
|
15
|
+
# session.set_alert_text("Hello, World!")
|
16
|
+
# ```
|
17
|
+
module Alerts
|
18
|
+
# Dismiss the current alert.
|
19
|
+
def dismiss_alert
|
20
|
+
session.post("alert/dismiss")
|
21
|
+
end
|
22
|
+
|
23
|
+
# Accept the current alert.
|
24
|
+
def accept_alert
|
25
|
+
session.post("alert/accept")
|
26
|
+
end
|
27
|
+
|
28
|
+
# Get the text of the current alert.
|
29
|
+
def alert_text
|
30
|
+
session.get("alert/text")
|
31
|
+
end
|
32
|
+
|
33
|
+
# Set the text input of the current alert.
|
34
|
+
def set_alert_text(text)
|
35
|
+
session.post("alert/text", {text: text})
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2023, by Samuel Williams.
|
5
|
+
|
6
|
+
module Async
|
7
|
+
module WebDriver
|
8
|
+
module Scope
|
9
|
+
# Helpers for working with cookies.
|
10
|
+
module Cookies
|
11
|
+
# Get all cookies.
|
12
|
+
def cookies
|
13
|
+
session.get("cookie")
|
14
|
+
end
|
15
|
+
|
16
|
+
# Get a cookie by name.
|
17
|
+
# @parameter name [String] The name of the cookie.
|
18
|
+
def cookie(name)
|
19
|
+
session.get("cookie/#{name}")
|
20
|
+
end
|
21
|
+
|
22
|
+
# Add a cookie.
|
23
|
+
# @parameter name [String] The name of the cookie.
|
24
|
+
# @parameter value [String] The value of the cookie.
|
25
|
+
# @parameter options [Hash] Additional options.
|
26
|
+
def add_cookie(name, value, **options)
|
27
|
+
session.post("cookie", {name: name, value: value}.merge(options))
|
28
|
+
end
|
29
|
+
|
30
|
+
# Delete a cookie by name.
|
31
|
+
# @parameter name [String] The name of the cookie.
|
32
|
+
def delete_cookie(name)
|
33
|
+
session.delete("cookie/#{name}")
|
34
|
+
end
|
35
|
+
|
36
|
+
# Delete all cookies.
|
37
|
+
def delete_all_cookies
|
38
|
+
session.delete("cookie")
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2023, by Samuel Williams.
|
5
|
+
|
6
|
+
module Async
|
7
|
+
module WebDriver
|
8
|
+
module Scope
|
9
|
+
# Helpers for working with the document.
|
10
|
+
module Document
|
11
|
+
# Get the current document title.
|
12
|
+
# @returns [String] The document title.
|
13
|
+
def title
|
14
|
+
get("title")
|
15
|
+
end
|
16
|
+
|
17
|
+
# Get the current document source.
|
18
|
+
# @returns [String] The document source.
|
19
|
+
def source
|
20
|
+
get("source")
|
21
|
+
end
|
22
|
+
|
23
|
+
# Execute a script in the current document.
|
24
|
+
# @parameter script [String] The script to execute.
|
25
|
+
# @parameter arguments [Array] The arguments to pass to the script.
|
26
|
+
# @returns [Object] The result of the script.
|
27
|
+
def execute(script, *arguments)
|
28
|
+
post("execute/sync", {script: script, args: arguments})
|
29
|
+
end
|
30
|
+
|
31
|
+
# Execute a script in the current document asynchronously.
|
32
|
+
# @parameter script [String] The script to execute.
|
33
|
+
# @parameter arguments [Array] The arguments to pass to the script.
|
34
|
+
# @returns [Object] The result of the script.
|
35
|
+
def execute_async(script, *arguments)
|
36
|
+
post("execute/async", {script: script, args: arguments})
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2023, by Samuel Williams.
|
5
|
+
|
6
|
+
require 'base64'
|
7
|
+
|
8
|
+
module Async
|
9
|
+
module WebDriver
|
10
|
+
module Scope
|
11
|
+
# Helpers for finding elements.
|
12
|
+
module Elements
|
13
|
+
# Find an element using the given locator. If no element is found, an exception is raised.
|
14
|
+
# @parameter locator [Locator] The locator to use.
|
15
|
+
# @returns [Element] The element.
|
16
|
+
# @raises [NoSuchElementError] If the element does not exist.
|
17
|
+
def find_element(locator)
|
18
|
+
current_scope.post("element", locator)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Find an element using the given CSS selector.
|
22
|
+
# @parameter css [String] The CSS selector to use.
|
23
|
+
# @returns [Element] The element.
|
24
|
+
# @raises [NoSuchElementError] If the element does not exist.
|
25
|
+
def find_element_by_css(css)
|
26
|
+
find_element({using: "css selector", value: css})
|
27
|
+
end
|
28
|
+
|
29
|
+
# Find an element using the given link text.
|
30
|
+
# @parameter text [String] The link text to use.
|
31
|
+
# @returns [Element] The element.
|
32
|
+
# @raises [NoSuchElementError] If the element does not exist.
|
33
|
+
def find_element_by_link_text(text)
|
34
|
+
find_element({using: "link text", value: text})
|
35
|
+
end
|
36
|
+
|
37
|
+
# Find an element using the given partial link text.
|
38
|
+
# @parameter text [String] The partial link text to use.
|
39
|
+
# @returns [Element] The element.
|
40
|
+
# @raises [NoSuchElementError] If the element does not exist.
|
41
|
+
def find_element_by_partial_link_text(text)
|
42
|
+
find_element({using: "partial link text", value: text})
|
43
|
+
end
|
44
|
+
|
45
|
+
# Find an element using the given tag name.
|
46
|
+
# @parameter name [String] The tag name to use.
|
47
|
+
# @returns [Element] The element.
|
48
|
+
# @raises [NoSuchElementError] If the element does not exist.
|
49
|
+
def find_element_by_tag_name(name)
|
50
|
+
find_element({using: "tag name", value: name})
|
51
|
+
end
|
52
|
+
|
53
|
+
# Find an element using the given XPath expression.
|
54
|
+
# @parameter xpath [String] The XPath expression to use.
|
55
|
+
# @returns [Element] The element.
|
56
|
+
# @raises [NoSuchElementError] If the element does not exist.
|
57
|
+
def find_element_by_xpath(xpath)
|
58
|
+
find_element({using: "xpath", value: xpath})
|
59
|
+
end
|
60
|
+
|
61
|
+
# Find all elements using the given locator. If no elements are found, an empty array is returned.
|
62
|
+
# @parameter locator [Locator] The locator to use.
|
63
|
+
# @returns [Array(Element)] The elements.
|
64
|
+
def find_elements(locator)
|
65
|
+
current_scope.post("elements", locator)
|
66
|
+
end
|
67
|
+
|
68
|
+
# Find all elements using the given CSS selector.
|
69
|
+
# @parameter css [String] The CSS selector to use.
|
70
|
+
# @returns [Array(Element)] The elements.
|
71
|
+
def find_elements_by_css(css)
|
72
|
+
find_elements({using: "css selector", value: css})
|
73
|
+
end
|
74
|
+
|
75
|
+
# Find all elements using the given link text.
|
76
|
+
# @parameter text [String] The link text to use.
|
77
|
+
# @returns [Array(Element)] The elements.
|
78
|
+
def find_elements_by_link_text(text)
|
79
|
+
find_elements({using: "link text", value: text})
|
80
|
+
end
|
81
|
+
|
82
|
+
# Find all elements using the given partial link text.
|
83
|
+
# @parameter text [String] The partial link text to use.
|
84
|
+
# @returns [Array(Element)] The elements.
|
85
|
+
def find_elements_by_partial_link_text(text)
|
86
|
+
find_elements({using: "partial link text", value: text})
|
87
|
+
end
|
88
|
+
|
89
|
+
# Find all elements using the given tag name.
|
90
|
+
# @parameter name [String] The tag name to use.
|
91
|
+
# @returns [Array(Element)] The elements.
|
92
|
+
def find_elements_by_tag_name(name)
|
93
|
+
find_elements({using: "tag name", value: name})
|
94
|
+
end
|
95
|
+
|
96
|
+
# Find all elements using the given XPath expression.
|
97
|
+
# @parameter xpath [String] The XPath expression to use.
|
98
|
+
# @returns [Array(Element)] The elements.
|
99
|
+
def find_elements_by_xpath(xpath)
|
100
|
+
find_elements({using: "xpath", value: xpath})
|
101
|
+
end
|
102
|
+
|
103
|
+
# Find all children of the current element.
|
104
|
+
# @returns [Array(Element)] The children of the current element.
|
105
|
+
def children
|
106
|
+
find_elements_by_xpath("./child::*")
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2023, by Samuel Williams.
|
5
|
+
|
6
|
+
require 'base64'
|
7
|
+
|
8
|
+
require_relative '../xpath'
|
9
|
+
|
10
|
+
module Async
|
11
|
+
module WebDriver
|
12
|
+
module Scope
|
13
|
+
# Helpers for working with forms and form fields.
|
14
|
+
module Fields
|
15
|
+
# Find a field with the given name.
|
16
|
+
# @parameter name [String] The name of the field.
|
17
|
+
# @returns [Element] The field.
|
18
|
+
# @raises [NoSuchElementError] If the field does not exist.
|
19
|
+
def find_field(name)
|
20
|
+
current_scope.find_element_by_xpath("//*[@name=#{XPath::escape(name)}]")
|
21
|
+
end
|
22
|
+
|
23
|
+
# Fill in a field with the given name.
|
24
|
+
#
|
25
|
+
# Clears the field before filling it in.
|
26
|
+
#
|
27
|
+
# @parameter name [String] The name of the field.
|
28
|
+
# @parameter value [String] The value to fill in.
|
29
|
+
# @raises [NoSuchElementError] If the field does not exist.
|
30
|
+
def fill_in(name, value)
|
31
|
+
element = find_field(name)
|
32
|
+
|
33
|
+
if element.tag_name == "input" || element.tag_name == "textarea"
|
34
|
+
element.clear
|
35
|
+
end
|
36
|
+
|
37
|
+
element.send_keys(value)
|
38
|
+
end
|
39
|
+
|
40
|
+
# Click a button with the given label.
|
41
|
+
# @parameter label [String] The label of the button.
|
42
|
+
# @raises [NoSuchElementError] If the button does not exist.
|
43
|
+
def click_button(label)
|
44
|
+
element = current_scope.find_element_by_xpath("//button[text()=#{XPath::escape(label)}] | //input[@type='submit' and @value=#{XPath::escape(label)}] | //input[@type='button' and @value=#{XPath::escape(label)}]")
|
45
|
+
|
46
|
+
element.click
|
47
|
+
end
|
48
|
+
|
49
|
+
# Check a checkbox with the given name.
|
50
|
+
#
|
51
|
+
# Does not modify the checkbox if it is already in the desired state.
|
52
|
+
#
|
53
|
+
# @parameter field_name [String] The name of the checkbox.
|
54
|
+
# @parameter value [Boolean] The value to set the checkbox to.
|
55
|
+
# @raises [NoSuchElementError] If the checkbox does not exist.
|
56
|
+
def check(field_name, value = true)
|
57
|
+
element = current_scope.find_element(xpath: "//input[@type='checkbox' and @name='#{field_name}']")
|
58
|
+
|
59
|
+
if element.checked? != value
|
60
|
+
element.click
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2023, by Samuel Williams.
|
5
|
+
|
6
|
+
module Async
|
7
|
+
module WebDriver
|
8
|
+
module Scope
|
9
|
+
# Helpers for working with frames.
|
10
|
+
#
|
11
|
+
# ``` ruby
|
12
|
+
# session.switch_to_frame(frame)
|
13
|
+
# session.switch_to_parent_frame
|
14
|
+
# ```
|
15
|
+
module Frames
|
16
|
+
# Switch to the given frame.
|
17
|
+
#
|
18
|
+
# @parameter frame [Element] The frame to switch to.
|
19
|
+
# @raises [NoSuchFrameError] If the frame does not exist.
|
20
|
+
def switch_to_frame(frame)
|
21
|
+
session.post("frame", {id: frame})
|
22
|
+
end
|
23
|
+
|
24
|
+
# Switch back to the parent frame.
|
25
|
+
#
|
26
|
+
# You should use this method to switch back to the parent frame after switching to a child frame.
|
27
|
+
def switch_to_parent_frame
|
28
|
+
session.post("frame/parent")
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2023, by Samuel Williams.
|
5
|
+
|
6
|
+
require 'uri'
|
7
|
+
|
8
|
+
module Async
|
9
|
+
module WebDriver
|
10
|
+
module Scope
|
11
|
+
# Helpers for navigating the browser.
|
12
|
+
module Navigation
|
13
|
+
# Navigate to the given URL.
|
14
|
+
# @parameter url [String] The URL to navigate to.
|
15
|
+
def navigate_to(url)
|
16
|
+
session.post("url", {url: url})
|
17
|
+
end
|
18
|
+
|
19
|
+
alias visit navigate_to
|
20
|
+
|
21
|
+
# Get the current URL.
|
22
|
+
# @returns [String] The current URL.
|
23
|
+
def current_url
|
24
|
+
session.get("url")
|
25
|
+
end
|
26
|
+
|
27
|
+
# Get the path component of the current URL.
|
28
|
+
# @returns [String] The current path.
|
29
|
+
def current_path
|
30
|
+
URI.parse(current_url).path
|
31
|
+
end
|
32
|
+
|
33
|
+
# Navigate back in the browser history.
|
34
|
+
def navigate_back
|
35
|
+
session.post("back")
|
36
|
+
end
|
37
|
+
|
38
|
+
# Navigate forward in the browser history.
|
39
|
+
def navigate_forward
|
40
|
+
session.post("forward")
|
41
|
+
end
|
42
|
+
|
43
|
+
# Refresh the current page.
|
44
|
+
def refresh
|
45
|
+
session.post("refresh")
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2023, by Samuel Williams.
|
5
|
+
|
6
|
+
require 'base64'
|
7
|
+
|
8
|
+
module Async
|
9
|
+
module WebDriver
|
10
|
+
module Scope
|
11
|
+
# Helpers for working with printing.
|
12
|
+
module Printing
|
13
|
+
# Print the current page and return the result as a Base64 encoded string containing a PDF representation of the paginated document.
|
14
|
+
def print(page_ranges: nil, total_pages: nil)
|
15
|
+
reply = session.post("print", {pageRanges: page_ranges, totalPages: total_pages}.compact)
|
16
|
+
|
17
|
+
return Base64.decode64(reply["value"])
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2023, by Samuel Williams.
|
5
|
+
|
6
|
+
require 'base64'
|
7
|
+
|
8
|
+
module Async
|
9
|
+
module WebDriver
|
10
|
+
module Scope
|
11
|
+
# Helpers for working with screen capture.
|
12
|
+
module ScreenCapture
|
13
|
+
# Take a screenshot of the current page or element.
|
14
|
+
# @returns [String] The screenshot as a Base64 encoded string.
|
15
|
+
def screenshot
|
16
|
+
reply = current_scope.post("screenshot")
|
17
|
+
|
18
|
+
return Base64.decode64(reply)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2023, by Samuel Williams.
|
5
|
+
|
6
|
+
module Async
|
7
|
+
module WebDriver
|
8
|
+
module Scope
|
9
|
+
# Helpers for working with timeouts.
|
10
|
+
#
|
11
|
+
# If your tests are failing because the page is not loading fast enough, you can increase the page load timeout:
|
12
|
+
#
|
13
|
+
# ``` ruby
|
14
|
+
# session.script_timeout = 1000 # 1 second
|
15
|
+
# session.implicit_wait_timeout = 10_000 # 10 seconds
|
16
|
+
# session.page_load_timeout = 60_000 # 60 seconds
|
17
|
+
# ```
|
18
|
+
module Timeouts
|
19
|
+
# Get the current timeouts.
|
20
|
+
# @returns [Hash] The timeouts.
|
21
|
+
def timeouts
|
22
|
+
session.get("timeouts")
|
23
|
+
end
|
24
|
+
|
25
|
+
# The script timeout is the amount of time the driver should wait when executing JavaScript asynchronously.
|
26
|
+
# @returns [Integer] The timeout in milliseconds.
|
27
|
+
def script_timeout
|
28
|
+
timeouts["script"]
|
29
|
+
end
|
30
|
+
|
31
|
+
# Set the script timeout.
|
32
|
+
# @parameter value [Integer] The timeout in milliseconds.
|
33
|
+
def script_timeout=(value)
|
34
|
+
session.post("timeouts", {script: value})
|
35
|
+
end
|
36
|
+
|
37
|
+
# The implicit wait timeout is the amount of time the driver should wait when searching for elements.
|
38
|
+
# @returns [Integer] The timeout in milliseconds.
|
39
|
+
def implicit_wait_timeout
|
40
|
+
timeouts["implicit"]
|
41
|
+
end
|
42
|
+
|
43
|
+
# Set the implicit wait timeout.
|
44
|
+
# @parameter value [Integer] The timeout in milliseconds.
|
45
|
+
def implicit_wait_timeout=(value)
|
46
|
+
session.post("timeouts", {implicit: value})
|
47
|
+
end
|
48
|
+
|
49
|
+
# The page load timeout is the amount of time the driver should wait when loading a page.
|
50
|
+
# @returns [Integer] The timeout in milliseconds.
|
51
|
+
def page_load_timeout
|
52
|
+
timeouts["pageLoad"]
|
53
|
+
end
|
54
|
+
|
55
|
+
# Set the page load timeout.
|
56
|
+
# @parameter value [Integer] The timeout in milliseconds.
|
57
|
+
def page_load_timeout=(value)
|
58
|
+
session.post("timeouts", {pageLoad: value})
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2023, by Samuel Williams.
|
5
|
+
|
6
|
+
require_relative 'scope/alerts'
|
7
|
+
require_relative 'scope/cookies'
|
8
|
+
require_relative 'scope/document'
|
9
|
+
require_relative 'scope/elements'
|
10
|
+
require_relative 'scope/fields'
|
11
|
+
require_relative 'scope/frames'
|
12
|
+
require_relative 'scope/navigation'
|
13
|
+
require_relative 'scope/printing'
|
14
|
+
require_relative 'scope/screen_capture'
|
15
|
+
require_relative 'scope/timeouts'
|