2022-05-10 10:18:17 +00:00
|
|
|
;; -*- geiser-scheme: chicken -*-
|
|
|
|
|
|
|
|
(import (r7rs))
|
|
|
|
(import (scheme base))
|
2022-05-14 22:30:10 +00:00
|
|
|
(import (srfi 1)
|
|
|
|
(srfi 180))
|
2022-05-13 00:57:33 +00:00
|
|
|
(import coops coops-extras coops-primitive-objects coops-utils)
|
|
|
|
(import (chicken process)
|
|
|
|
(chicken gc)
|
|
|
|
(chicken condition))
|
|
|
|
(import uri-common)
|
2022-05-12 00:12:50 +00:00
|
|
|
(import intarweb)
|
2022-05-10 10:18:17 +00:00
|
|
|
(import http-client)
|
|
|
|
|
2022-05-12 00:12:50 +00:00
|
|
|
(define-class <Browser> ()
|
2022-05-13 00:57:33 +00:00
|
|
|
((base-url accessor: base-url)
|
|
|
|
(stdout accessor: stdout)
|
|
|
|
(stdin accessor: stdin)
|
|
|
|
(stderr accessor: stderr)
|
|
|
|
(pid accessor: pid)
|
|
|
|
(session accessor: session)))
|
2022-05-12 00:12:50 +00:00
|
|
|
|
|
|
|
(define-method (initialize-instance (browser <Browser>))
|
2022-05-13 00:57:33 +00:00
|
|
|
(set-finalizer! browser (lambda (obj) (terminate browser)))
|
|
|
|
(call-next-method))
|
|
|
|
|
2022-05-14 22:30:10 +00:00
|
|
|
(define (raise-error error-alist)
|
|
|
|
(print "BOOM!")
|
|
|
|
(error (alist-ref 'error error-alist)
|
|
|
|
error-alist))
|
|
|
|
|
|
|
|
(define-method (read-reply (browser <Browser>))
|
|
|
|
(lambda ()
|
|
|
|
(json-read)))
|
|
|
|
|
2022-05-13 00:57:33 +00:00
|
|
|
(define-method (send (browser <Browser>) struct path method)
|
2022-05-14 22:30:10 +00:00
|
|
|
(let ((reply
|
|
|
|
(with-input-from-request
|
|
|
|
(make-request method: method
|
|
|
|
uri: (uri-reference (string-append (base-url browser) path))
|
|
|
|
headers: (headers `((content-type application/json))))
|
|
|
|
(lambda () (json-write struct))
|
|
|
|
(read-reply browser))))
|
|
|
|
(if (and (list? reply) (find (lambda (x) (eqv? (car x) 'error)) reply))
|
|
|
|
(raise-error (alist-ref 'error reply))
|
|
|
|
reply)))
|
2022-05-13 00:57:33 +00:00
|
|
|
|
|
|
|
(define-method (initialize-session (browser <Browser>))
|
|
|
|
(set! (session browser) (alist-ref 'sessionId (send browser '() "session" 'POST))))
|
2022-05-12 00:12:50 +00:00
|
|
|
|
2022-05-13 00:57:33 +00:00
|
|
|
(define-method (terminate-session (browser <Browser>))
|
|
|
|
(send browser '() (string-append "session/" (session browser)) 'DELETE))
|
|
|
|
|
2022-05-13 13:54:51 +00:00
|
|
|
(define-method (send-with-session (browser <Browser>) struct path method)
|
|
|
|
(send browser struct
|
|
|
|
(string-append "session/" (session browser) "/" path)
|
|
|
|
method))
|
|
|
|
|
2022-05-13 00:57:33 +00:00
|
|
|
(define-method (terminate (browser <Browser>))
|
|
|
|
(call/cc
|
|
|
|
(lambda (c)
|
|
|
|
(with-exception-handler
|
|
|
|
(lambda (x) (c #t))
|
|
|
|
(lambda ()
|
|
|
|
(terminate-session browser)
|
|
|
|
(process-signal (pid browser))
|
|
|
|
(close-input-port (stdout browser))
|
|
|
|
(close-input-port (stderr browser))
|
|
|
|
(close-output-port (stdin browser)))))))
|
2022-05-12 00:12:50 +00:00
|
|
|
|
|
|
|
(define-class <Firefox> (<Browser>))
|
|
|
|
|
|
|
|
(define (firefox #!key ip ip port port)
|
|
|
|
(let-values (((stdout stdin pid stderr) (process* "geckodriver")))
|
2022-05-13 00:57:33 +00:00
|
|
|
(make <Firefox>
|
|
|
|
'base-url (string-append "http://" (or ip "127.0.0.1")
|
|
|
|
":" (or port "4444") "/")
|
|
|
|
'stdout stdout
|
|
|
|
'stdin stdin
|
|
|
|
'stderr stderr
|
|
|
|
'pid pid)))
|
|
|
|
|
2022-05-14 22:30:10 +00:00
|
|
|
(define-method (read-reply (browser <Firefox>))
|
|
|
|
(lambda ()
|
|
|
|
(alist-ref 'value (json-read))))
|
2022-05-13 13:54:51 +00:00
|
|
|
|
|
|
|
;; =======================
|
|
|
|
;; Main API Implementation
|
|
|
|
;; =======================
|
|
|
|
|
2022-05-14 22:30:10 +00:00
|
|
|
(define-method (status (browser <Browser>))
|
|
|
|
(send browser '() "status" 'GET))
|
|
|
|
|
|
|
|
(define-method (maximize! (browser <Browser>))
|
|
|
|
(send-with-session browser '() "maximize" 'POST))
|
|
|
|
|
|
|
|
(define-method (minimize! (browser <Browser>))
|
|
|
|
(send-with-session browser '() "minimize" 'POST))
|
|
|
|
|
|
|
|
(define-method (fullscreen! (browser <Browser>))
|
|
|
|
(send-with-session browser '() "fullscreen" 'POST))
|
|
|
|
|
2022-05-13 13:54:51 +00:00
|
|
|
(define-method (forward! (browser <Browser>))
|
|
|
|
(send-with-session browser '() "forward" 'POST))
|
|
|
|
|
|
|
|
(define-method (back! (browser <Browser>))
|
|
|
|
(send-with-session browser '() "back" 'POST))
|
|
|
|
|
|
|
|
(define-method (refresh! (browser <Browser>))
|
|
|
|
(send-with-session browser '() "refresh" 'POST))
|
|
|
|
|
|
|
|
(define-method (url (browser <Browser>))
|
|
|
|
(send-with-session browser '() "url" 'GET))
|
|
|
|
|
|
|
|
(define-method (url! (browser <Browser>) (uri <string>))
|
|
|
|
(send-with-session browser `((url . ,uri)) "url" 'POST))
|
|
|
|
|
|
|
|
(define-method (title (browser <Browser>))
|
|
|
|
(send-with-session browser '() "title" 'GET))
|
|
|
|
|
|
|
|
(define-method (source (browser <Browser>))
|
|
|
|
(send-with-session browser '() "source" 'GET))
|
2022-05-14 22:30:10 +00:00
|
|
|
|
|
|
|
;; =============================
|
|
|
|
;; Timeout Settings
|
|
|
|
;; =============================
|
|
|
|
(define-record timeouts script page-load implicit)
|
|
|
|
(define-method (get-timeouts (browser <Browser>))
|
|
|
|
(let ((result (send-with-session browser '() "timeouts" 'GET)))
|
|
|
|
(make-timeouts (alist-ref 'script result)
|
|
|
|
(alist-ref 'pageLoad result)
|
|
|
|
(alist-ref 'implicit result))))
|
|
|
|
(define-method (timeouts! (browser <Browser>) timeouts)
|
|
|
|
(let ((timeouts-alist `((script . ,(timeouts-script timeouts))
|
|
|
|
(pageLoad . ,(timeouts-page-load timeouts))
|
|
|
|
(implicit . ,(timeouts-implicit timeouts)))))
|
|
|
|
(send-with-session browser timeouts-alist "timeouts" 'POST)))
|
|
|
|
|
|
|
|
;; =============================
|
|
|
|
;; Elements
|
|
|
|
;; =============================
|
|
|
|
|
|
|
|
(define-record element id)
|
|
|
|
(define locator-strategies '((css: . "css selector")
|
|
|
|
(linktext: . "link text")
|
|
|
|
(partial-linktext: . "partial link text")
|
|
|
|
(tag: . "tag name")
|
|
|
|
(xpath: . "xpath")))
|
|
|
|
(define-method (get-element (browser <Browser>) (locator-strategy <keyword>) (locator <string>))
|
|
|
|
(make-element
|
|
|
|
(cdar
|
|
|
|
(send-with-session browser `((using . ,(alist-ref locator-strategy locator-strategies))
|
|
|
|
(value . ,locator))
|
|
|
|
"element" 'POST))))
|
|
|
|
(define-method (get-elements (browser <Browser>) (locator-strategy <keyword>) (locator <string>))
|
|
|
|
(map (lambda (elem) (make-element (cdar elem)))
|
|
|
|
(send-with-session browser `((using . ,(alist-ref locator-strategy locator-strategies))
|
|
|
|
(value . ,locator))
|
|
|
|
"elements" 'POST)))
|
|
|
|
|
|
|
|
(define-method (element-selected? (browser <Browser>) elem)
|
|
|
|
(send-with-session browser '()
|
|
|
|
(string-append "element/" (element-id elem) "/selected")
|
|
|
|
'GET))
|
|
|
|
|
|
|
|
(define-method (element-attribute (browser <Browser>) elem attribute)
|
|
|
|
(send-with-session browser '()
|
|
|
|
(string-append "element/" (element-id elem) "/attribute/" attribute)
|
|
|
|
'GET))
|
|
|
|
|
|
|
|
(define-method (element-property (browser <Browser>) elem property)
|
|
|
|
(send-with-session browser '()
|
|
|
|
(string-append "element/" (element-id elem) "/property/" property)
|
|
|
|
'GET))
|
|
|
|
|
|
|
|
(define-method (element-css-value (browser <Browser>) elem property)
|
|
|
|
(send-with-session browser '()
|
|
|
|
(string-append "element/" (element-id elem) "/css/" property)
|
|
|
|
'GET))
|
|
|
|
|
|
|
|
(define-method (element-text (browser <Browser>) elem)
|
|
|
|
(send-with-session browser '()
|
|
|
|
(string-append "element/" (element-id elem) "/text")
|
|
|
|
'GET))
|
|
|
|
|
|
|
|
(define-method (element-tag-name (browser <Browser>) elem)
|
|
|
|
(send-with-session browser '()
|
|
|
|
(string-append "element/" (element-id elem) "/name")
|
|
|
|
'GET))
|
|
|
|
|
|
|
|
(define-method (element-rect (browser <Browser>) elem)
|
|
|
|
(send-with-session browser '()
|
|
|
|
(string-append "element/" (element-id elem) "/rect")
|
|
|
|
'GET))
|
|
|
|
|
|
|
|
(define-method (element-enabled? (browser <Browser>) elem)
|
|
|
|
(send-with-session browser '()
|
|
|
|
(string-append "element/" (element-id elem) "/enabled")
|
|
|
|
'GET))
|
|
|
|
|
|
|
|
(define-method (element-computed-role (browser <Browser>) elem)
|
|
|
|
(send-with-session browser '()
|
|
|
|
(string-append "element/" (element-id elem) "/computedrole")
|
|
|
|
'GET))
|
|
|
|
|
|
|
|
(define-method (element-computed-label (browser <Browser>) elem)
|
|
|
|
(send-with-session browser '()
|
|
|
|
(string-append "element/" (element-id elem) "/computedlabel")
|
|
|
|
'GET))
|
|
|
|
|
|
|
|
(define-method (element-click (browser <Browser>) elem)
|
|
|
|
(send-with-session browser '()
|
|
|
|
(string-append "element/" (element-id elem) "/click")
|
|
|
|
'POST))
|
|
|
|
|
|
|
|
(define-method (element-clear (browser <Browser>) elem)
|
|
|
|
(send-with-session browser '()
|
|
|
|
(string-append "element/" (element-id elem) "/clear")
|
|
|
|
'POST))
|
|
|
|
|
|
|
|
(define-method (element-type-text (browser <Browser>) elem text)
|
|
|
|
(send-with-session browser `((text . ,text))
|
|
|
|
(string-append "element/" (element-id elem) "/value")
|
|
|
|
'POST))
|