Marionette is a Crystal shard that replaces the functionality of Selenium (Firefox only for now) by communicating directly with an instance of the browser. It provides a simple, but powserful API which allows everything from navigation to screenshots to executing JavaScript.
- Marionette
- Installation
- Usage
- Launch options
- The Browser Class
- new_session(capabilities)
- close_session
- on_request(&block : HTTP::Server::Context ->)
- on_headers(&block : HTTP::Headers ->)
- on_har_capture(&block : HAR::Entry ->)
- har_entries
- generate_har
- export_har(file, har = nil)
- goto(url)
- title
- url
- refresh
- back
- forward
- set_context
- context
- using_context(&block)
- current_window_handle
- current_chrome_window_handle
- window_handles
- switch_to_window(handle)
- window_rect
- set_window_rect(rect : WindowRect)
- maximize_window
- minimize_window
- fullscreeen
- close_window
- orientation
- set_orienation
- active_frame
- switch_to_frame(frame : String | HTMLElement | Nil, focus: true)
- switch_to_frame(by : LocatorStrategy, value, focus = true)
- switch_to_parent_frame
- cookies
- cookie(name)
- element_enabled?(el)
- element_selected?(el)
- element_displayed?(el)
- element_tag_name(el)
- element_text(el)
- element_attribute(el, name)
- element_css_property(el, property)
- element_rect(el)
- click_element(el)
- send_keys_to_element(el, *keys)
- clear_element(el)
- find_elements(by : LocatorStrategy, value, start_node = nil)
- find_element(by : LocatorStrategy, value, start_node = nil)
- take_screenshot(**options)
- save_screenshot(file, **options)
- execute_script(script, args = nil, timeout = @timeout, new_sandbox = true)
- execute_script_async(script, args = nil, timeout = @timeout, new_sandbox = true)
- dismiss_dialog
- accept_dialog
- get_text_from_dialog
- send_keys_to_dialog(*keys)
- quit
- restart
- clear_pref(pref)
- pref(pref, default_branch = false, value_type = "unspecified")
- set_pref(pref, value, default_branch = false)
- set_prefs(prefs, defualt_branch = false)
- using_prefs(prefs, default_branch = false, &block)
- Contributing
- Contributors
Add this to your application's shard.yml:
dependencies:
marionette:
github: watzon/marionetteFirst, of course, you need to require marionette in your project.
require "marionette"Marionette itself is a module which exposes two methods:
launch(**options)launch(**options, &block : Browser ->)
The first launch method accepts the launch options listed below and returns a new Browser instance. The browser will not be closed at the end of the program's execution, so it's important to remember to run Browser#quit if the browser process was created with marionette.
The second launch method accepts the same launch options and a block. The newly created Browser instance is yielded to the block and the browser process will be closed automatically at the end of the block if the process was created with marionette.
Marionette.launch accepts all the same arguments as Launcher#launch. These arguments are:
- address - The address that Firefox is listening on. (default: 127.0.0.1)
- port - The port that Firefox is listening on. (default: 2828)
- executable - The executable to launch. If
nilan executable will be searched for. Iffalseno executable will be launched. - args - Arguments to pass to the Firefox process (only if executable is not false)
- profile - User profile path to launch with (only if executable is not false)
- headless - Launch browser in headless mode (default: true) (only if executable is not false)
- stdout -
IOto use for STDOUT (only if executable is not false) - stderr -
IOto use for STDERR (only if executable is not false) - accept_insecure_certs - Open all connections, even if the cert is invalid
- env - Environment to pass to
Process(only if executable is not false) - default_viewport - Default size of the browser window (default: {width: 800, height: 600})
- timeout - Universal timeout (default: 60000)
- proxy - NamedTuple with
addressandportfor proxy.
Most of the time while using marionette you will be dealing directly with the Browser class. As its name implies, the Browser class represents the browser instance. It includes a plethora of methods for interacting with the browser, I'll try and document them here as best as I can.
Create a new browser session with provided capabilities and returns the session_id.
browser.new_session({"browserName": "chrome", "platformName": "linux"})Closes the current session without shutting down the browser.
browser.close_sessionNote: To use this method the
extendedoption must be set to true.
Passes the full HTTP::Server::Context to the provided block for every request made by the browser. This method can be called more than once to add multiple handlers.
browser.on_request do |ctx|
pp ctx.requst
pp ctx.response
endNote: To use this method the
extendedoption must be set to true.
Passes the headers for every request to the provided block. This method can be called more than once to add multiple handlers.
browser.on_headers do |headers|
pp headers
endNote: To use this method the
extendedoption must be set to true.
When the extended option is set to true automatic HAR capturing will be enabled. on_har_capture sends each captured HAR::Entry object to the provided block.
browser.on_har do |har|
pp har
endNote: To use this method the
extendedoption must be set to true.
Lists each an every HAR::Entry object captured so far.
browser.har_entries
# => [] of HAR::EntryNote: To use this method the
extendedoption must be set to true.
Generates a HAR::Data object which can be modified or converted to json using to_json. This represents a .har file.
browser.generate_har
# => <#HAR::Data ...>Note: To use this method the
extendedoption must be set to true.
Generates and saves a .har file to the specified path. You can optionally provide it with a HAR::Data object to be saved.
browser.export_har("google.com.har")Navigates the browser to the specified URL. If extended is true this will use a proxy under the hood to fetch the content from the URL and deliver it to the browser, otherwise the default WebDriver method will be used.
browser.goto("https://www.google.com")Gets the title of the current page.
browser.goto("https://www.google.com")
browser.title
# => "Google"Gets the URL of the current page.
browser.goto("https://www.google.com")
browser.url
# => "https://www.google.com"Refreshes the page.
browser.refreshGoes back to the previous page.
browser.backGoes forward to the next page.
browser.forwardSets the context of subsequent commands to be either :chrome (allowing you access to the Firefox UI itself) or :content (allowing access to the current page).
browser.set_context(:chrome)
browser.set_context(:content)Gets the current browser context.
browser.context
# => BrowserContext::Content
browser.set_context(:chrome)
browser.context
# => BrowserContext::ChromeSets the context for the provided block, then returns it to the previous context.
using_context do
# Do stuff
endGets the handle for the current window, useful for switching between window instances.
browser.current_window_handleGet the current chrome window's handle. Corresponds to a chrome window that may itself contain tabs identified by window_handles.
browser.current_chrome_window_handleReturns an array of handles for currently open windows.
browser.current_window_handles
# => ["123..."]Switches to the window with the provided handle.
browser.switch_to_window("123...")Gets the current window as a WindowRect instance containing it's x and y positions as well as it's width and height.
browser.window_rect
# => <#Window:Rect x: 0, y: 0, width: 800, height: 600>Sets the window's size and position according to the provided WindowRect instance.
rect = Marionette::WindowRect.new(x: 0, y: 0, width: 800, height: 600)
browser.set_window_rect(rect)Maximizes the current window.
browser.maximize_windowMinimizes the current window.
browser.minimize_windowMakes the current window fullscreen.
browser.fullscreenCloses the current window.
browser.close_windowGet the screen orientation of the current browser. Returns either portrait-primary, landscape-primary, portrait-secondary, or landscape-secondary.
TODO: Use an enum for this.
browser.orientation
# => "portrait-primary"Set the screen orientation to one of portrait-primary, landscape-primary, portrait-secondary, or landscape-secondary.
TODO: Use an enum for this.
browser.set_orientation("landscape-secondary")Gets the current frame as an HTMLElement or nil if the top level frame is active. (Note that frame means iframe)
browser.active_frame
# => nilSets the active frame to the provided element or element id. If frame is nil the top level frame will be the active frame.
el = browser.find_element(:xpath, "//iframe")
browser.switch_to_frame(el) if el
browser.active_frame
# => <#HTML::Element ...>Convenience method for finding an element and switching the active frame to it. See find_element.
Switches the frame to the parent of the active frame.
browser.switch_to_parent_frame
browser.active_frame
# => nilGet's all cookies for the current page as HTTP::Cookie instaneces.
browser.cookies
# => [<#HTTP::Cookie name: "KBD", value: "8hq2eko2epoijADlkjh9">]Gets a single cookie by name. Retuns nil if the cookie doesn't exist.
browser.cookie("KBD")
# => <#HTTP::Cookie name: "KBD", value: "8hq2eko2epoijADlkjh9">Returns true if the provided element is enabled. el can be a HTMLElement or the ID of an element.
browser.element_enabled?(el)
# => trueReturns true if the provided element is selected. el can be a HTMLElement or the ID of an element.
browser.element_selected?(el)
# => falseReturns true if the provided element is displayed. el can be a HTMLElement or the ID of an element.
browser.element_displayed?(el)
# => trueReturns the tag name of el. el can be a HTMLElement or the ID of an element.
browser.element_tag_name(el)
# => "input"Returns the text of el. el can be a HTMLElement or the ID of an element.
browser.element_text(el)
# => ""Returns the value of the provided atribute name for el. el can be a HTMLElement or the ID of an element.
browser.element_attribute(el, "value")
# => "Hello world"Returns the value of the provided css property for el. el can be a HTMLElement or the ID of an element.
browser.element_css_property(el, "background-color")
# => "#FFFFFF"Returns a ElementRect instance representing the provided element's position and size within the browser. el can be a HTMLElement or the ID of an element.
browser.element_rect(el)
# => <#Elementrect x: 123.0, y: 99.0, width: 100.0, height: 80.0>Simulate a click on el. el can be a HTMLElement or the ID of an element.
browser.click_element(el)Sends keys to the provided element. Keys are strings. Keystrokes for special keys such as return anc backspace can be simulated by sending a special unicode character. To make this easier their is a convenience method [key]. el can be a HTMLElement or the ID of an element.
browser.send_keys(input, "Hello world", key(:enter))Clears a clearable element, such as an input. el can be a HTMLElement or the ID of an element.
browser.clear_element(input)Find all elements on the current page using the specified LocatorStrategy. If a start_node is provided it will be used as the container to search inside of. start_node can be a HTMLElement or the ID of an element.
inputs = browser.find_elements(:xpath, "//input")Find a single on the current page using the specified LocatorStrategy. If a start_node is provided it will be used as the container to search inside of. start_node can be a HTMLElement or the ID of an element.
input = browser.find_element(:xpath, "//input")Takes a screenshot of a particular element or the current frame. If the current context is set to :chrome the screenshot will be of the entire browser, otherwise the screenshot will be of the current page or provided element.
- element : HTMLElement | String | Nil - Element to take a screenshot of.
- hightlights : Array(HTMLElement | String) | Nil - Array of elements to highlight.
- full : Bool - Take a screenshot of the full page.
- scroll : Bool - Scroll to the provided element.
- format : ScreenshotFormat - Format to export the screenshot as.
browser.take_screenshot(
element = nil,
highlights = nil,
full = true,
scroll = true,
format = :binary
)Take and save the screenshot to the specified file. Accepts the same options as take_screenshot
Execute JavaScript on the current page. script should be a valid JavaScript document as a String. args are the arguments to provide, which can be accessed with arguments[n] in the script. You can also provide a timeout and tell the browser to execute this code in a new sandbox (true by default). If sandbox is false the variables from any previously executed script will still exist.
Scripts are executed in the browser context and have access to XPCOM bindings, allowing you to actually control aspects of the browser through JavaScript. Something that normally can't be done with sansboxed code executed by websites.
browser.execute_script("alert(arguments[0])", ["Hello world"])Like execute_script, but asynchronous.
browser.execute_script_async("alert(arguments[0])", ["Hello world"])Dismisses a dialog/alert if there is one. Same as clicking no/cancel.
browser.dismiss_dialogAccepts a dialog if there is one. Same as clicking ok/yes.
browser.accept_dialogGets the text from the current dialog if there is one, otherwise returns nil.
browser.execute_script("alert(arguments[0])", ["Hello world"])
browser.get_text_from_dialog
# => "Hello world"Sends keys to a dialog. Similar to 'send_keys_to_element`.
browser.send_keys_to_dialog("My name", key(:enter))Closes the browser.
browser.quitAttempts to restart the browser without closing it. (Not working yet)
browser.restartSets a preference back to it's default value.
Gets the value of a user defined preference.
Sets a preference to the provided value.
Accepts a Hash or Array of Tuples and sets each preference (key) to the value.
Sets the preferences for the provided block and then resets them afterwards.
- Fork it ( https://github.com/watzon/marionette/fork )
- Create your feature branch (git checkout -b my-new-feature)
- Commit your changes (git commit -am 'Add some feature')
- Push to the branch (git push origin my-new-feature)
- Create a new Pull Request
- watzon - creator, maintainer