Compare commits
No commits in common. "master" and "v0.1.0" have entirely different histories.
3 changed files with 11 additions and 106 deletions
|
|
@ -1,7 +0,0 @@
|
||||||
# webdriver
|
|
||||||
|
|
||||||
A simple implementation of the pretty recent [W3C WebDriver spec](https://www.w3.org/TR/webdriver/).
|
|
||||||
Currently Firefox is just about the only browser that supports it.
|
|
||||||
|
|
||||||
I have coded this library during a livestream, do check that out to see how the library is used:
|
|
||||||
https://www.youtube.com/watch?v=583BwZ7uSro&index=1&list=PLm-fq5xBdPkrMuVkPWuho7XzszB6kJ2My
|
|
||||||
|
|
@ -1,6 +1,4 @@
|
||||||
# For reference, this is brilliant: https://github.com/jlipps/simple-wd-spec
|
import httpclient, uri, json, tables
|
||||||
|
|
||||||
import httpclient, uri, json, tables, options, strutils, unicode
|
|
||||||
|
|
||||||
type
|
type
|
||||||
WebDriver* = ref object
|
WebDriver* = ref object
|
||||||
|
|
@ -45,13 +43,12 @@ proc createSession*(self: WebDriver): Session =
|
||||||
# Check the readiness of the Web Driver.
|
# Check the readiness of the Web Driver.
|
||||||
let resp = self.client.getContent($(self.url / "status"))
|
let resp = self.client.getContent($(self.url / "status"))
|
||||||
let obj = parseJson(resp)
|
let obj = parseJson(resp)
|
||||||
let ready = obj{"value", "ready"}
|
|
||||||
|
|
||||||
if ready.isNil():
|
if obj{"value", "ready"}.isNil():
|
||||||
let msg = "Readiness message does not follow spec"
|
let msg = "Readiness message does not follow spec"
|
||||||
raise newException(ProtocolException, msg)
|
raise newException(ProtocolException, msg)
|
||||||
|
|
||||||
if not ready.getBool():
|
if not obj{"value", "ready"}.getBool():
|
||||||
raise newException(WebDriverException, "WebDriver is not ready")
|
raise newException(WebDriverException, "WebDriver is not ready")
|
||||||
|
|
||||||
# Create our session.
|
# Create our session.
|
||||||
|
|
@ -59,17 +56,10 @@ proc createSession*(self: WebDriver): Session =
|
||||||
let sessionResp = self.client.postContent($(self.url / "session"),
|
let sessionResp = self.client.postContent($(self.url / "session"),
|
||||||
$sessionReq)
|
$sessionReq)
|
||||||
let sessionObj = parseJson(sessionResp)
|
let sessionObj = parseJson(sessionResp)
|
||||||
let sessionId = sessionObj{"value", "sessionId"}
|
if sessionObj{"value", "sessionId"}.isNil():
|
||||||
if sessionId.isNil():
|
|
||||||
raise newException(ProtocolException, "No sessionId in response to request")
|
raise newException(ProtocolException, "No sessionId in response to request")
|
||||||
|
|
||||||
return Session(id: sessionId.getStr(), driver: self)
|
return Session(id: sessionObj["value"]["sessionId"].getStr(), driver: self)
|
||||||
|
|
||||||
proc close*(self: Session) =
|
|
||||||
let reqUrl = $(self.driver.url / "session" / self.id)
|
|
||||||
let resp = self.driver.client.request(reqUrl, HttpDelete)
|
|
||||||
|
|
||||||
let respObj = checkResponse(resp.body)
|
|
||||||
|
|
||||||
proc navigate*(self: Session, url: string) =
|
proc navigate*(self: Session, url: string) =
|
||||||
## Instructs the session to navigate to the specified URL.
|
## Instructs the session to navigate to the specified URL.
|
||||||
|
|
@ -91,20 +81,15 @@ proc getPageSource*(self: Session): string =
|
||||||
return respObj{"value"}.getStr()
|
return respObj{"value"}.getStr()
|
||||||
|
|
||||||
proc findElement*(self: Session, selector: string,
|
proc findElement*(self: Session, selector: string,
|
||||||
strategy = CssSelector): Option[Element] =
|
strategy = CssSelector): Element =
|
||||||
let reqUrl = $(self.driver.url / "session" / self.id / "element")
|
let reqUrl = $(self.driver.url / "session" / self.id / "element")
|
||||||
let reqObj = %*{"using": toKeyword(strategy), "value": selector}
|
let reqObj = %*{"using": toKeyword(strategy), "value": selector}
|
||||||
let resp = self.driver.client.post(reqUrl, $reqObj)
|
let resp = self.driver.client.postContent(reqUrl, $reqObj)
|
||||||
if resp.status == Http404:
|
|
||||||
return none(Element)
|
|
||||||
|
|
||||||
if resp.status != Http200:
|
let respObj = checkResponse(resp)
|
||||||
raise newException(WebDriverException, resp.status)
|
|
||||||
|
|
||||||
let respObj = checkResponse(resp.body)
|
|
||||||
|
|
||||||
for key, value in respObj["value"].getFields().pairs():
|
for key, value in respObj["value"].getFields().pairs():
|
||||||
return some(Element(id: value.getStr(), session: self))
|
return Element(id: value.getStr(), session: self)
|
||||||
|
|
||||||
proc getText*(self: Element): string =
|
proc getText*(self: Element): string =
|
||||||
let reqUrl = $(self.session.driver.url / "session" / self.session.id /
|
let reqUrl = $(self.session.driver.url / "session" / self.session.id /
|
||||||
|
|
@ -114,77 +99,6 @@ proc getText*(self: Element): string =
|
||||||
|
|
||||||
return respObj["value"].getStr()
|
return respObj["value"].getStr()
|
||||||
|
|
||||||
proc click*(self: Element) =
|
|
||||||
let reqUrl = $(self.session.driver.url / "session" / self.session.id /
|
|
||||||
"element" / self.id / "click")
|
|
||||||
let obj = %*{}
|
|
||||||
let resp = self.session.driver.client.post(reqUrl, $obj)
|
|
||||||
if resp.status != Http200:
|
|
||||||
raise newException(WebDriverException, resp.status)
|
|
||||||
|
|
||||||
discard checkResponse(resp.body)
|
|
||||||
|
|
||||||
# Note: There currently is an open bug in geckodriver that causes DOM events not to fire when sending keys.
|
|
||||||
# https://github.com/mozilla/geckodriver/issues/348
|
|
||||||
proc sendKeys*(self: Element, text: string) =
|
|
||||||
let reqUrl = $(self.session.driver.url / "session" / self.session.id /
|
|
||||||
"element" / self.id / "value")
|
|
||||||
let obj = %*{"text": text}
|
|
||||||
let resp = self.session.driver.client.post(reqUrl, $obj)
|
|
||||||
if resp.status != Http200:
|
|
||||||
raise newException(WebDriverException, resp.status)
|
|
||||||
|
|
||||||
discard checkResponse(resp.body)
|
|
||||||
|
|
||||||
type
|
|
||||||
# https://w3c.github.io/webdriver/#keyboard-actions
|
|
||||||
Key* = enum
|
|
||||||
Unidentified = 0,
|
|
||||||
Cancel,
|
|
||||||
Help,
|
|
||||||
Backspace,
|
|
||||||
Tab,
|
|
||||||
Clear,
|
|
||||||
Return,
|
|
||||||
Enter,
|
|
||||||
Shift,
|
|
||||||
Control,
|
|
||||||
Alt,
|
|
||||||
Pause,
|
|
||||||
Escape
|
|
||||||
|
|
||||||
proc toUnicode(key: Key): Rune =
|
|
||||||
Rune(0xE000 + ord(key))
|
|
||||||
|
|
||||||
proc press*(self: Session, keys: varargs[Key]) =
|
|
||||||
let reqUrl = $(self.driver.url / "session" / self.id / "actions")
|
|
||||||
let obj = %*{"actions": [
|
|
||||||
{
|
|
||||||
"type": "key",
|
|
||||||
"id": "keyboard",
|
|
||||||
"actions": []
|
|
||||||
}
|
|
||||||
]}
|
|
||||||
for key in keys:
|
|
||||||
obj["actions"][0]["actions"].elems.add(
|
|
||||||
%*{
|
|
||||||
"type": "keyDown",
|
|
||||||
"value": $toUnicode(key)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
obj["actions"][0]["actions"].elems.add(
|
|
||||||
%*{
|
|
||||||
"type": "keyUp",
|
|
||||||
"value": $toUnicode(key)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
let resp = self.driver.client.post(reqUrl, $obj)
|
|
||||||
if resp.status != Http200:
|
|
||||||
raise newException(WebDriverException, resp.status)
|
|
||||||
|
|
||||||
discard checkResponse(resp.body)
|
|
||||||
|
|
||||||
when isMainModule:
|
when isMainModule:
|
||||||
let webDriver = newWebDriver()
|
let webDriver = newWebDriver()
|
||||||
let session = webDriver.createSession()
|
let session = webDriver.createSession()
|
||||||
|
|
@ -192,6 +106,4 @@ when isMainModule:
|
||||||
"Entertainment-System/dp/B073BVHY3F"
|
"Entertainment-System/dp/B073BVHY3F"
|
||||||
session.navigate(amazonUrl)
|
session.navigate(amazonUrl)
|
||||||
|
|
||||||
echo session.findElement("#priceblock_ourprice").get().getText()
|
echo session.findElement("#priceblock_ourprice").getText()
|
||||||
|
|
||||||
session.close()
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
# Package
|
# Package
|
||||||
|
|
||||||
version = "0.2.0"
|
version = "0.1.0"
|
||||||
author = "Dominik Picheta"
|
author = "Dominik Picheta"
|
||||||
description = "Implementation of the WebDriver w3c spec."
|
description = "Implementation of the WebDriver w3c spec."
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue