Skip to content
This repository was archived by the owner on Jun 23, 2020. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/.crystal
/.shards
/shard.lock
/lib
2 changes: 1 addition & 1 deletion shard.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ version: 1.0
shards:
minitest:
github: ysbaddaden/minitest.cr
version: 0.3.6
version: 0.4.0

21 changes: 10 additions & 11 deletions src/webdriver.cr
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ module Selenium
end

def get(path)
headers = HTTP::Headers{ "Accept" => "application/json" }
headers = HTTP::Headers{"Accept" => "application/json"}

{% if flag?(:DEBUG) %}
puts "REQUEST: GET #{path}"
Expand All @@ -27,13 +27,13 @@ module Selenium

{% if flag?(:DEBUG) %}
puts "RESPONSE: #{response.status_code}"
p JSON.parse(response.body).raw
p JSON.parse(response.body)
puts
{% end %}

case response.status_code
when 200
JSON.parse(response.body).raw.as(Hash)
JSON.parse(response.body)
else
failure(response)
end
Expand All @@ -46,21 +46,21 @@ module Selenium
{% end %}

if body
headers = HTTP::Headers{ "Content-Type" => "application/json; charset=UTF-8" }
headers = HTTP::Headers{"Content-Type" => "application/json; charset=UTF-8"}
response = @client.post("#{@path}#{path}", headers, body.to_json)
else
response = @client.post("#{@path}#{path}")
end

{% if flag?(:DEBUG) %}
puts "RESPONSE: #{response.status_code}"
p JSON.parse(response.body).raw
p JSON.parse(response.body)
puts
{% end %}

case response.status_code
when 200
JSON.parse(response.body).raw.as(Hash)
JSON.parse(response.body)
else
failure(response)
end
Expand All @@ -75,7 +75,7 @@ module Selenium

{% if flag?(:DEBUG) %}
puts "RESPONSE: #{response.status_code}"
p JSON.parse(response.body).raw
p JSON.parse(response.body)
{% end %}

raise Error.new(response.body) unless response.status_code == 200
Expand All @@ -84,10 +84,9 @@ module Selenium

private def failure(response)
if response.headers["Content-Type"].starts_with?("application/json")
body = JSON.parse(response.body).raw.as(Hash)
status = body["status"].as(Int)
value = body["value"].as(Hash)
raise Selenium.error_class(status).new(value["message"].as(String))
body = JSON.parse(response.body)
status = body["status"].as_i
raise Selenium.error_class(status).new(body["value"]["message"].as_s)
end
raise Error.new(response.body)
end
Expand Down
2 changes: 1 addition & 1 deletion src/webdriver/alert.cr
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ module Selenium
end

def send_keys(sequence : String)
session.post("/alert_text", { value: sequence })
session.post("/alert_text", {value: sequence})
end

def accept
Expand Down
32 changes: 28 additions & 4 deletions src/webdriver/errors.cr
Original file line number Diff line number Diff line change
@@ -1,37 +1,61 @@
module Selenium
class Error < Exception; end

class NoSuchDriver < Error; end

class NoSuchElement < Error; end

class NoSuchFrame < Error; end

class UnknownCommand < Error; end

class StaleElementReference < Error; end

class ElementNotVisible < Error; end

class InvalidElementState < Error; end

class UnknownError < Error; end

class ElementIsNotSelectable < Error; end

class JavaScriptError < Error; end

class XPathLookupError < Error; end

class Timeout < Error; end

class NoSuchWindow < Error; end

class InvalidCookieDomain < Error; end

class UnableToSetCookie < Error; end

class UnexpectedAlertOpen < Error; end

class NoAlertOpenError < Error; end

class ScriptTimeout < Error; end

class InvalidElementCoordinates < Error; end

class IMENotAvailable < Error; end

class IMEEngineActivationFailed < Error; end

class InvalidSelector < Error; end

class SessionNotCreatedException < Error; end

class MoveTargetOutOfBounds < Error; end

