Marionette
1 Introduction
2 Examples
3 Reference
start-marionette!
call-with-marionette!
call-with-marionette/  browser!
call-with-marionette/  browser/  page!
call-with-browser!
call-with-page!
3.1 Browser
browser?
browser-connect!
browser-disconnect!
browser-timeouts
set-browser-timeouts!
browser-viewport-size
set-browser-viewport-size!
make-browser-page!
browser-capabilities
browser-pages
browser-focus!
3.2 Page
page?
page=?
page-close!
page-refresh!
page-goto!
page-go-back!
page-go-forward!
page-execute-async!
page-interactive?
page-loaded?
page-title
page-url
page-content
set-page-content!
page-wait-for!
page-query-selector!
page-query-selector-all!
cookie/  c
page-cookies
page-add-cookie!
page-delete-all-cookies!
page-delete-cookie!
page-alert-text
page-alert-accept!
page-alert-dismiss!
page-alert-type!
call-with-page-pdf!
call-with-page-screenshot!
3.3 Element
element?
element=?
element-click!
element-clear!
element-type!
element-query-selector!
element-query-selector-all!
element-enabled?
element-selected?
element-visible?
element-tag
element-text
element-rect
element-attribute
element-property
call-with-element-screenshot!
rect
3.4 Capabilities
page-load-strategy/  c
unhandled-prompt-behavior/  c
capabilities
make-capabilities
3.5 Timeouts
timeouts
make-timeouts
8.2

Marionette

Bogdan Popa <bogdan@defn.io>

1 Introduction

Marionette lets you control the Firefox web browser via the Marionette Protocol. This is the same interface used by Selenium, via geckodriver.

To use this library, you need to have a running Firefox instance with the marionette protocol enabled. To do this, all you have to do is run the firefox binary with the -marionette flag.

2 Examples

Here are some simple examples of using marionette. The first saves a PNG file containing an image of the current racket-lang.org webpage:

> (require marionette
           racket/file)
>
> (define data
    (call-with-marionette/browser/page!
     (lambda (p)
       (page-goto! p "https://racket-lang.org")
       (call-with-page-screenshot! p values))))
>
> (define filename
    (make-temporary-file "~a.png"))
>
> (with-output-to-file filename
    #:exists 'truncate/replace
    (lambda ()
      (write-bytes data)))

791931

>
> (printf "filename of page screenshot: ~v\n" (path->string filename))

filename of page screenshot: "/var/folders/6s/8kt06x656dddy8z5y0jmf_fc0000gn/T/16266838661626683866996.png"

This next example dowloads the HTML content of a password-protected web page:

#lang racket
 
(require marionette)
 
(define username "zipnarg")
 
(define nextcatalog-csc-minor-url
 "https://nextcatalog-admin.calpoly.edu/collegesandprograms/\
collegeofengineering/computersciencesoftwareengineering/\
computerscienceminor/")
 
(define profile-path
 (build-path "/Users/zipnarg/Library/Application Support/"
             "Firefox/Profiles/s9y75gtr.wazoo"))
 