# :nodoc:
protected def self.error_class(status)
case status
when 6 then NoSuchDriver
when 7 then NoSuchElement
when 8 then NoSuchFrame
when 9 then UnknownCommand
when 6 then NoSuchDriver
when 7 then NoSuchElement
when 8 then NoSuchFrame
when 9 then UnknownCommand
when 10 then StaleElementReference
when 11 then ElementNotVisible
when 12 then InvalidElementState
Expand Down
52 changes: 26 additions & 26 deletions src/webdriver/session.cr
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,17 @@ module Selenium

getter driver : Webdriver
getter! id : String
getter! capabilities : Hash(String, JSON::Type)
getter! capabilities : Hash(String, JSON::Any)

def initialize(@driver, desired_capabilities = Webdriver::CAPABILITIES, required_capabilities = Webdriver::CAPABILITIES, url = "about:blank")
body = {
"desiredCapabilities" => desired_capabilities,
"desiredCapabilities" => desired_capabilities,
"requiredCapabilities" => required_capabilities,
}
response = driver.post("/session", body)

@id = response["sessionId"].as(String)
@capabilities = response["value"].as(Hash)
@id = response["sessionId"].as_s
@capabilities = response["value"].as_h

if url
self.url = url
Expand All @@ -54,11 +54,11 @@ module Selenium
end

def url
get("/url").as(String)
get("/url").as_s
end

def url=(url)
post("/url", { url: url })
post("/url", {url: url})
end

def forward
Expand All @@ -82,15 +82,15 @@ module Selenium
end

def execute(script, *args)
post("/execute", { script: script, args: args })
post("/execute", {script: script, args: args})
end

def execute_async(script, *args)
post("/execute", { script: script, args: args })
post("/execute", {script: script, args: args})
end

def frame(identifier)
post("/frame", { id: identifier })
post("/frame", {id: identifier})
end

def parent_frame
Expand All @@ -103,31 +103,31 @@ module Selenium
end

def save_screenshot(path)
data = get("/screenshot").as(String)
data = get("/screenshot").as_s
File.open(path, "w") { |file| Base64.decode(data, file) }
end

def find_element(by, selector, parent : WebElement? = nil)
url = parent ? "/element/#{ parent.id }/element" : "/element"
url = parent ? "/element/#{parent.id}/element" : "/element"
value = post(url, {
using: WebElement.locator_for(by),
value: selector
value: selector,
})
WebElement.new(self, value.as(Hash))
WebElement.new(self, value.as_h)
end

def find_elements(by, selector, parent : WebElement? = nil)
url = parent ? "/element/#{ parent.id }/elements" : "/elements"
url = parent ? "/element/#{parent.id}/elements" : "/elements"
value = post(url, {
using: WebElement.locator_for(by),
value: selector
}).as(Array)
value.map { |item| WebElement.new(self, item.as(Hash)) }
value: selector,
}).as_a
value.map { |item| WebElement.new(self, item.as_h) }
end

def active_element
value = post("/element/active")
WebElement.new(self, value.as(Hash))
WebElement.new(self, value.as_h)
end

def orientation
Expand All @@ -136,7 +136,7 @@ module Selenium

def orientation=(value)
raise ArgumentError.new unless %i(portrait landscape).includes?(value)
post("/orientation", { orientation: value.to_s.upcase })
post("/orientation", {orientation: value.to_s.upcase})
end

def alert
Expand All @@ -152,33 +152,33 @@ module Selenium
end

def click(button : MouseButton = MouseButton::LEFT)
post("/click", { button: button.value })
post("/click", {button: button.value})
end

def double_click(button : MouseButton = MouseButton::Left)
post("/doubleclick", { button: button.value })
post("/doubleclick", {button: button.value})
end

def button_down(button : MouseButton = MouseButton::Left)
post("/buttondown", { button: button.value })
post("/buttondown", {button: button.value})
end

def button_up(button : MouseButton = MouseButton::Left)
post("/buttonup", { button: button.value })
post("/buttonup", {button: button.value})
end

protected def get(path = "")
response = driver.get("/session/#{ id }#{ path }")
response = driver.get("/session/#{id}#{path}")
response["value"]
end

protected def post(path, body = nil)
response = driver.post("/session/#{ id }#{ path }", body)
response = driver.post("/session/#{id}#{path}", body)
response["value"]
end

protected def delete(path = "")
driver.delete("/session/#{ id }#{ path }")
driver.delete("/session/#{id}#{path}")
end
end
end
Loading