(define content
 (call-with-marionette/browser/page!
  #:profile profile-path
  (λ (page)
    (page-goto! page nextcatalog-csc-minor-url)
    (printf "ready? ~v\n" (page-loaded? page))
    (printf "page title: ~v\n" (page-title page))
    (let ()
      (define username-elt (page-query-selector! page "#username"))
      (cond [username-elt
             (element-type! username-elt username)]
            [else
             (error 'login "couldn't find username field.")]))
    (let ()
      (define password-elt (page-query-selector! page "#password"))
      (cond [password-elt
             (printf "password: ")
             (define str (read-line))
             (element-type! password-elt str)]
            [else
             (error 'login "couldn't find password field.")]))
    (let ()
      (define form-button (page-query-selector! page ".form-button"))
      (cond [form-button
             (element-click! form-button)]
            [else
             (error 'login "couldn't find login button.")]))
    ;; wait until the page is ready and the title is no longer
    ;; that of the login page
    (let loop ()
      (define loaded? (page-loaded? page))
      (cond [loaded?
             (define title (page-title page))
             (cond [(equal? title "Cal Poly Web Login Service")
                    (printf "still login screen title, waiting...\n")
                    (sleep 1)
                    (loop)]
                   [else 'ok])]
            [else
             (printf "not ready, waiting...\n")
             (sleep 1)
             (loop)]))
    (printf "final page title: ~v\n" (page-title page))
    (page-content page))))

3 Reference

procedure

(start-marionette! [#:command command    
  #:profile profile    
  #:port port    
  #:safe-mode? safe-mode?    
  #:headless? headless?    
  #:timeout timeout])  (-> void?)
  command : absolute-path? = "/usr/local/bin/firefox"
  profile : (or/c false/c absolute-path?) = #f
  port : (or/c false/c (integer-in 1 65535)) = #f
  safe-mode? : boolean? = #t
  headless? : boolean? = #t
  timeout : exact-nonnegative-integer? = 5

procedure

(call-with-marionette! p)  any

  p : (-> any)

procedure

(call-with-marionette/browser! p)  any

  p : (-> browser? any)

procedure

(call-with-marionette/browser/page! p)  any

  p : (-> page? any)
Start a marionette-enabled instance of the Firefox browser using profile. The return value is a procedure that can be used to stop the browser.

The command argument controls the path to the firefox binary. If not provided, the system PATH is searched along with the /Applications folder on macOS.

If profile is #f, then a temporary path si created for the profile and it it subsequently removed when the browser is stopped.

If port is provided, then the profile will be modified to instruct the marionette server to listen on that port.

call-with-marionette! accepts the same keyword arguments that start-marionette! does. It starts the browser, applies its p argument then immediately stops the browser.

call-with-marionette/browser! composes call-with-marionette! and call-with-browser! together. Keyword arguments are passed through to start-marionette!.

call-with-marionette/browser/page! composes call-with-marionette/browser! and call-with-page! together. Keyword arguments are passed through to start-marionette!.

procedure

(call-with-browser! p    
  [#:host host    
  #:port port    
  #:capabilities capabilities])  any
  p : (-> browser? any)
  host : non-empty-string? = "127.0.0.1"
  port : (integer-in 1 65535) = 2828
  capabilities : capabilities? = (make-capabilities)
Calls p after initiating a new browser session and disconnects after p finishes executing.

procedure

(call-with-page! b p)  any

  b : browser?
  p : (-> page? any)
Calls p after creating a new page and closes said page after p finishes executing.

3.1 Browser

Browsers represent a connection to a marionette-driven instance of Firefox. Browsers are not thread-safe, nor is it safe to interleave commands against the same marionette server. If you need concurrency, then create multiple marionettes and control them separately.

procedure

(browser? b)  boolean?

  b : any/c
Returns #t when b is a browser.

procedure

(browser-connect! [#:host host    
  #:port port    
  #:capabilities capabilities])  browser?
  host : non-empty-string? = "127.0.0.1"
  port : (integer-in 1 65535) = 2828
  capabilities : capabilities? = (make-capabilities)
Connects to the marionette server at host and port and returns a browser session.

procedure

(browser-disconnect! b)  void?

  b : browser?
Disconnects b from its marionette.

procedure

(browser-timeouts b)  timeouts?

  b : browser?

procedure

(set-browser-timeouts! b t)  void?

  b : browser?
  t : timeouts?
Get or set the b’s current timeout settings.

Get or set b’s current viewport size.

procedure

(make-browser-page! b)  page?

  b : browser?
Open a new page in b and return it.

procedure

(browser-capabilities b)  capabilities?

  b : browser?
Retrieve the capabilities? for b.

procedure

(browser-pages b)  (listof page?)

  b : browser?
Lists all the pages belonging to b.

procedure

(browser-focus! b p)  void?

  b : browser?
  p : page?
Makes p the currently active page.

3.2 Page

procedure

(page? p)  boolean?

  p : any/c
Returns #t when p is a page.

procedure

(page=? p1 p2)  boolean?

  p1 : page?
  p2 : page?
Returns #t when p1 and p2 have the same handle and belong to the same marionette.

procedure

(page-close! p)  void?

  p : page?
Tells the browser to close p.

procedure

(page-refresh! p)  void?

  p : page?
Tells the browser to refresh p.

procedure

(page-goto! p location)  void?

  p : page?
  location : (or/c string? url?)
Navigates p to location.

procedure

(page-go-back! p)  void?

  p : page?

procedure

(page-go-forward! p)  void?

  p : page?
Moves p backward and forward through its history.

procedure

(page-execute-async! p s arg ...)  jsexpr?

  p : page?
  s : string?
  arg : any/c
Executes the script s on p and returns its result.

procedure

(page-interactive? p)  boolean?

  p : page?

procedure

(page-loaded? p)  boolean?

  p : page?
Ascertains the current "ready state" of p.

procedure

(page-title p)  string?

  p : page?

procedure

(page-url p)  url?

  p : page?
Accessors for p’s title and url, respectively.

procedure

(page-content p)  string?

  p : page?

procedure

(set-page-content! p s)  void?

  p : page?
  s : string?
Get or set p’s HTML content.

procedure

(page-wait-for! p    
  selector    
  [#:timeout timeout    
  #:visible? visible?])  (or/c false/c element?)
  p : page?
  selector : non-empty-string?
  timeout : (and/c real? (not/c negative?)) = 30
  visible? : boolean? = #t
Waits for an element matching the given CSS selector to appear on p or timeout milliseconds to pass. If visible? is #t, then the element must be visible on the page for it to match.

procedure

(page-query-selector! p selector)  (or/c false/c element?)

  p : page?
  selector : non-empty-string?

procedure

(page-query-selector-all! p selector)  (listof element?)

  p : page?
  selector : non-empty-string?
Queries p for either the first or all element?s that match the given CSS selector.

value

cookie/c : contract?

procedure

(page-cookies p)  (listof cookie/c)

  p : page?

procedure

(page-add-cookie! p c)  void?

  p : page?
  c : cookie/c

procedure

(page-delete-all-cookies! p)  void?

  p : page?

procedure

(page-delete-cookie! p name)  void?

  p : page?
  name : string?

procedure

(page-alert-text p)  string?

  p : page?

procedure

(page-alert-accept! p)  void?

  p : page?

procedure

(page-alert-dismiss! p)  void?

  p : page?

procedure

(page-alert-type! p text)  void?

  p : page?
  text : string?
Interacts with the current prompt on p. By default, all prompts are automatically dismissed, so you won’t have anything to interact with. To change this, specify a different unhandled prompt behavior in your capabilities.

procedure

(call-with-page-pdf! page proc)  any

  page : page?
  proc : (-> bytes? any)
Converts the contents of page to a PDF and passes the resulting bytes to proc.

procedure

(call-with-page-screenshot! page    
  proc    
  [#:full? full?])  any
  page : page?
  proc : (-> bytes? any)
  full? : boolean? = #t
Takes a screenshot of page and calls proc with the resulting bytes?. full? determines whether or not the entire page is captured.

3.3 Element

Elements represent individual elements on a specific page. They are only valid for as long as the page they were queried from active. That is, if you query an element and then navigate off the page you got it from, it becomes invalid.

procedure

(element? e)  boolean?

  e : any/c
Returns #t when e is an element.

procedure

(element=? e1 e2)  boolean?

  e1 : element?
  e2 : element?
Returns #t when e1 and e2 have the same handle and belong to the same page.

procedure

(element-click! e)  void?

  e : element?
Clicks on e.

procedure

(element-clear! e)  void?

  e : element?
Clears e’s contents if it is an HTMLInputElement.

procedure

(element-type! e text)  void

  e : element?
  text : string?
Types text into e.

procedure

(element-query-selector! e selector)  (or/c false/c element?)

  e : element?
  selector : non-empty-string?

procedure

(element-query-selector-all! e selector)  (listof element?)

  e : element?
  selector : non-empty-string?
Queries e for either the first or all element?s belonging to it that match the given CSS selector.

procedure

(element-enabled? e)  boolean?

  e : element?

procedure

(element-selected? e)  boolean?

  e : element?

procedure

(element-visible? e)  boolean?

  e : element?
Returns #t if e is enabled, selected or visible, respectively.

procedure

(element-tag e)  string?

  e : element?

procedure

(element-text e)  string?

  e : element?

procedure

(element-rect e)  rect?

  e : element?
Accessors for various e fields.

procedure

(element-attribute e name)  (or/c false/c string?)

  e : element?
  name : string?

procedure

(element-property e name)  (or/c false/c string?)

  e : element?
  name : string?
Retrieves e’s attribute named name statically and dynamically, respectively.

procedure

(call-with-element-screenshot! e p)  any

  e : element?
  p : (-> bytes? any)
Takes a screenshot of e and calls proc with the resulting bytes?.

struct

(struct rect (x y w h)
    #:extra-constructor-name make-rect)
  x : real?
  y : real?
  w : real?
  h : real?
Represents an element’s bounding client rect.

3.4 Capabilities

value

page-load-strategy/c : (or/c 'none 'eager 'normal)

value

unhandled-prompt-behavior/c : 
(or/c 'dismiss
      'dismiss-and-notify
      'accept
      'accept-and-notify
      'ignore)
Contracts used by the functions in this module.

struct

(struct capabilities (timeouts
    page-load-strategy
    unhandled-prompt-behavior
    accept-insecure-certs?)
    #:extra-constructor-name make-capabilities)
  timeouts : timeouts?
  page-load-strategy : page-load-strategy/c
  unhandled-prompt-behavior : unhandled-prompt-behavior/c
  accept-insecure-certs? : boolean?

procedure

(make-capabilities 
  [#:timeouts timeouts 
  #:page-load-strategy page-load-strategy 
  #:unhandled-prompt-behavior unhandled-prompt-behavior 
  #:accept-insecure-certs? accept-insecure-certs?]) 
  capabilities?
  timeouts : timeouts? = (make-timeouts)
  page-load-strategy : page-load-strategy/c = 'normal
  unhandled-prompt-behavior : unhandled-prompt-behavior/c
   = 'dismiss-and-notify
  accept-insecure-certs? : boolean? = #f
Represents a session’s capabilities. Capabilities control various settings and behaviors of the sessions created via browser-connect!.

3.5 Timeouts

struct

(struct timeouts (script page-load implicit)
    #:extra-constructor-name make-timeouts)
  script : exact-nonnegative-integer?
  page-load : exact-nonnegative-integer?
  implicit : exact-nonnegative-integer?

procedure

(make-timeouts [#:script script    
  #:page-load page-load    
  #:implicit implicit])  timeouts?
  script : exact-nonnegative-integer? = 30000
  page-load : exact-nonnegative-integer? = 300000
  implicit : exact-nonnegative-integer? = 0
Timeouts let you control how long the browser will wait for various operations to finish before raising an exception.